diff --git a/lib/sqlite/sqlite3.c b/lib/sqlite/sqlite3.c
index efe31d888..e60c4579b 100644
--- a/lib/sqlite/sqlite3.c
+++ b/lib/sqlite/sqlite3.c
@@ -1,15 +1,15 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.6.23.1. By combining all the individual C code files into this
-** single large file, the entire code can be compiled as a one translation
+** version 3.7.8. 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
-** of 5% are more are commonly seen when SQLite is compiled as a single
+** of 5% or more are commonly seen when SQLite is compiled as a single
** translation unit.
**
** This file is all you need to compile SQLite. To use SQLite in other
** programs, you need this file and the "sqlite3.h" header file that defines
-** the programming interface to the SQLite library. (If you do not have
+** the programming interface to the SQLite library. (If you do not have
** the "sqlite3.h" header file at hand, you will find a copy embedded within
** the text of this file. Search for "Begin file sqlite3.h" to find the start
** of the embedded sqlite3.h header file.) Additional code files may be needed
@@ -91,7 +91,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
-**
+**
** This file defines various limits of what SQLite can process.
*/
@@ -139,9 +139,9 @@
#endif
/*
-** The maximum depth of an expression tree. This is limited to
-** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might
-** want to place more severe limits on the complexity of an
+** The maximum depth of an expression tree. This is limited to
+** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might
+** want to place more severe limits on the complexity of an
** expression.
**
** A value of 0 used to mean that the limit was not enforced.
@@ -190,9 +190,17 @@
# define SQLITE_DEFAULT_TEMP_CACHE_SIZE 500
#endif
+/*
+** The default number of frames to accumulate in the log file before
+** checkpointing the database in WAL mode.
+*/
+#ifndef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT
+# define SQLITE_DEFAULT_WAL_AUTOCHECKPOINT 1000
+#endif
+
/*
** The maximum number of attached databases. This must be between 0
-** and 30. The upper bound on 30 is because a 32-bit integer bitmap
+** and 62. The upper bound on 62 is because a 64-bit integer bitmap
** is used internally to track attached databases.
*/
#ifndef SQLITE_MAX_ATTACHED
@@ -207,20 +215,21 @@
# define SQLITE_MAX_VARIABLE_NUMBER 999
#endif
-/* Maximum page size. The upper bound on this value is 32768. This a limit
-** imposed by the necessity of storing the value in a 2-byte unsigned integer
-** and the fact that the page size must be a power of 2.
+/* Maximum page size. The upper bound on this value is 65536. This a limit
+** imposed by the use of 16-bit offsets within each page.
**
-** If this limit is changed, then the compiled library is technically
-** incompatible with an SQLite library compiled with a different limit. If
-** a process operating on a database with a page-size of 65536 bytes
-** crashes, then an instance of SQLite compiled with the default page-size
-** limit will not be able to rollback the aborted transaction. This could
-** lead to database corruption.
+** Earlier versions of SQLite allowed the user to change this value at
+** compile time. This is no longer permitted, on the grounds that it creates
+** a library that is technically incompatible with an SQLite library
+** compiled with a different limit. If a process operating on a database
+** with a page-size of 65536 bytes crashes, then an instance of SQLite
+** compiled with the default page-size limit will not be able to rollback
+** the aborted transaction. This could lead to database corruption.
*/
-#ifndef SQLITE_MAX_PAGE_SIZE
-# define SQLITE_MAX_PAGE_SIZE 32768
+#ifdef SQLITE_MAX_PAGE_SIZE
+# undef SQLITE_MAX_PAGE_SIZE
#endif
+#define SQLITE_MAX_PAGE_SIZE 65536
/*
@@ -273,7 +282,7 @@
** Maximum depth of recursion for triggers.
**
** A value of 1 means that a trigger program will not be able to itself
-** fire any triggers. A value of 0 means that no trigger programs at all
+** fire any triggers. A value of 0 means that no trigger programs at all
** may be executed.
*/
#ifndef SQLITE_MAX_TRIGGER_DEPTH
@@ -308,7 +317,7 @@
#endif
/*
-** The number of samples of an index that SQLite takes in order to
+** The number of samples of an index that SQLite takes in order to
** construct a histogram of the table content when running ANALYZE
** and with SQLITE_ENABLE_STAT2
*/
@@ -320,10 +329,10 @@
** to the next, so we have developed the following set of #if statements
** to generate appropriate macros for a wide range of compilers.
**
-** The correct "ANSI" way to do this is to use the intptr_t type.
+** The correct "ANSI" way to do this is to use the intptr_t type.
** Unfortunately, that typedef is not available on all compilers, or
** if it is available, it requires an #include of specific headers
-** that very from one machine to the next.
+** that vary from one machine to the next.
**
** Ticket #3860: The llvm-gcc-4.2 compiler from Apple chokes on
** the ((void*)&((char*)0)[X]) construct. But MSVC chokes on ((void*)(X)).
@@ -345,21 +354,27 @@
#endif
/*
-** The SQLITE_THREADSAFE macro must be defined as either 0 or 1.
+** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2.
+** 0 means mutexes are permanently disable and the library is never
+** threadsafe. 1 means the library is serialized which is the highest
+** level of threadsafety. 2 means the libary is multithreaded - multiple
+** threads can use SQLite as long as no two threads try to use the same
+** database connection at the same time.
+**
** Older versions of SQLite used an optional THREADSAFE macro.
-** We support that for legacy
+** We support that for legacy.
*/
#if !defined(SQLITE_THREADSAFE)
#if defined(THREADSAFE)
# define SQLITE_THREADSAFE THREADSAFE
#else
-# define SQLITE_THREADSAFE 1
+# define SQLITE_THREADSAFE 1 /* IMP: R-07272-22309 */
#endif
#endif
/*
** The SQLITE_DEFAULT_MEMSTATUS macro must be defined as either 0 or 1.
-** It determines whether or not the features related to
+** It determines whether or not the features related to
** SQLITE_CONFIG_MEMSTATUS are available by default or not. This value can
** be overridden at runtime using the sqlite3_config() API.
*/
@@ -372,19 +387,25 @@
** specify which memory allocation subsystem to use.
**
** SQLITE_SYSTEM_MALLOC // Use normal system malloc()
+** SQLITE_WIN32_MALLOC // Use Win32 native heap API
** SQLITE_MEMDEBUG // Debugging version of system malloc()
**
+** On Windows, if the SQLITE_WIN32_MALLOC_VALIDATE macro is defined and the
+** assert() macro is enabled, each call into the Win32 native heap subsystem
+** will cause HeapValidate to be called. If heap validation should fail, an
+** assertion will be triggered.
+**
** (Historical note: There used to be several other options, but we've
** pared it down to just these two.)
**
** If none of the above are defined, then set SQLITE_SYSTEM_MALLOC as
** the default.
*/
-#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_MEMDEBUG)>1
+#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_WIN32_MALLOC)+defined(SQLITE_MEMDEBUG)>1
# error "At most one of the following compile-time configuration options\
- is allows: SQLITE_SYSTEM_MALLOC, SQLITE_MEMDEBUG"
+ is allows: SQLITE_SYSTEM_MALLOC, SQLITE_WIN32_MALLOC, SQLITE_MEMDEBUG"
#endif
-#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_MEMDEBUG)==0
+#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_WIN32_MALLOC)+defined(SQLITE_MEMDEBUG)==0
# define SQLITE_SYSTEM_MALLOC 1
#endif
@@ -427,12 +448,12 @@
** option is set. Thus NDEBUG becomes an opt-in rather than an opt-out
** feature.
*/
-#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
+#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
# define NDEBUG 1
#endif
/*
-** The testcase() macro is used to aid in coverage testing. When
+** The testcase() macro is used to aid in coverage testing. When
** doing coverage testing, the condition inside the argument to
** testcase() must be evaluated both true and false in order to
** get full branch coverage. The testcase() macro is inserted
@@ -478,7 +499,7 @@ SQLITE_PRIVATE void sqlite3Coverage(int);
#endif
/*
-** The ALWAYS and NEVER macros surround boolean expressions which
+** The ALWAYS and NEVER macros surround boolean expressions which
** are intended to always be true or false, respectively. Such
** expressions could be omitted from the code completely. But they
** are included in a few cases in order to enhance the resilience
@@ -503,6 +524,13 @@ SQLITE_PRIVATE void sqlite3Coverage(int);
# define NEVER(X) (X)
#endif
+/*
+** Return true (non-zero) if the input is a integer that is too large
+** to fit in 32-bits. This macro is used inside of various testcase()
+** macros to verify that we have tested SQLite for large-file support.
+*/
+#define IS_BIG_INT(X) (((X)&~(i64)0xffffffff)!=0)
+
/*
** The macro unlikely() is a hint that surrounds a boolean
** expression that is usually false. Macro likely() surrounds
@@ -618,7 +646,7 @@ extern "C" {
**
** Since version 3.6.18, SQLite source code has been stored in the
** Fossil configuration management
-** system. ^The SQLITE_SOURCE_ID macro evalutes to
+** system. ^The SQLITE_SOURCE_ID macro evaluates to
** a string which identifies a particular check-in of SQLite
** within its configuration management system. ^The SQLITE_SOURCE_ID
** string contains the date and time of the check-in (UTC) and an SHA1
@@ -628,9 +656,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.6.23.1"
-#define SQLITE_VERSION_NUMBER 3006023
-#define SQLITE_SOURCE_ID "2010-03-26 22:28:06 b078b588d617e07886ad156e9f54ade6d823568e"
+#define SQLITE_VERSION "3.7.8"
+#define SQLITE_VERSION_NUMBER 3007008
+#define SQLITE_SOURCE_ID "2011-09-19 14:49:19 3e0da808d2f5b4d12046e05980ca04578f581177"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -656,8 +684,8 @@ extern "C" {
** function is provided for use in DLLs since DLL users usually do not have
** direct access to string constants within the DLL. ^The
** sqlite3_libversion_number() function returns an integer equal to
-** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function returns
-** a pointer to a string constant whose value is the same as the
+** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function returns
+** a pointer to a string constant whose value is the same as the
** [SQLITE_SOURCE_ID] C preprocessor macro.
**
** See also: [sqlite_version()] and [sqlite_source_id()].
@@ -667,32 +695,32 @@ SQLITE_API const char *sqlite3_libversion(void);
SQLITE_API const char *sqlite3_sourceid(void);
SQLITE_API int sqlite3_libversion_number(void);
-#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
/*
** CAPI3REF: Run-Time Library Compilation Options Diagnostics
**
-** ^The sqlite3_compileoption_used() function returns 0 or 1
-** indicating whether the specified option was defined at
-** compile time. ^The SQLITE_ prefix may be omitted from the
-** option name passed to sqlite3_compileoption_used().
+** ^The sqlite3_compileoption_used() function returns 0 or 1
+** indicating whether the specified option was defined at
+** compile time. ^The SQLITE_ prefix may be omitted from the
+** option name passed to sqlite3_compileoption_used().
**
-** ^The sqlite3_compileoption_get() function allows interating
+** ^The sqlite3_compileoption_get() function allows iterating
** over the list of options that were defined at compile time by
** returning the N-th compile time option string. ^If N is out of range,
-** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_
-** prefix is omitted from any strings returned by
+** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_
+** prefix is omitted from any strings returned by
** sqlite3_compileoption_get().
**
** ^Support for the diagnostic functions sqlite3_compileoption_used()
-** and sqlite3_compileoption_get() may be omitted by specifing the
+** and sqlite3_compileoption_get() may be omitted by specifying the
** [SQLITE_OMIT_COMPILEOPTION_DIAGS] option at compile time.
**
** See also: SQL functions [sqlite_compileoption_used()] and
** [sqlite_compileoption_get()] and the [compile_options pragma].
*/
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
SQLITE_API int sqlite3_compileoption_used(const char *zOptName);
SQLITE_API const char *sqlite3_compileoption_get(int N);
-#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
+#endif
/*
** CAPI3REF: Test To See If The Library Is Threadsafe
@@ -704,7 +732,7 @@ SQLITE_API const char *sqlite3_compileoption_get(int N);
** SQLite can be compiled with or without mutexes. When
** the [SQLITE_THREADSAFE] C preprocessor macro is 1 or 2, mutexes
** are enabled and SQLite is threadsafe. When the
-** [SQLITE_THREADSAFE] macro is 0,
+** [SQLITE_THREADSAFE] macro is 0,
** the mutexes are omitted. Without the mutexes, it is not safe
** to use SQLite concurrently from more than one thread.
**
@@ -760,7 +788,7 @@ typedef struct sqlite3 sqlite3;
**
** ^The sqlite3_int64 and sqlite_int64 types can store integer values
** between -9223372036854775808 and +9223372036854775807 inclusive. ^The
-** sqlite3_uint64 and sqlite_uint64 types can store integer values
+** sqlite3_uint64 and sqlite_uint64 types can store integer values
** between 0 and +18446744073709551615 inclusive.
*/
#ifdef SQLITE_INT64_TYPE
@@ -789,7 +817,7 @@ typedef sqlite_uint64 sqlite3_uint64;
**
** ^The sqlite3_close() routine is the destructor for the [sqlite3] object.
** ^Calls to sqlite3_close() return SQLITE_OK if the [sqlite3] object is
-** successfullly destroyed and all associated resources are deallocated.
+** successfully destroyed and all associated resources are deallocated.
**
** Applications must [sqlite3_finalize | finalize] all [prepared statements]
** and [sqlite3_blob_close | close] all [BLOB handles] associated with
@@ -805,7 +833,7 @@ typedef sqlite_uint64 sqlite3_uint64;
** pointer or an [sqlite3] object pointer obtained
** from [sqlite3_open()], [sqlite3_open16()], or
** [sqlite3_open_v2()], and not previously closed.
-** ^Calling sqlite3_close() with a NULL pointer argument is a
+** ^Calling sqlite3_close() with a NULL pointer argument is a
** harmless no-op.
*/
SQLITE_API int sqlite3_close(sqlite3 *);
@@ -823,7 +851,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** The sqlite3_exec() interface is a convenience wrapper around
** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()],
** that allows an application to run multiple statements of SQL
-** without having to use a lot of C code.
+** without having to use a lot of C code.
**
** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded,
** semicolon-separate SQL statements passed into its 2nd argument,
@@ -831,7 +859,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** argument. ^If the callback function of the 3rd argument to
** sqlite3_exec() is not NULL, then it is invoked for each result row
** coming out of the evaluated SQL statements. ^The 4th argument to
-** to sqlite3_exec() is relayed through to the 1st argument of each
+** sqlite3_exec() is relayed through to the 1st argument of each
** callback invocation. ^If the callback pointer to sqlite3_exec()
** is NULL, then no callback is ever invoked and result rows are
** ignored.
@@ -863,7 +891,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** from [sqlite3_column_name()].
**
** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer
-** to an empty string, or a pointer that contains only whitespace and/or
+** to an empty string, or a pointer that contains only whitespace and/or
** SQL comments, then no SQL statements are evaluated and the database
** is not changed.
**
@@ -896,7 +924,8 @@ SQLITE_API int sqlite3_exec(
**
** New error codes may be added in future versions of SQLite.
**
-** See also: [SQLITE_IOERR_READ | extended result codes]
+** See also: [SQLITE_IOERR_READ | extended result codes],
+** [sqlite3_vtab_on_conflict()] [SQLITE_ROLLBACK | result codes].
*/
#define SQLITE_OK 0 /* Successful result */
/* beginning-of-error-codes */
@@ -911,10 +940,10 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/
#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
-#define SQLITE_NOTFOUND 12 /* NOT USED. Table or record not found */
+#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */
#define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
-#define SQLITE_PROTOCOL 15 /* NOT USED. Database lock protocol error */
+#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
#define SQLITE_EMPTY 16 /* Database is empty */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
@@ -970,15 +999,24 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15<<8))
#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8))
#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8))
-#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8) )
+#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8))
+#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8))
+#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_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
+#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
+#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<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))
/*
** CAPI3REF: Flags For File Open Operations
**
** These bit values are intended for use in the
** 3rd parameter to the [sqlite3_open_v2()] interface and
-** in the 4th parameter to the xOpen method of the
-** [sqlite3_vfs] object.
+** in the 4th parameter to the [sqlite3_vfs.xOpen] method.
*/
#define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */
@@ -986,6 +1024,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */
#define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */
#define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */
+#define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */
#define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */
#define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */
@@ -997,11 +1036,14 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */
+#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */
+
+/* Reserved: 0x00F00000 */
/*
** CAPI3REF: Device Characteristics
**
-** The xDeviceCapabilities method of the [sqlite3_io_methods]
+** The xDeviceCharacteristics method of the [sqlite3_io_methods]
** object returns an integer which is a vector of the these
** bit values expressing I/O characteristics of the mass storage
** device that holds the file that the [sqlite3_io_methods]
@@ -1018,17 +1060,18 @@ SQLITE_API int sqlite3_exec(
** information is written to disk in the same order as calls
** to xWrite().
*/
-#define SQLITE_IOCAP_ATOMIC 0x00000001
-#define SQLITE_IOCAP_ATOMIC512 0x00000002
-#define SQLITE_IOCAP_ATOMIC1K 0x00000004
-#define SQLITE_IOCAP_ATOMIC2K 0x00000008
-#define SQLITE_IOCAP_ATOMIC4K 0x00000010
-#define SQLITE_IOCAP_ATOMIC8K 0x00000020
-#define SQLITE_IOCAP_ATOMIC16K 0x00000040
-#define SQLITE_IOCAP_ATOMIC32K 0x00000080
-#define SQLITE_IOCAP_ATOMIC64K 0x00000100
-#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
-#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
+#define SQLITE_IOCAP_ATOMIC 0x00000001
+#define SQLITE_IOCAP_ATOMIC512 0x00000002
+#define SQLITE_IOCAP_ATOMIC1K 0x00000004
+#define SQLITE_IOCAP_ATOMIC2K 0x00000008
+#define SQLITE_IOCAP_ATOMIC4K 0x00000010
+#define SQLITE_IOCAP_ATOMIC8K 0x00000020
+#define SQLITE_IOCAP_ATOMIC16K 0x00000040
+#define SQLITE_IOCAP_ATOMIC32K 0x00000080
+#define SQLITE_IOCAP_ATOMIC64K 0x00000100
+#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
+#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
+#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
/*
** CAPI3REF: File Locking Levels
@@ -1056,6 +1099,18 @@ SQLITE_API int sqlite3_exec(
** equal SQLITE_SYNC_NORMAL, that means to use normal fsync() semantics.
** If the lower four bits equal SQLITE_SYNC_FULL, that means
** to use Mac OS X style fullsync instead of fsync().
+**
+** Do not confuse the SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL flags
+** with the [PRAGMA synchronous]=NORMAL and [PRAGMA synchronous]=FULL
+** settings. The [synchronous pragma] determines when calls to the
+** xSync VFS method occur and applies uniformly across all platforms.
+** The SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL flags determine how
+** energetic or rigorous or forceful the sync operations are and
+** only make a difference on Mac OSX for the default SQLite code.
+** (Third-party VFS implementations might also make the distinction
+** between SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL, but among the
+** operating systems natively supported by SQLite, only Mac OSX
+** cares about the difference.)
*/
#define SQLITE_SYNC_NORMAL 0x00002
#define SQLITE_SYNC_FULL 0x00003
@@ -1064,7 +1119,7 @@ SQLITE_API int sqlite3_exec(
/*
** CAPI3REF: OS Interface Open File Handle
**
-** An [sqlite3_file] object represents an open file in the
+** An [sqlite3_file] object represents an open file in the
** [sqlite3_vfs | OS interface layer]. Individual OS interface
** implementations will
** want to subclass this object by appending additional fields
@@ -1080,17 +1135,18 @@ struct sqlite3_file {
/*
** CAPI3REF: OS Interface File Virtual Methods Object
**
-** Every file opened by the [sqlite3_vfs] xOpen method populates an
+** Every file opened by the [sqlite3_vfs.xOpen] method populates an
** [sqlite3_file] object (or, more commonly, a subclass of the
** [sqlite3_file] object) with a pointer to an instance of this object.
** This object defines the methods used to perform various operations
** against the open file represented by the [sqlite3_file] object.
**
-** If the xOpen method sets the sqlite3_file.pMethods element
+** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element
** to a non-NULL pointer, then the sqlite3_io_methods.xClose method
-** may be invoked even if the xOpen reported that it failed. The
-** only way to prevent a call to xClose following a failed xOpen
-** is for the xOpen to set the sqlite3_file.pMethods element to NULL.
+** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The
+** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen]
+** is for the [sqlite3_vfs.xOpen] to set the sqlite3_file.pMethods element
+** to NULL.
**
** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or
** [SQLITE_SYNC_FULL]. The first choice is the normal fsync().
@@ -1124,7 +1180,9 @@ struct sqlite3_file {
** core reserves all opcodes less than 100 for its own use.
** A [SQLITE_FCNTL_LOCKSTATE | list of opcodes] less than 100 is available.
** Applications that define a custom xFileControl method should use opcodes
-** greater than 100 to avoid conflicts.
+** greater than 100 to avoid conflicts. VFS implementations should
+** return [SQLITE_NOTFOUND] for file control opcodes that they do not
+** recognize.
**
** The xSectorSize() method returns the sector size of the
** device that underlies the file. The sector size is the
@@ -1179,6 +1237,12 @@ struct sqlite3_io_methods {
int (*xFileControl)(sqlite3_file*, int op, void *pArg);
int (*xSectorSize)(sqlite3_file*);
int (*xDeviceCharacteristics)(sqlite3_file*);
+ /* Methods above are valid for version 1 */
+ int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
+ int (*xShmLock)(sqlite3_file*, int offset, int n, int flags);
+ void (*xShmBarrier)(sqlite3_file*);
+ int (*xShmUnmap)(sqlite3_file*, int deleteFlag);
+ /* Methods above are valid for version 2 */
/* Additional methods may be added in future releases */
};
@@ -1196,11 +1260,78 @@ struct sqlite3_io_methods {
** into an integer that the pArg argument points to. This capability
** is used during testing and only needs to be supported when SQLITE_TEST
** is defined.
+**
+** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
+** layer a hint of how large the database file will grow to be during the
+** current transaction. This hint is not guaranteed to be accurate but it
+** is often close. The underlying VFS might choose to preallocate database
+** file space based on this hint in order to help writes to the database
+** file run faster.
+**
+** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS
+** extends and truncates the database file in chunks of a size specified
+** by the user. The fourth argument to [sqlite3_file_control()] should
+** point to an integer (type int) containing the new chunk-size to use
+** for the nominated database. Allocating database file space in large
+** chunks (say 1MB at a time), may reduce file-system fragmentation and
+** improve performance on some systems.
+**
+** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer
+** to the [sqlite3_file] object associated with a particular database
+** connection. See the [sqlite3_file_control()] documentation for
+** additional information.
+**
+** ^(The [SQLITE_FCNTL_SYNC_OMITTED] opcode is generated internally by
+** SQLite and sent to all VFSes in place of a call to the xSync method
+** when the database connection has [PRAGMA synchronous] set to OFF.)^
+** Some specialized VFSes need this signal in order to operate correctly
+** when [PRAGMA synchronous | PRAGMA synchronous=OFF] is set, but most
+** VFSes do not need this signal and should silently ignore this opcode.
+** Applications should not call [sqlite3_file_control()] with this
+** opcode as doing so may disrupt the operation of the specialized VFSes
+** that do require it.
+**
+** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic
+** retry counts and intervals for certain disk I/O operations for the
+** windows [VFS] in order to work to provide robustness against
+** anti-virus programs. By default, the windows VFS will retry file read,
+** file write, and file delete opertions up to 10 times, with a delay
+** of 25 milliseconds before the first retry and with the delay increasing
+** by an additional 25 milliseconds with each subsequent retry. This
+** opcode allows those to values (10 retries and 25 milliseconds of delay)
+** to be adjusted. The values are changed for all database connections
+** within the same process. The argument is a pointer to an array of two
+** integers where the first integer i the new retry count and the second
+** integer is the delay. If either integer is negative, then the setting
+** is not changed but instead the prior value of that setting is written
+** into the array entry, allowing the current retry settings to be
+** interrogated. The zDbName parameter is ignored.
+**
+** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the
+** persistent [WAL | Write AHead Log] setting. By default, the auxiliary
+** write ahead log and shared memory files used for transaction control
+** are automatically deleted when the latest connection to the database
+** closes. Setting persistent WAL mode causes those files to persist after
+** close. Persisting the files is useful when other processes that do not
+** have write permission on the directory containing the database file want
+** to read the database file, as the WAL and shared memory files must exist
+** in order for the database to be readable. The fourth parameter to
+** [sqlite3_file_control()] for this opcode should be a pointer to an integer.
+** That integer is 0 to disable persistent WAL mode or 1 to enable persistent
+** WAL mode. If the integer is -1, then it is overwritten with the current
+** WAL persistence setting.
+**
*/
#define SQLITE_FCNTL_LOCKSTATE 1
#define SQLITE_GET_LOCKPROXYFILE 2
#define SQLITE_SET_LOCKPROXYFILE 3
#define SQLITE_LAST_ERRNO 4
+#define SQLITE_FCNTL_SIZE_HINT 5
+#define SQLITE_FCNTL_CHUNK_SIZE 6
+#define SQLITE_FCNTL_FILE_POINTER 7
+#define SQLITE_FCNTL_SYNC_OMITTED 8
+#define SQLITE_FCNTL_WIN32_AV_RETRY 9
+#define SQLITE_FCNTL_PERSIST_WAL 10
/*
** CAPI3REF: Mutex Handle
@@ -1219,7 +1350,8 @@ typedef struct sqlite3_mutex sqlite3_mutex;
**
** An instance of the sqlite3_vfs object defines the interface between
** the SQLite core and the underlying operating system. The "vfs"
-** in the name of the object stands for "virtual file system".
+** in the name of the object stands for "virtual file system". See
+** the [VFS | VFS documentation] for further information.
**
** The value of the iVersion field is initially 1 but may be larger in
** future versions of SQLite. Additional fields may be appended to this
@@ -1248,26 +1380,31 @@ typedef struct sqlite3_mutex sqlite3_mutex;
** The zName field holds the name of the VFS module. The name must
** be unique across all VFS modules.
**
-** SQLite will guarantee that the zFilename parameter to xOpen
+** [[sqlite3_vfs.xOpen]]
+** ^SQLite guarantees that the zFilename parameter to xOpen
** is either a NULL pointer or string obtained
-** from xFullPathname(). SQLite further guarantees that
+** from xFullPathname() with an optional suffix added.
+** ^If a suffix is added to the zFilename parameter, it will
+** consist of a single "-" character followed by no more than
+** 10 alphanumeric and/or "-" characters.
+** ^SQLite further guarantees that
** the string will be valid and unchanged until xClose() is
** called. Because of the previous sentence,
** the [sqlite3_file] can safely store a pointer to the
** filename if it needs to remember the filename for some reason.
-** If the zFilename parameter is xOpen is a NULL pointer then xOpen
-** must invent its own temporary name for the file. Whenever the
+** If the zFilename parameter to xOpen is a NULL pointer then xOpen
+** must invent its own temporary name for the file. ^Whenever the
** xFilename parameter is NULL it will also be the case that the
** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE].
**
** The flags argument to xOpen() includes all bits set in
** the flags argument to [sqlite3_open_v2()]. Or if [sqlite3_open()]
** or [sqlite3_open16()] is used, then flags includes at least
-** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE].
+** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE].
** If xOpen() opens a file read-only then it sets *pOutFlags to
** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be set.
**
-** SQLite will also add one of the following flags to the xOpen()
+** ^(SQLite will also add one of the following flags to the xOpen()
** call, depending on the object being opened:
**
**
@@ -1278,7 +1415,8 @@ typedef struct sqlite3_mutex sqlite3_mutex;
** - [SQLITE_OPEN_TRANSIENT_DB]
**
- [SQLITE_OPEN_SUBJOURNAL]
**
- [SQLITE_OPEN_MASTER_JOURNAL]
-**
+** [SQLITE_OPEN_WAL]
+** )^
**
** The file I/O implementation can use the object type flags to
** change the way it deals with files. For example, an application
@@ -1297,19 +1435,20 @@ typedef struct sqlite3_mutex sqlite3_mutex;
**
**
** The [SQLITE_OPEN_DELETEONCLOSE] flag means the file should be
-** deleted when it is closed. The [SQLITE_OPEN_DELETEONCLOSE]
-** will be set for TEMP databases, journals and for subjournals.
+** deleted when it is closed. ^The [SQLITE_OPEN_DELETEONCLOSE]
+** will be set for TEMP databases and their journals, transient
+** databases, and subjournals.
**
-** The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction
+** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction
** with the [SQLITE_OPEN_CREATE] flag, which are both directly
** analogous to the O_EXCL and O_CREAT flags of the POSIX open()
-** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the
+** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the
** SQLITE_OPEN_CREATE, is used to indicate that file should always
** be created, and that it is an error if it already exists.
-** It is not used to indicate the file should be opened
+** It is not used to indicate the file should be opened
** for exclusive access.
**
-** At least szOsFile bytes of memory are allocated by SQLite
+** ^At least szOsFile bytes of memory are allocated by SQLite
** to hold the [sqlite3_file] structure passed as the third
** argument to xOpen. The xOpen method does not have to
** allocate the structure; it should just fill it in. Note that
@@ -1319,33 +1458,54 @@ typedef struct sqlite3_mutex sqlite3_mutex;
** element will be valid after xOpen returns regardless of the success
** or failure of the xOpen call.
**
-** The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS]
+** [[sqlite3_vfs.xAccess]]
+** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS]
** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to
** test whether a file is readable and writable, or [SQLITE_ACCESS_READ]
** to test whether a file is at least readable. The file can be a
** directory.
**
-** SQLite will always allocate at least mxPathname+1 bytes for the
+** ^SQLite will always allocate at least mxPathname+1 bytes for the
** output buffer xFullPathname. The exact size of the output buffer
** is also passed as a parameter to both methods. If the output buffer
** is not large enough, [SQLITE_CANTOPEN] should be returned. Since this is
** handled as a fatal error by SQLite, vfs implementations should endeavor
** to prevent this by setting mxPathname to a sufficiently large value.
**
-** The xRandomness(), xSleep(), and xCurrentTime() interfaces
-** are not strictly a part of the filesystem, but they are
+** The xRandomness(), xSleep(), xCurrentTime(), and xCurrentTimeInt64()
+** interfaces are not strictly a part of the filesystem, but they are
** included in the VFS structure for completeness.
** The xRandomness() function attempts to return nBytes bytes
** of good-quality randomness into zOut. The return value is
** the actual number of bytes of randomness obtained.
** The xSleep() method causes the calling thread to sleep for at
-** least the number of microseconds given. The xCurrentTime()
-** method returns a Julian Day Number for the current date and time.
+** least the number of microseconds given. ^The xCurrentTime()
+** method returns a Julian Day Number for the current date and time as
+** a floating point value.
+** ^The xCurrentTimeInt64() method returns, as an integer, the Julian
+** Day Number multiplied by 86400000 (the number of milliseconds in
+** a 24-hour day).
+** ^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.
**
+** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces
+** are not used by the SQLite core. These optional interfaces are provided
+** by some VFSes to facilitate testing of the VFS code. By overriding
+** system calls with functions under its control, a test program can
+** simulate faults and error conditions that would otherwise be difficult
+** or impossible to induce. The set of system calls that can be overridden
+** varies from one VFS to another, and from one version of the same VFS to the
+** next. Applications that use these interfaces must be prepared for any
+** or all of these interfaces to be NULL or for their behavior to change
+** from one release to the next. Applications must not attempt to access
+** any of these methods if the iVersion of the VFS is less than 3.
*/
typedef struct sqlite3_vfs sqlite3_vfs;
+typedef void (*sqlite3_syscall_ptr)(void);
struct sqlite3_vfs {
- int iVersion; /* Structure version number */
+ int iVersion; /* Structure version number (currently 3) */
int szOsFile; /* Size of subclassed sqlite3_file */
int mxPathname; /* Maximum file pathname length */
sqlite3_vfs *pNext; /* Next registered VFS */
@@ -1364,8 +1524,23 @@ struct sqlite3_vfs {
int (*xSleep)(sqlite3_vfs*, int microseconds);
int (*xCurrentTime)(sqlite3_vfs*, double*);
int (*xGetLastError)(sqlite3_vfs*, int, char *);
- /* New fields may be appended in figure versions. The iVersion
- ** value will increment whenever this happens. */
+ /*
+ ** The methods above are in version 1 of the sqlite_vfs object
+ ** definition. Those that follow are added in version 2 or later
+ */
+ int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*);
+ /*
+ ** The methods above are in versions 1 and 2 of the sqlite_vfs object.
+ ** Those below are for version 3 and greater.
+ */
+ int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr);
+ sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName);
+ const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName);
+ /*
+ ** The methods above are in versions 1 through 3 of the sqlite_vfs object.
+ ** New fields may be appended in figure versions. The iVersion
+ ** value will increment whenever this happens.
+ */
};
/*
@@ -1377,13 +1552,58 @@ struct sqlite3_vfs {
** With SQLITE_ACCESS_EXISTS, the xAccess method
** simply checks whether the file exists.
** With SQLITE_ACCESS_READWRITE, the xAccess method
-** checks whether the file is both readable and writable.
+** checks whether the named directory is both readable and writable
+** (in other words, if files can be added, removed, and renamed within
+** the directory).
+** The SQLITE_ACCESS_READWRITE constant is currently used only by the
+** [temp_store_directory pragma], though this could change in a future
+** release of SQLite.
** With SQLITE_ACCESS_READ, the xAccess method
-** checks whether the file is readable.
+** checks whether the file is readable. The SQLITE_ACCESS_READ constant is
+** currently unused, though it might be used in a future release of
+** SQLite.
*/
#define SQLITE_ACCESS_EXISTS 0
-#define SQLITE_ACCESS_READWRITE 1
-#define SQLITE_ACCESS_READ 2
+#define SQLITE_ACCESS_READWRITE 1 /* Used by PRAGMA temp_store_directory */
+#define SQLITE_ACCESS_READ 2 /* Unused */
+
+/*
+** CAPI3REF: Flags for the xShmLock VFS method
+**
+** These integer constants define the various locking operations
+** allowed by the xShmLock method of [sqlite3_io_methods]. The
+** following are the only legal combinations of flags to the
+** xShmLock method:
+**
+**
+** - SQLITE_SHM_LOCK | SQLITE_SHM_SHARED
+**
- SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE
+**
- SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED
+**
- SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE
+**
+**
+** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as
+** was given no the corresponding lock.
+**
+** The xShmLock method can transition between unlocked and SHARED or
+** between unlocked and EXCLUSIVE. It cannot transition between SHARED
+** and EXCLUSIVE.
+*/
+#define SQLITE_SHM_UNLOCK 1
+#define SQLITE_SHM_LOCK 2
+#define SQLITE_SHM_SHARED 4
+#define SQLITE_SHM_EXCLUSIVE 8
+
+/*
+** CAPI3REF: Maximum xShmLock index
+**
+** The xShmLock method on [sqlite3_io_methods] may use values
+** between 0 and this upper bound as its "offset" argument.
+** The SQLite core will never attempt to acquire or release a
+** lock outside of this range
+*/
+#define SQLITE_SHM_NLOCK 8
+
/*
** CAPI3REF: Initialize The SQLite Library
@@ -1485,44 +1705,37 @@ SQLITE_API int sqlite3_os_end(void);
** implementation of an application-defined [sqlite3_os_init()].
**
** The first argument to sqlite3_config() is an integer
-** [SQLITE_CONFIG_SINGLETHREAD | configuration option] that determines
+** [configuration option] that determines
** what property of SQLite is to be configured. Subsequent arguments
-** vary depending on the [SQLITE_CONFIG_SINGLETHREAD | configuration option]
+** vary depending on the [configuration option]
** in the first argument.
**
** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK].
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_config(int, ...);
+SQLITE_API int sqlite3_config(int, ...);
/*
** CAPI3REF: Configure database connections
-** EXPERIMENTAL
**
** The sqlite3_db_config() interface is used to make configuration
** changes to a [database connection]. The interface is similar to
** [sqlite3_config()] except that the changes apply to a single
-** [database connection] (specified in the first argument). The
-** sqlite3_db_config() interface should only be used immediately after
-** the database connection is created using [sqlite3_open()],
-** [sqlite3_open16()], or [sqlite3_open_v2()].
+** [database connection] (specified in the first argument).
**
** The second argument to sqlite3_db_config(D,V,...) is the
-** configuration verb - an integer code that indicates what
-** aspect of the [database connection] is being configured.
-** The only choice for this value is [SQLITE_DBCONFIG_LOOKASIDE].
-** New verbs are likely to be added in future releases of SQLite.
-** Additional arguments depend on the verb.
+** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code
+** that indicates what aspect of the [database connection] is being configured.
+** Subsequent arguments vary depending on the configuration verb.
**
** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
** the call is considered successful.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_db_config(sqlite3*, int op, ...);
+SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Memory Allocation Routines
-** EXPERIMENTAL
**
** An instance of this object defines the interface between SQLite
** and low-level memory allocation routines.
@@ -1530,7 +1743,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_db_config(sqlite3*, int op, ...);
** This object is used in only one place in the SQLite interface.
** A pointer to an instance of this object is the argument to
** [sqlite3_config()] when the configuration option is
-** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC].
+** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC].
** By creating an instance of this object
** and passing it to [sqlite3_config]([SQLITE_CONFIG_MALLOC])
** during configuration, an application can specify an alternative
@@ -1546,16 +1759,10 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_db_config(sqlite3*, int op, ...);
** order to verify that SQLite recovers gracefully from such
** conditions.
**
-** The xMalloc and xFree methods must work like the
-** malloc() and free() functions from the standard C library.
-** The xRealloc method must work like realloc() from the standard C library
-** with the exception that if the second argument to xRealloc is zero,
-** xRealloc must be a no-op - it must not perform any allocation or
-** deallocation. ^SQLite guarantees that the second argument to
+** The xMalloc, xRealloc, and xFree methods must work like the
+** malloc(), realloc() and free() functions from the standard C library.
+** ^SQLite guarantees that the second argument to
** xRealloc is always a value returned by a prior call to xRoundup.
-** And so in cases where xRoundup always returns a positive number,
-** xRealloc can perform exactly as the standard library realloc() and
-** still be in compliance with this specification.
**
** xSize should return the allocated size of a memory allocation
** previously obtained from xMalloc or xRealloc. The allocated size
@@ -1566,7 +1773,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_db_config(sqlite3*, int op, ...);
** allocators round up memory allocations at least to the next multiple
** of 8. Some allocators round up to a larger multiple or to a power of 2.
** Every memory allocation request coming in through [sqlite3_malloc()]
-** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0,
+** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0,
** that causes the corresponding memory allocation to fail.
**
** The xInit method initializes the memory allocator. (For example,
@@ -1604,7 +1811,7 @@ struct sqlite3_mem_methods {
/*
** CAPI3REF: Configuration Options
-** EXPERIMENTAL
+** KEYWORDS: {configuration option}
**
** These constants are the available integer configuration options that
** can be passed as the first argument to the [sqlite3_config()] interface.
@@ -1617,18 +1824,18 @@ struct sqlite3_mem_methods {
** is invoked.
**
**
-** - SQLITE_CONFIG_SINGLETHREAD
+** [[SQLITE_CONFIG_SINGLETHREAD]] - SQLITE_CONFIG_SINGLETHREAD
** - There are no arguments to this option. ^This option sets the
** [threading mode] to Single-thread. In other words, it disables
** all mutexing and puts SQLite into a mode where it can only be used
** by a single thread. ^If SQLite is compiled with
** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
** it is not possible to change the [threading mode] from its default
-** value of Single-thread and so [sqlite3_config()] will return
+** value of Single-thread and so [sqlite3_config()] will return
** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD
** configuration option.
**
-** - SQLITE_CONFIG_MULTITHREAD
+** [[SQLITE_CONFIG_MULTITHREAD]] - SQLITE_CONFIG_MULTITHREAD
** - There are no arguments to this option. ^This option sets the
** [threading mode] to Multi-thread. In other words, it disables
** mutexing on [database connection] and [prepared statement] objects.
@@ -1642,7 +1849,7 @@ struct sqlite3_mem_methods {
** [sqlite3_config()] will return [SQLITE_ERROR] if called with the
** SQLITE_CONFIG_MULTITHREAD configuration option.
**
-** - SQLITE_CONFIG_SERIALIZED
+** [[SQLITE_CONFIG_SERIALIZED]] - SQLITE_CONFIG_SERIALIZED
** - There are no arguments to this option. ^This option sets the
** [threading mode] to Serialized. In other words, this option enables
** all mutexes including the recursive
@@ -1658,7 +1865,7 @@ struct sqlite3_mem_methods {
** [sqlite3_config()] will return [SQLITE_ERROR] if called with the
** SQLITE_CONFIG_SERIALIZED configuration option.
**
-** - SQLITE_CONFIG_MALLOC
+** [[SQLITE_CONFIG_MALLOC]] - SQLITE_CONFIG_MALLOC
** - ^(This option takes a single argument which is a pointer to an
** instance of the [sqlite3_mem_methods] structure. The argument specifies
** alternative low-level memory allocation routines to be used in place of
@@ -1666,7 +1873,7 @@ struct sqlite3_mem_methods {
** its own private copy of the content of the [sqlite3_mem_methods] structure
** before the [sqlite3_config()] call returns.
**
-** - SQLITE_CONFIG_GETMALLOC
+** [[SQLITE_CONFIG_GETMALLOC]] - SQLITE_CONFIG_GETMALLOC
** - ^(This option takes a single argument which is a pointer to an
** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods]
** structure is filled with the currently defined memory allocation routines.)^
@@ -1674,15 +1881,15 @@ struct sqlite3_mem_methods {
** routines with a wrapper that simulations memory allocation failure or
** tracks memory usage, for example.
**
-** - SQLITE_CONFIG_MEMSTATUS
-** - ^This option takes single argument of type int, interpreted as a
-** boolean, which enables or disables the collection of memory allocation
-** statistics. ^(When memory allocation statistics are disabled, the
+** [[SQLITE_CONFIG_MEMSTATUS]]
- SQLITE_CONFIG_MEMSTATUS
+** - ^This option takes single argument of type int, interpreted as a
+** boolean, which enables or disables the collection of memory allocation
+** statistics. ^(When memory allocation statistics are disabled, the
** following SQLite interfaces become non-operational:
**
** - [sqlite3_memory_used()]
**
- [sqlite3_memory_highwater()]
-**
- [sqlite3_soft_heap_limit()]
+**
- [sqlite3_soft_heap_limit64()]
**
- [sqlite3_status()]
**
)^
** ^Memory allocation statistics are enabled by default unless SQLite is
@@ -1690,26 +1897,25 @@ struct sqlite3_mem_methods {
** allocation statistics are disabled by default.
**
**
-** - SQLITE_CONFIG_SCRATCH
+** [[SQLITE_CONFIG_SCRATCH]] - SQLITE_CONFIG_SCRATCH
** - ^This option specifies a static memory buffer that SQLite can use for
** scratch memory. There are three arguments: A pointer an 8-byte
-** aligned memory buffer from which the scrach allocations will be
+** aligned memory buffer from which the scratch allocations will be
** drawn, the size of each scratch allocation (sz),
** and the maximum number of scratch allocations (N). The sz
-** argument must be a multiple of 16. The sz parameter should be a few bytes
-** larger than the actual scratch space required due to internal overhead.
+** argument must be a multiple of 16.
** The first argument must be a pointer to an 8-byte aligned buffer
** of at least sz*N bytes of memory.
-** ^SQLite will use no more than one scratch buffer per thread. So
-** N should be set to the expected maximum number of threads. ^SQLite will
-** never require a scratch buffer that is more than 6 times the database
-** page size. ^If SQLite needs needs additional scratch memory beyond
-** what is provided by this configuration option, then
+** ^SQLite will use no more than two scratch buffers per thread. So
+** N should be set to twice the expected maximum number of threads.
+** ^SQLite will never require a scratch buffer that is more than 6
+** times the database page size. ^If SQLite needs needs additional
+** scratch memory beyond what is provided by this configuration option, then
** [sqlite3_malloc()] will be used to obtain the memory needed.
**
-** - SQLITE_CONFIG_PAGECACHE
+** [[SQLITE_CONFIG_PAGECACHE]] - SQLITE_CONFIG_PAGECACHE
** - ^This option specifies a static memory buffer that SQLite can use for
-** the database page cache with the default page cache implemenation.
+** the database page cache with the default page cache implementation.
** This configuration should not be used if an application-define page
** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option.
** There are three arguments to this option: A pointer to 8-byte aligned
@@ -1724,12 +1930,11 @@ struct sqlite3_mem_methods {
** memory needs for the first N pages that it adds to cache. ^If additional
** page cache memory is needed beyond what is provided by this option, then
** SQLite goes to [sqlite3_malloc()] for the additional storage space.
-** ^The implementation might use one or more of the N buffers to hold
-** memory accounting information. The pointer in the first argument must
+** The pointer in the first argument must
** be aligned to an 8-byte boundary or subsequent behavior of SQLite
** will be undefined.
**
-** - SQLITE_CONFIG_HEAP
+** [[SQLITE_CONFIG_HEAP]] - SQLITE_CONFIG_HEAP
** - ^This option specifies a static memory buffer that SQLite will use
** for all of its dynamic memory allocation needs beyond those provided
** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE].
@@ -1742,9 +1947,11 @@ struct sqlite3_mem_methods {
** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
** allocator is engaged to handle all of SQLites memory allocation needs.
** The first pointer (the memory pointer) must be aligned to an 8-byte
-** boundary or subsequent behavior of SQLite will be undefined.
+** boundary or subsequent behavior of SQLite will be undefined.
+** The minimum allocation size is capped at 2^12. Reasonable values
+** for the minimum allocation size are 2^5 through 2^8.
**
-** - SQLITE_CONFIG_MUTEX
+** [[SQLITE_CONFIG_MUTEX]] - SQLITE_CONFIG_MUTEX
** - ^(This option takes a single argument which is a pointer to an
** instance of the [sqlite3_mutex_methods] structure. The argument specifies
** alternative low-level mutex routines to be used in place
@@ -1756,7 +1963,7 @@ struct sqlite3_mem_methods {
** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will
** return [SQLITE_ERROR].
**
-** - SQLITE_CONFIG_GETMUTEX
+** [[SQLITE_CONFIG_GETMUTEX]] - SQLITE_CONFIG_GETMUTEX
** - ^(This option takes a single argument which is a pointer to an
** instance of the [sqlite3_mutex_methods] structure. The
** [sqlite3_mutex_methods]
@@ -1769,7 +1976,7 @@ struct sqlite3_mem_methods {
** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will
** return [SQLITE_ERROR].
**
-** - SQLITE_CONFIG_LOOKASIDE
+** [[SQLITE_CONFIG_LOOKASIDE]] - SQLITE_CONFIG_LOOKASIDE
** - ^(This option takes two arguments that determine the default
** memory allocation for the lookaside memory allocator on each
** [database connection]. The first argument is the
@@ -1779,17 +1986,47 @@ struct sqlite3_mem_methods {
** verb to [sqlite3_db_config()] can be used to change the lookaside
** configuration on individual connections.)^
**
-** - SQLITE_CONFIG_PCACHE
+** [[SQLITE_CONFIG_PCACHE]] - SQLITE_CONFIG_PCACHE
** - ^(This option takes a single argument which is a pointer to
** an [sqlite3_pcache_methods] object. This object specifies the interface
** to a custom page cache implementation.)^ ^SQLite makes a copy of the
** object and uses it for page cache memory allocations.
**
-** - SQLITE_CONFIG_GETPCACHE
+** [[SQLITE_CONFIG_GETPCACHE]] - SQLITE_CONFIG_GETPCACHE
** - ^(This option takes a single argument which is a pointer to an
** [sqlite3_pcache_methods] object. SQLite copies of the current
** page cache implementation into that object.)^
**
+** [[SQLITE_CONFIG_LOG]] - SQLITE_CONFIG_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
+** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op.
+** ^The void pointer that is the second argument to SQLITE_CONFIG_LOG is
+** passed through as the first parameter to the application-defined logger
+** function whenever that function is invoked. ^The second parameter to
+** the logger function is a copy of the first parameter to the corresponding
+** [sqlite3_log()] call and is intended to be a [result code] or an
+** [extended result code]. ^The third parameter passed to the logger is
+** log message after formatting via [sqlite3_snprintf()].
+** The SQLite logging interface is not reentrant; the logger function
+** supplied by the application must not invoke any SQLite interface.
+** In a multi-threaded application, the application-defined logger
+** function must be threadsafe.
+**
+** [[SQLITE_CONFIG_URI]] - SQLITE_CONFIG_URI
+**
- This option takes a single argument of type int. If non-zero, then
+** URI handling is globally enabled. If the parameter is zero, then URI handling
+** is globally disabled. If URI handling is globally enabled, all filenames
+** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or
+** specified as part of [ATTACH] commands are interpreted as URIs, regardless
+** of whether or not the [SQLITE_OPEN_URI] flag is set when the database
+** connection is opened. If it is globally disabled, filenames are
+** only interpreted as URIs if the SQLITE_OPEN_URI flag is set when the
+** database connection is opened. By default, URI handling is globally
+** disabled. The default value may be changed by compiling with the
+** [SQLITE_USE_URI] symbol defined.
**
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -1803,15 +2040,15 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */
#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */
-/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
+/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
#define SQLITE_CONFIG_PCACHE 14 /* sqlite3_pcache_methods* */
#define SQLITE_CONFIG_GETPCACHE 15 /* sqlite3_pcache_methods* */
#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
+#define SQLITE_CONFIG_URI 17 /* int */
/*
-** CAPI3REF: Configuration Options
-** EXPERIMENTAL
+** CAPI3REF: Database Connection Configuration Options
**
** These constants are the available integer configuration options that
** can be passed as the second argument to the [sqlite3_db_config()] interface.
@@ -1825,10 +2062,10 @@ struct sqlite3_mem_methods {
**
**
** - SQLITE_DBCONFIG_LOOKASIDE
-** - ^This option takes three additional arguments that determine the
+**
- ^This option takes three additional arguments that determine the
** [lookaside memory allocator] configuration for the [database connection].
** ^The first argument (the third parameter to [sqlite3_db_config()] is a
-** pointer to an memory buffer to use for lookaside memory.
+** pointer to a memory buffer to use for lookaside memory.
** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb
** may be NULL in which case SQLite will allocate the
** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the
@@ -1837,12 +2074,40 @@ struct sqlite3_mem_methods {
** or equal to the product of the second and third arguments. The buffer
** must be aligned to an 8-byte boundary. ^If the second argument to
** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally
-** rounded down to the next smaller
-** multiple of 8. See also: [SQLITE_CONFIG_LOOKASIDE]
+** rounded down to the next smaller multiple of 8. ^(The lookaside memory
+** configuration for a database connection can only be changed when that
+** connection is not currently using lookaside memory, or in other words
+** when the "current value" returned by
+** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero.
+** Any attempt to change the lookaside memory configuration when lookaside
+** memory is in use leaves the configuration unchanged and returns
+** [SQLITE_BUSY].)^
+**
+** - SQLITE_DBCONFIG_ENABLE_FKEY
+** - ^This option is used to enable or disable the enforcement of
+** [foreign key constraints]. There should be two additional arguments.
+** The first argument is an integer which is 0 to disable FK enforcement,
+** positive to enable FK enforcement or negative to leave FK enforcement
+** unchanged. The second parameter is a pointer to an integer into which
+** is written 0 or 1 to indicate whether FK enforcement is off or on
+** following this call. The second parameter may be a NULL pointer, in
+** which case the FK enforcement setting is not reported back.
+**
+** - SQLITE_DBCONFIG_ENABLE_TRIGGER
+** - ^This option is used to enable or disable [CREATE TRIGGER | triggers].
+** There should be two additional arguments.
+** The first argument is an integer which is 0 to disable triggers,
+** positive to enable triggers or negative to leave the setting unchanged.
+** The second parameter is a pointer to an integer into which
+** is written 0 or 1 to indicate whether triggers are disabled or enabled
+** following this call. The second parameter may be a NULL pointer, in
+** which case the trigger setting is not reported back.
**
**
*/
-#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
+#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
+#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
/*
@@ -1866,13 +2131,17 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
**
** ^This routine returns the [rowid] of the most recent
** successful [INSERT] into the database from the [database connection]
-** in the first argument. ^If no successful [INSERT]s
+** in the first argument. ^As of SQLite version 3.7.7, this routines
+** records the last insert rowid of both ordinary tables and [virtual tables].
+** ^If no successful [INSERT]s
** have ever occurred on that database connection, zero is returned.
**
-** ^(If an [INSERT] occurs within a trigger, then the [rowid] of the inserted
-** row is returned by this routine as long as the trigger is running.
-** But once the trigger terminates, the value returned by this routine
-** reverts to the last value inserted before the trigger fired.)^
+** ^(If an [INSERT] occurs within a trigger or within a [virtual table]
+** method, then this routine will return the [rowid] of the inserted
+** row as long as the trigger or virtual table method is running.
+** But once the trigger or virtual table method ends, the value returned
+** by this routine reverts to what it was before the trigger or virtual
+** table method began.)^
**
** ^An [INSERT] that fails due to a constraint violation is not a
** successful [INSERT] and does not change the value returned by this
@@ -1921,7 +2190,7 @@ SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
** mechanisms do not count as direct row changes.)^
**
** A "trigger context" is a scope of execution that begins and
-** ends with the script of a [CREATE TRIGGER | trigger].
+** ends with the script of a [CREATE TRIGGER | trigger].
** Most SQL statements are
** evaluated outside of any trigger. This is the "top level"
** trigger context. If a trigger fires from the top level, a
@@ -1964,7 +2233,7 @@ SQLITE_API int sqlite3_changes(sqlite3*);
** the count does not include changes used to implement [REPLACE] constraints,
** do rollbacks or ABORT processing, or [DROP TABLE] processing. The
** count does not include rows of views that fire an [INSTEAD OF trigger],
-** though if the INSTEAD OF trigger makes changes of its own, those changes
+** though if the INSTEAD OF trigger makes changes of its own, those changes
** are counted.)^
** ^The sqlite3_total_changes() function counts the changes as soon as
** the statement that makes them is completed (when the statement handle
@@ -2004,7 +2273,7 @@ SQLITE_API int sqlite3_total_changes(sqlite3*);
**
** ^The sqlite3_interrupt(D) call is in effect until all currently running
** SQL statements on [database connection] D complete. ^Any new SQL statements
-** that are started after the sqlite3_interrupt() call and before the
+** that are started after the sqlite3_interrupt() call and before the
** running statements reaches zero are interrupted as if they had been
** running prior to the sqlite3_interrupt() call. ^New SQL statements
** that are started after the running statement count reaches zero are
@@ -2039,7 +2308,7 @@ SQLITE_API void sqlite3_interrupt(sqlite3*);
** ^These routines do not parse the SQL statements thus
** will not detect syntactically incorrect SQL.
**
-** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior
+** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior
** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked
** automatically by sqlite3_complete16(). If that initialization fails,
** then the return value from sqlite3_complete16() will be non-zero
@@ -2114,7 +2383,7 @@ SQLITE_API int sqlite3_complete16(const void *sql);
** The busy callback should not take any actions which modify the
** database connection that invoked the busy handler. Any such actions
** result in undefined behavior.
-**
+**
** A busy handler must not close the database connection
** or [prepared statement] that invoked the busy handler.
*/
@@ -2143,6 +2412,9 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
/*
** CAPI3REF: Convenience Routines For Running Queries
**
+** This is a legacy interface that is preserved for backwards compatibility.
+** Use of this interface is not recommended.
+**
** Definition: A result table is memory data structure created by the
** [sqlite3_get_table()] interface. A result table records the
** complete query results from one or more queries.
@@ -2163,7 +2435,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
** It is not safe to pass a result table directly to [sqlite3_free()].
** A result table should be deallocated using [sqlite3_free_table()].
**
-** As an example of the result table format, suppose a query result
+** ^(As an example of the result table format, suppose a query result
** is as follows:
**
**
@@ -2187,7 +2459,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
** azResult[5] = "28";
** azResult[6] = "Cindy";
** azResult[7] = "21";
-**
+** )^
**
** ^The sqlite3_get_table() function evaluates one or more
** semicolon-separated SQL statements in the zero-terminated UTF-8
@@ -2195,19 +2467,19 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
** pointer given in its 3rd parameter.
**
** After the application has finished with the result from sqlite3_get_table(),
-** it should pass the result table pointer to sqlite3_free_table() in order to
+** it must pass the result table pointer to sqlite3_free_table() in order to
** release the memory that was malloced. Because of the way the
** [sqlite3_malloc()] happens within sqlite3_get_table(), the calling
** function must not try to call [sqlite3_free()] directly. Only
** [sqlite3_free_table()] is able to release the memory properly and safely.
**
-** ^(The sqlite3_get_table() interface is implemented as a wrapper around
+** The sqlite3_get_table() interface is implemented as a wrapper around
** [sqlite3_exec()]. The sqlite3_get_table() routine does not have access
** to any internal data structures of SQLite. It uses only the public
** interface defined here. As a consequence, errors that occur in the
** wrapper layer outside of the internal [sqlite3_exec()] call are not
** reflected in subsequent calls to [sqlite3_errcode()] or
-** [sqlite3_errmsg()].)^
+** [sqlite3_errmsg()].
*/
SQLITE_API int sqlite3_get_table(
sqlite3 *db, /* An open database */
@@ -2232,7 +2504,7 @@ SQLITE_API void sqlite3_free_table(char **result);
** NULL pointer if [sqlite3_malloc()] is unable to allocate enough
** memory to hold the resulting string.
**
-** ^(In sqlite3_snprintf() routine is similar to "snprintf()" from
+** ^(The sqlite3_snprintf() routine is similar to "snprintf()" from
** the standard C library. The result is written into the
** buffer supplied as the second parameter whose size is given by
** the first parameter. Note that the order of the
@@ -2251,6 +2523,8 @@ SQLITE_API void sqlite3_free_table(char **result);
** the zero terminator. So the longest string that can be completely
** written will be n-1 characters.
**
+** ^The sqlite3_vsnprintf() routine is a varargs version of sqlite3_snprintf().
+**
** These routines all implement some additional formatting
** options that are useful for constructing SQL statements.
** All of the usual printf() formatting options apply. In addition, there
@@ -2314,6 +2588,7 @@ SQLITE_API void sqlite3_free_table(char **result);
SQLITE_API char *sqlite3_mprintf(const char*,...);
SQLITE_API char *sqlite3_vmprintf(const char*, va_list);
SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...);
+SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
/*
** CAPI3REF: Memory Allocation Subsystem
@@ -2359,7 +2634,9 @@ SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...);
** is not freed.
**
** ^The memory returned by sqlite3_malloc() and sqlite3_realloc()
-** is always aligned to at least an 8 byte boundary.
+** is always aligned to at least an 8 byte boundary, or to a
+** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time
+** option is used.
**
** In SQLite version 3.5.0 and 3.5.1, it was possible to define
** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in
@@ -2436,7 +2713,7 @@ SQLITE_API void sqlite3_randomness(int N, void *P);
/*
** CAPI3REF: Compile-Time Authorization Callbacks
**
-** ^This routine registers a authorizer callback with a particular
+** ^This routine registers an authorizer callback with a particular
** [database connection], supplied in the first argument.
** ^The authorizer callback is invoked as SQL statements are being compiled
** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()],
@@ -2456,7 +2733,7 @@ SQLITE_API void sqlite3_randomness(int N, void *P);
** requested is ok. ^When the callback returns [SQLITE_DENY], the
** [sqlite3_prepare_v2()] or equivalent call that triggered the
** authorizer will fail with an error message explaining that
-** access is denied.
+** access is denied.
**
** ^The first parameter to the authorizer callback is a copy of the third
** parameter to the sqlite3_set_authorizer() interface. ^The second parameter
@@ -2503,7 +2780,7 @@ SQLITE_API void sqlite3_randomness(int N, void *P);
** database connections for the meaning of "modify" in this paragraph.
**
** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the
-** statement might be re-prepared during [sqlite3_step()] due to a
+** statement might be re-prepared during [sqlite3_step()] due to a
** schema change. Hence, the application should ensure that the
** correct authorizer callback remains in place during the [sqlite3_step()].
**
@@ -2527,6 +2804,9 @@ SQLITE_API int sqlite3_set_authorizer(
** to signal SQLite whether or not the action is permitted. See the
** [sqlite3_set_authorizer | authorizer documentation] for additional
** information.
+**
+** Note that SQLITE_IGNORE is also used as a [SQLITE_ROLLBACK | return code]
+** from the [sqlite3_vtab_on_conflict()] interface.
*/
#define SQLITE_DENY 1 /* Abort the SQL statement with an error */
#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
@@ -2587,7 +2867,6 @@ SQLITE_API int sqlite3_set_authorizer(
/*
** CAPI3REF: Tracing And Profiling Functions
-** EXPERIMENTAL
**
** These routines register callback functions that can be used for
** tracing and profiling the execution of SQL statements.
@@ -2603,26 +2882,43 @@ SQLITE_API int sqlite3_set_authorizer(
** ^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
-** of how long that statement took to run.
+** of how long that statement took to run. ^The profile callback
+** time is in units of nanoseconds, however the current implementation
+** is only capable of millisecond resolution so the six least significant
+** digits in the time are meaningless. Future versions of SQLite
+** might provide greater resolution on the profiler callback. The
+** sqlite3_profile() function is considered experimental and is
+** subject to change in future versions of SQLite.
*/
-SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
+SQLITE_API void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
/*
** CAPI3REF: Query Progress Callbacks
**
-** ^This routine configures a callback function - the
-** progress callback - that is invoked periodically during long
-** running calls to [sqlite3_exec()], [sqlite3_step()] and
-** [sqlite3_get_table()]. An example use for this
+** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback
+** function X to be invoked periodically during long running calls to
+** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for
+** database connection D. An example use for this
** interface is to keep a GUI updated during a large query.
**
+** ^The parameter P is passed through as the only parameter to the
+** callback function X. ^The parameter N is the number of
+** [virtual machine instructions] that are evaluated between successive
+** invocations of the callback X.
+**
+** ^Only a single progress handler may be defined at one time per
+** [database connection]; setting a new progress handler cancels the
+** old one. ^Setting parameter X to NULL disables the progress handler.
+** ^The progress handler is also disabled by setting N to a value less
+** than 1.
+**
** ^If the progress callback returns non-zero, the operation is
** interrupted. This feature can be used to implement a
** "Cancel" button on a GUI progress dialog box.
**
-** The progress handler must not do anything that will modify
+** The progress handler callback must not do anything that will modify
** the database connection that invoked the progress handler.
** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their
** database connections for the meaning of "modify" in this paragraph.
@@ -2633,7 +2929,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
/*
** CAPI3REF: Opening A New Database Connection
**
-** ^These routines open an SQLite database file whose name is given by the
+** ^These routines open an SQLite database file as specified by the
** filename argument. ^The filename argument is interpreted as UTF-8 for
** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte
** order for sqlite3_open16(). ^(A [database connection] handle is usually
@@ -2658,9 +2954,9 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** except that it accepts two additional parameters for additional control
** over the new database connection. ^(The flags parameter to
** sqlite3_open_v2() can take one of
-** the following three values, optionally combined with the
+** the following three values, optionally combined with the
** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE],
-** and/or [SQLITE_OPEN_PRIVATECACHE] flags:)^
+** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^
**
**
** ^(- [SQLITE_OPEN_READONLY]
@@ -2673,15 +2969,14 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** case the database must already exist, otherwise an error is returned.)^
**
** ^(- [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]
-** - The database is opened for reading and writing, and is creates it if
+**
- The database is opened for reading and writing, and is created if
** it does not already exist. This is the behavior that is always used for
** sqlite3_open() and sqlite3_open16().
)^
**
**
** If the 3rd parameter to sqlite3_open_v2() is not one of the
-** combinations shown above or one of the combinations shown above combined
-** with the [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX],
-** [SQLITE_OPEN_SHAREDCACHE] and/or [SQLITE_OPEN_SHAREDCACHE] flags,
+** combinations shown above optionally combined with other
+** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits]
** then the behavior is undefined.
**
** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection
@@ -2696,6 +2991,11 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not
** participate in [shared cache mode] even if it is enabled.
**
+** ^The fourth parameter to sqlite3_open_v2() is the name of the
+** [sqlite3_vfs] object that defines the operating system interface that
+** the new database connection should use. ^If the fourth parameter is
+** a NULL pointer then the default [sqlite3_vfs] object is used.
+**
** ^If the filename is ":memory:", then a private, temporary in-memory database
** is created for the connection. ^This in-memory database will vanish when
** the database connection is closed. Future versions of SQLite might
@@ -2708,10 +3008,111 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** on-disk database will be created. ^This private database will be
** automatically deleted as soon as the database connection is closed.
**
-** ^The fourth parameter to sqlite3_open_v2() is the name of the
-** [sqlite3_vfs] object that defines the operating system interface that
-** the new database connection should use. ^If the fourth parameter is
-** a NULL pointer then the default [sqlite3_vfs] object is used.
+** [[URI filenames in sqlite3_open()]] URI Filenames
+**
+** ^If [URI filename] interpretation is enabled, and the filename argument
+** begins with "file:", then the filename is interpreted as a URI. ^URI
+** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is
+** set in the fourth argument to sqlite3_open_v2(), or if it has
+** been enabled globally using the [SQLITE_CONFIG_URI] option with the
+** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option.
+** As of SQLite version 3.7.7, URI filename interpretation is turned off
+** by default, but future releases of SQLite might enable URI filename
+** interpretation by default. See "[URI filenames]" for additional
+** information.
+**
+** URI filenames are parsed according to RFC 3986. ^If the URI contains an
+** authority, then it must be either an empty string or the string
+** "localhost". ^If the authority is not an empty string or "localhost", an
+** error is returned to the caller. ^The fragment component of a URI, if
+** present, is ignored.
+**
+** ^SQLite uses the path component of the URI as the name of the disk file
+** which contains the database. ^If the path begins with a '/' character,
+** then it is interpreted as an absolute path. ^If the path does not begin
+** with a '/' (meaning that the authority section is omitted from the URI)
+** then the path is interpreted as a relative path.
+** ^On windows, the first component of an absolute path
+** is a drive specification (e.g. "C:").
+**
+** [[core URI query parameters]]
+** The query component of a URI may contain parameters that are interpreted
+** either by SQLite itself, or by a [VFS | custom VFS implementation].
+** SQLite interprets the following three query parameters:
+**
+**
+** - vfs: ^The "vfs" parameter may be used to specify the name of
+** a VFS object that provides the operating system interface that should
+** be used to access the database file on disk. ^If this option is set to
+** an empty string the default VFS object is used. ^Specifying an unknown
+** VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is
+** present, then the VFS specified by the option takes precedence over
+** the value passed as the fourth parameter to sqlite3_open_v2().
+**
+**
- mode: ^(The mode parameter may be set to either "ro", "rw" or
+** "rwc". Attempting to set it to any other value is 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
+** "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
+** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If sqlite3_open_v2() is
+** used, it is an error to specify a value for the mode parameter that is
+** less restrictive than that specified by the flags passed as the third
+** parameter.
+**
+**
- cache: ^The cache parameter may be set to either "shared" or
+** "private". ^Setting it to "shared" is equivalent to setting the
+** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to
+** 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
+** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
+**
+**
+** ^Specifying an unknown parameter in the query component of a URI is not an
+** error. Future versions of SQLite might understand additional query
+** parameters. See "[query parameters with special meaning to SQLite]" for
+** additional information.
+**
+** [[URI filename examples]] URI filename examples
+**
+**
+** URI filenames | Results
+** |
---|
file:data.db |
+** Open the file "data.db" in the current directory.
+** |
file:/home/fred/data.db
+** file:///home/fred/data.db
+** file://localhost/home/fred/data.db |
+** Open the database file "/home/fred/data.db".
+** |
file://darkstar/home/fred/data.db |
+** An error. "darkstar" is not a recognized authority.
+** |
+** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db
+** | Windows only: Open the file "data.db" on fred's desktop on drive
+** C:. Note that the %20 escaping in this example is not strictly
+** necessary - space characters can be used literally
+** in URI filenames.
+** |
file:data.db?mode=ro&cache=private |
+** Open file "data.db" in the current directory for read-only access.
+** Regardless of whether or not shared-cache mode is enabled by
+** default, use a private cache.
+** |
file:/home/fred/data.db?vfs=unix-nolock |
+** Open file "/home/fred/data.db". Use the special VFS "unix-nolock".
+** |
file:data.db?mode=readonly |
+** An error. "readonly" is not a valid option for the "mode" parameter.
+** |
+**
+** ^URI hexadecimal escape sequences (%HH) are supported within the path and
+** query components of a URI. A hexadecimal escape sequence consists of a
+** percent sign - "%" - followed by exactly two hexadecimal digits
+** specifying an octet value. ^Before the path or query components of a
+** URI filename are interpreted, they are encoded using UTF-8 and all
+** hexadecimal escape sequences replaced by a single byte containing the
+** corresponding octet. If this process generates an invalid UTF-8 encoding,
+** the results are undefined.
**
** Note to Windows users: The encoding used for the filename argument
** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever
@@ -2734,6 +3135,26 @@ SQLITE_API int sqlite3_open_v2(
const char *zVfs /* Name of VFS module to use */
);
+/*
+** CAPI3REF: Obtain Values For URI Parameters
+**
+** This is a utility routine, useful to VFS implementations, that checks
+** to see if a database file was a URI that contained a specific query
+** parameter, and if so obtains the value of the query parameter.
+**
+** The zFilename argument is the filename pointer passed into the xOpen()
+** method of a VFS implementation. The zParam argument is the name of the
+** query parameter we seek. This routine returns the value of the zParam
+** parameter if it exists. If the parameter does not exist, this routine
+** returns a NULL pointer.
+**
+** If the zFilename argument to this function is not a pointer that SQLite
+** passed into the xOpen VFS method, then the behavior of this routine
+** is undefined and probably undesirable.
+*/
+SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
+
+
/*
** CAPI3REF: Error Codes And Messages
**
@@ -2742,7 +3163,7 @@ SQLITE_API int sqlite3_open_v2(
** associated with a [database connection]. If a prior API call failed
** but the most recent API call succeeded, the return value from
** sqlite3_errcode() is undefined. ^The sqlite3_extended_errcode()
-** interface is the same except that it always returns the
+** interface is the same except that it always returns the
** [extended result code] even when extended result codes are
** disabled.
**
@@ -2806,17 +3227,22 @@ typedef struct sqlite3_stmt sqlite3_stmt;
** [database connection] whose limit is to be set or queried. The
** second parameter is one of the [limit categories] that define a
** class of constructs to be size limited. The third parameter is the
-** new limit for that construct. The function returns the old limit.)^
+** new limit for that construct.)^
**
** ^If the new limit is a negative number, the limit is unchanged.
-** ^(For the limit category of SQLITE_LIMIT_XYZ there is a
+** ^(For each limit category SQLITE_LIMIT_NAME there is a
** [limits | hard upper bound]
-** set by a compile-time C preprocessor macro named
-** [limits | SQLITE_MAX_XYZ].
+** set at compile-time by a C preprocessor macro called
+** [limits | SQLITE_MAX_NAME].
** (The "_LIMIT_" in the name is changed to "_MAX_".))^
** ^Attempts to increase a limit above its hard upper bound are
** silently truncated to the hard upper bound.
**
+** ^Regardless of whether or not the limit was changed, the
+** [sqlite3_limit()] interface returns the prior value of the limit.
+** ^Hence, to find the current value of a limit without changing it,
+** simply invoke this interface with the third parameter set to -1.
+**
** Run-time limits are intended for use in applications that manage
** both their own internal database and also databases that are controlled
** by untrusted external sources. An example application might be a
@@ -2844,42 +3270,45 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** Additional information is available at [limits | Limits in SQLite].
**
**
-** ^(- SQLITE_LIMIT_LENGTH
-** - The maximum size of any string or BLOB or table row.
- )^
+** [[SQLITE_LIMIT_LENGTH]] ^(
- SQLITE_LIMIT_LENGTH
+** - The maximum size of any string or BLOB or table row, in bytes.
- )^
**
-** ^(
- SQLITE_LIMIT_SQL_LENGTH
+** [[SQLITE_LIMIT_SQL_LENGTH]] ^(- SQLITE_LIMIT_SQL_LENGTH
** - The maximum length of an SQL statement, in bytes.
)^
**
-** ^(- SQLITE_LIMIT_COLUMN
+** [[SQLITE_LIMIT_COLUMN]] ^(- SQLITE_LIMIT_COLUMN
** - The maximum number of columns in a table definition or in the
** result set of a [SELECT] or the maximum number of columns in an index
** or in an ORDER BY or GROUP BY clause.
)^
**
-** ^(- SQLITE_LIMIT_EXPR_DEPTH
+** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(- SQLITE_LIMIT_EXPR_DEPTH
** - The maximum depth of the parse tree on any expression.
)^
**
-** ^(- SQLITE_LIMIT_COMPOUND_SELECT
+** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(- SQLITE_LIMIT_COMPOUND_SELECT
** - The maximum number of terms in a compound SELECT statement.
)^
**
-** ^(- SQLITE_LIMIT_VDBE_OP
+** [[SQLITE_LIMIT_VDBE_OP]] ^(- SQLITE_LIMIT_VDBE_OP
** - The maximum number of instructions in a virtual machine program
-** used to implement an SQL statement.
)^
+** used to implement an SQL statement. This limit is not currently
+** enforced, though that might be added in some future release of
+** SQLite.)^
**
-** ^(- SQLITE_LIMIT_FUNCTION_ARG
+** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(- SQLITE_LIMIT_FUNCTION_ARG
** - The maximum number of arguments on a function.
)^
**
-** ^(- SQLITE_LIMIT_ATTACHED
+** [[SQLITE_LIMIT_ATTACHED]] ^(- SQLITE_LIMIT_ATTACHED
** - The maximum number of [ATTACH | attached databases].)^
**
+** [[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]]
** ^(- SQLITE_LIMIT_LIKE_PATTERN_LENGTH
** - The maximum length of the pattern argument to the [LIKE] or
** [GLOB] operators.
)^
**
+** [[SQLITE_LIMIT_VARIABLE_NUMBER]]
** ^(- SQLITE_LIMIT_VARIABLE_NUMBER
-** - The maximum number of variables in an SQL statement that can
-** be bound.
)^
+** - The maximum index number of any [parameter] in an SQL statement.)^
**
-** ^(
- SQLITE_LIMIT_TRIGGER_DEPTH
+** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(- SQLITE_LIMIT_TRIGGER_DEPTH
** - The maximum depth of recursion for triggers.
)^
**
*/
@@ -2949,12 +3378,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
**
** ^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. ^If the schema has changed in
-** a way that makes the statement no longer valid, [sqlite3_step()] will still
-** return [SQLITE_SCHEMA]. But unlike the legacy behavior, [SQLITE_SCHEMA] is
-** now a fatal error. Calling [sqlite3_prepare_v2()] again will not make the
-** error go away. Note: use [sqlite3_errmsg()] to find the text
-** of the parsing error that results in an [SQLITE_SCHEMA] return.
+** statement and try to run it again.
**
**
**
@@ -2967,11 +3391,16 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
**
**
**
-** ^If the value of a [parameter | host parameter] in the WHERE clause might
-** change the query plan for a statement, then the statement may be
-** automatically recompiled (as if there had been a schema change) on the first
-** [sqlite3_step()] call following any change to the
-** [sqlite3_bind_text | bindings] of the [parameter].
+** ^If the specific value bound to [parameter | host parameter] in the
+** WHERE clause might influence the choice of query plan for a statement,
+** then the statement will be automatically recompiled, as if there had been
+** a schema change, on the first [sqlite3_step()] call following any change
+** to the [sqlite3_bind_text | bindings] of that [parameter].
+** ^The specific value of WHERE-clause [parameter] might influence the
+** choice of query plan if the parameter is the left-hand side of a [LIKE]
+** or [GLOB] operator or if the parameter is compared to an indexed column
+** and the [SQLITE_ENABLE_STAT2] compile-time option is enabled.
+** the
**
**
*/
@@ -3013,6 +3442,37 @@ SQLITE_API int sqlite3_prepare16_v2(
*/
SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
+/*
+** CAPI3REF: Determine If An SQL Statement Writes The Database
+**
+** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if
+** and only if the [prepared statement] X makes no direct changes to
+** the content of the database file.
+**
+** Note that [application-defined SQL functions] or
+** [virtual tables] might change the database indirectly as a side effect.
+** ^(For example, if an application defines a function "eval()" that
+** calls [sqlite3_exec()], then the following SQL statement would
+** change the database file through side-effects:
+**
+**
+** SELECT eval('DELETE FROM t1') FROM t2;
+**
+**
+** But because the [SELECT] statement does not change the database file
+** directly, sqlite3_stmt_readonly() would still return true.)^
+**
+** ^Transaction control statements such as [BEGIN], [COMMIT], [ROLLBACK],
+** [SAVEPOINT], and [RELEASE] cause sqlite3_stmt_readonly() to return true,
+** since the statements themselves do not actually modify the database but
+** rather they control the timing of when other statements modify the
+** database. ^The [ATTACH] and [DETACH] statements also cause
+** sqlite3_stmt_readonly() to return true since, while those statements
+** change the configuration of a database connection, they do not make
+** changes to the content of the database files on disk.
+*/
+SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
+
/*
** CAPI3REF: Dynamically Typed Value Object
** KEYWORDS: {protected sqlite3_value} {unprotected sqlite3_value}
@@ -3029,16 +3489,16 @@ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
** whether or not it requires a protected sqlite3_value.
**
** The terms "protected" and "unprotected" refer to whether or not
-** a mutex is held. A internal mutex is held for a protected
+** a mutex is held. An internal mutex is held for a protected
** sqlite3_value object but no mutex is held for an unprotected
** sqlite3_value object. If SQLite is compiled to be single-threaded
** (with [SQLITE_THREADSAFE=0] and with [sqlite3_threadsafe()] returning 0)
-** or if SQLite is run in one of reduced mutex modes
+** or if SQLite is run in one of reduced mutex modes
** [SQLITE_CONFIG_SINGLETHREAD] or [SQLITE_CONFIG_MULTITHREAD]
** then there is no distinction between protected and unprotected
** sqlite3_value objects and they can be used interchangeably. However,
** for maximum code portability it is recommended that applications
-** still make the distinction between between protected and unprotected
+** still make the distinction between protected and unprotected
** sqlite3_value objects even when not strictly required.
**
** ^The sqlite3_value objects that are passed as parameters into the
@@ -3084,7 +3544,7 @@ typedef struct sqlite3_context sqlite3_context;
**
**
** In the templates above, NNN represents an integer literal,
-** and VVV represents an alphanumeric identifer.)^ ^The values of these
+** and VVV represents an alphanumeric identifier.)^ ^The values of these
** parameters (also called "host parameter names" or "SQL parameters")
** can be set using the sqlite3_bind_*() routines defined here.
**
@@ -3112,7 +3572,10 @@ typedef struct sqlite3_context sqlite3_context;
**
** ^The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and
** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
-** string after SQLite has finished with it. ^If the fifth argument is
+** string after SQLite has finished with it. ^The destructor is called
+** to dispose of the BLOB or string even if the call to sqlite3_bind_blob(),
+** sqlite3_bind_text(), or sqlite3_bind_text16() fails.
+** ^If the fifth argument is
** the special value [SQLITE_STATIC], then SQLite assumes that the
** information is in static, unmanaged space and does not need to be freed.
** ^If the fifth argument has the value [SQLITE_TRANSIENT], then
@@ -3233,6 +3696,8 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
** ^Return the number of columns in the result set returned by the
** [prepared statement]. ^This routine returns 0 if pStmt is an SQL
** statement that does not return data (for example an [UPDATE]).
+**
+** See also: [sqlite3_data_count()]
*/
SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
@@ -3248,7 +3713,9 @@ SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
** column number. ^The leftmost column is number 0.
**
** ^The returned string pointer is valid until either the [prepared statement]
-** is destroyed by [sqlite3_finalize()] or until the next call to
+** is destroyed by [sqlite3_finalize()] or until the statement is automatically
+** reprepared by the first call to [sqlite3_step()] for a particular run
+** or until the next call to
** sqlite3_column_name() or sqlite3_column_name16() on the same column.
**
** ^If sqlite3_malloc() fails during the processing of either routine
@@ -3274,7 +3741,9 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
** the database name, the _table_ routines return the table name, and
** the origin_ routines return the column name.
** ^The returned string is valid until the [prepared statement] is destroyed
-** using [sqlite3_finalize()] or until the same information is requested
+** using [sqlite3_finalize()] or until the statement is automatically
+** reprepared by the first call to [sqlite3_step()] for a particular run
+** or until the same information is requested
** again in a different encoding.
**
** ^The names returned are the original un-aliased names of the
@@ -3368,7 +3837,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
** ^[SQLITE_BUSY] means that the database engine was unable to acquire the
** database locks it needs to do its job. ^If the statement is a [COMMIT]
** or occurs outside of an explicit transaction, then you can retry the
-** statement. If the statement is not a [COMMIT] and occurs within a
+** statement. If the statement is not a [COMMIT] and occurs within an
** explicit transaction then you should rollback the transaction before
** continuing.
**
@@ -3398,6 +3867,18 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
** be the case that the same database connection is being used by two or
** more threads at the same moment in time.
**
+** For all versions of SQLite up to and including 3.6.23.1, a call to
+** [sqlite3_reset()] was required after sqlite3_step() returned anything
+** other than [SQLITE_ROW] before any subsequent invocation of
+** sqlite3_step(). Failure to reset the prepared statement using
+** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
+** sqlite3_step(). But after version 3.6.23.1, sqlite3_step() began
+** calling [sqlite3_reset()] automatically in this circumstance rather
+** than returning [SQLITE_MISUSE]. This is not considered a compatibility
+** break because any application that ever receives an SQLITE_MISUSE error
+** is broken by definition. The [SQLITE_OMIT_AUTORESET] compile-time option
+** can be used to restore the legacy behavior.
+**
** Goofy Interface Alert: In the legacy interface, the sqlite3_step()
** API always returns a generic error code, [SQLITE_ERROR], following any
** error other than [SQLITE_BUSY] and [SQLITE_MISUSE]. You must call
@@ -3415,8 +3896,14 @@ SQLITE_API int sqlite3_step(sqlite3_stmt*);
/*
** CAPI3REF: Number of columns in a result set
**
-** ^The sqlite3_data_count(P) the number of columns in the
-** of the result set of [prepared statement] P.
+** ^The sqlite3_data_count(P) interface returns the number of columns in the
+** current row of the result set of [prepared statement] P.
+** ^If prepared statement P does not have results ready to return
+** (via calls to the [sqlite3_column_int | sqlite3_column_*()] of
+** interfaces) then sqlite3_data_count(P) returns 0.
+** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer.
+**
+** See also: [sqlite3_column_count()]
*/
SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
@@ -3496,18 +3983,26 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** ^If the result is a numeric value then sqlite3_column_bytes() uses
** [sqlite3_snprintf()] to convert that value to a UTF-8 string and returns
** the number of bytes in that string.
-** ^The value returned does not include the zero terminator at the end
-** of the string. ^For clarity: the value returned is the number of
+** ^If the result is NULL, then sqlite3_column_bytes() returns zero.
+**
+** ^If the result is a BLOB or UTF-16 string then the sqlite3_column_bytes16()
+** routine returns the number of bytes in that BLOB or string.
+** ^If the result is a UTF-8 string, then sqlite3_column_bytes16() converts
+** the string to UTF-16 and then returns the number of bytes.
+** ^If the result is a numeric value then sqlite3_column_bytes16() uses
+** [sqlite3_snprintf()] to convert that value to a UTF-16 string and returns
+** the number of bytes in that string.
+** ^If the result is NULL, then sqlite3_column_bytes16() returns zero.
+**
+** ^The values returned by [sqlite3_column_bytes()] and
+** [sqlite3_column_bytes16()] do not include the zero terminators at the end
+** of the string. ^For clarity: the values returned by
+** [sqlite3_column_bytes()] and [sqlite3_column_bytes16()] are the number of
** bytes in the string, not the number of characters.
**
** ^Strings returned by sqlite3_column_text() and sqlite3_column_text16(),
** even empty strings, are always zero terminated. ^The return
-** value from sqlite3_column_blob() for a zero-length BLOB is an arbitrary
-** pointer, possibly even a NULL pointer.
-**
-** ^The sqlite3_column_bytes16() routine is similar to sqlite3_column_bytes()
-** but leaves the result in UTF-16 in native byte order instead of UTF-8.
-** ^The zero terminator is not included in this count.
+** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
**
** ^The object returned by [sqlite3_column_value()] is an
** [unprotected sqlite3_value] object. An unprotected sqlite3_value object
@@ -3552,10 +4047,10 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** used in the table for brevity and because they are familiar to most
** C programmers.
**
-** ^Note that when type conversions occur, pointers returned by prior
+** Note that when type conversions occur, pointers returned by prior
** calls to sqlite3_column_blob(), sqlite3_column_text(), and/or
** sqlite3_column_text16() may be invalidated.
-** ^(Type conversions and pointer invalidations might occur
+** Type conversions and pointer invalidations might occur
** in the following cases:
**
**
@@ -3568,22 +4063,22 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** - The initial content is UTF-16 text and sqlite3_column_bytes() or
** sqlite3_column_text() is called. The content must be converted
** to UTF-8.
-**
)^
+**
**
** ^Conversions between UTF-16be and UTF-16le are always done in place and do
** not invalidate a prior pointer, though of course the content of the buffer
-** that the prior pointer points to will have been modified. Other kinds
+** that the prior pointer references will have been modified. Other kinds
** of conversion are done in place when it is possible, but sometimes they
** are not possible and in those cases prior pointers are invalidated.
**
-** ^(The safest and easiest to remember policy is to invoke these routines
+** The safest and easiest to remember policy is to invoke these routines
** in one of the following ways:
**
**
** - sqlite3_column_text() followed by sqlite3_column_bytes()
** - sqlite3_column_blob() followed by sqlite3_column_bytes()
** - sqlite3_column_text16() followed by sqlite3_column_bytes16()
-**
)^
+**
**
** In other words, you should call sqlite3_column_text(),
** sqlite3_column_blob(), or sqlite3_column_text16() first to force the result
@@ -3621,17 +4116,26 @@ SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
** CAPI3REF: Destroy A Prepared Statement Object
**
** ^The sqlite3_finalize() function is called to delete a [prepared statement].
-** ^If the statement was executed successfully or not executed at all, then
-** SQLITE_OK is returned. ^If execution of the statement failed then an
-** [error code] or [extended error code] is returned.
+** ^If the most recent evaluation of the statement encountered no errors
+** or if the statement is never been evaluated, then sqlite3_finalize() returns
+** SQLITE_OK. ^If the most recent evaluation of statement S failed, then
+** sqlite3_finalize(S) returns the appropriate [error code] or
+** [extended error code].
**
-** ^This routine can be called at any point during the execution of the
-** [prepared statement]. ^If the virtual machine has not
-** completed execution when this routine is called, that is like
-** encountering an error or an [sqlite3_interrupt | interrupt].
-** ^Incomplete updates may be rolled back and transactions canceled,
-** depending on the circumstances, and the
-** [error code] returned will be [SQLITE_ABORT].
+** ^The sqlite3_finalize(S) routine can be called at any point during
+** the life cycle of [prepared statement] S:
+** before statement S is ever evaluated, after
+** one or more calls to [sqlite3_reset()], or after any call
+** to [sqlite3_step()] regardless of whether or not the statement has
+** completed execution.
+**
+** ^Invoking sqlite3_finalize() on a NULL pointer is a harmless no-op.
+**
+** The application must finalize every [prepared statement] in order to avoid
+** resource leaks. It is a grievous error for the application to try to use
+** a prepared statement after it has been finalized. Any use of a prepared
+** statement after it has been finalized can result in undefined and
+** undesirable behavior such as segfaults and heap corruption.
*/
SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
@@ -3667,23 +4171,25 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** KEYWORDS: {application-defined SQL function}
** KEYWORDS: {application-defined SQL functions}
**
-** ^These two functions (collectively known as "function creation routines")
+** ^These functions (collectively known as "function creation routines")
** are used to add SQL functions or aggregates or to redefine the behavior
-** of existing SQL functions or aggregates. The only difference between the
-** two is that the second parameter, the name of the (scalar) function or
-** aggregate, is encoded in UTF-8 for sqlite3_create_function() and UTF-16
-** for sqlite3_create_function16().
+** of existing SQL functions or aggregates. The only differences between
+** these routines are the text encoding expected for
+** the second parameter (the name of the function being created)
+** and the presence or absence of a destructor callback for
+** the application data pointer.
**
** ^The first parameter is the [database connection] to which the SQL
** function is to be added. ^If an application uses more than one database
** connection then application-defined SQL functions must be added
** to each database connection separately.
**
-** The second parameter is the name of the SQL function to be created or
-** redefined. ^The length of the name is limited to 255 bytes, exclusive of
-** the zero-terminator. Note that the name length limit is in bytes, not
-** characters. ^Any attempt to create a function with a longer name
-** will result in [SQLITE_ERROR] being returned.
+** ^The second parameter is the name of the SQL function to be created or
+** redefined. ^The length of the name is limited to 255 bytes in a UTF-8
+** representation, exclusive of the zero-terminator. ^Note that the name
+** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes.
+** ^Any attempt to create a function with a longer name
+** will result in [SQLITE_MISUSE] being returned.
**
** ^The third parameter (nArg)
** is the number of arguments that the SQL function or
@@ -3693,10 +4199,10 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** parameter is less than -1 or greater than 127 then the behavior is
** undefined.
**
-** The fourth parameter, eTextRep, specifies what
+** ^The fourth parameter, eTextRep, specifies what
** [SQLITE_UTF8 | text encoding] this SQL function prefers for
-** its parameters. Any SQL function implementation should be able to work
-** work with UTF-8, UTF-16le, or UTF-16be. But some implementations may be
+** its parameters. Every SQL function implementation must be able to work
+** with UTF-8, UTF-16le, or UTF-16be. But some implementations may be
** more efficient with one encoding than another. ^An application may
** invoke sqlite3_create_function() or sqlite3_create_function16() multiple
** times with the same function but with different values of eTextRep.
@@ -3708,13 +4214,24 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** ^(The fifth parameter is an arbitrary pointer. The implementation of the
** function can gain access to this pointer using [sqlite3_user_data()].)^
**
-** The seventh, eighth and ninth parameters, xFunc, xStep and xFinal, are
+** ^The sixth, seventh and eighth parameters, xFunc, xStep and xFinal, are
** pointers to C-language functions that implement the SQL function or
** aggregate. ^A scalar SQL function requires an implementation of the xFunc
-** callback only; NULL pointers should be passed as the xStep and xFinal
+** callback only; NULL pointers must be passed as the xStep and xFinal
** parameters. ^An aggregate SQL function requires an implementation of xStep
-** and xFinal and NULL should be passed for xFunc. ^To delete an existing
-** SQL function or aggregate, pass NULL for all three function callbacks.
+** and xFinal and NULL pointer must be passed for xFunc. ^To delete an existing
+** SQL function or aggregate, pass NULL pointers for all three function
+** callbacks.
+**
+** ^(If the ninth parameter to sqlite3_create_function_v2() is not NULL,
+** then it is destructor for the application data pointer.
+** The destructor is invoked when the function is deleted, either by being
+** overloaded or when the database connection closes.)^
+** ^The destructor is also invoked if the call to
+** sqlite3_create_function_v2() fails.
+** ^When the destructor callback of the tenth parameter is invoked, it
+** is passed a single argument which is a copy of the application data
+** pointer which was the fifth parameter to sqlite3_create_function_v2().
**
** ^It is permitted to register multiple implementations of the same
** functions with the same name but with either differing numbers of
@@ -3724,17 +4241,12 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** nArg parameter is a better match than a function implementation with
** a negative nArg. ^A function where the preferred text encoding
** matches the database encoding is a better
-** match than a function where the encoding is different.
+** match than a function where the encoding is different.
** ^A function where the encoding difference is between UTF16le and UTF16be
** is a closer match than a function where the encoding difference is
** between UTF8 and UTF16.
**
** ^Built-in functions may be overloaded by new application-defined functions.
-** ^The first application-defined function with a given name overrides all
-** built-in functions in the same [database connection] with the same name.
-** ^Subsequent application-defined functions of the same name only override
-** prior application-defined functions that are an exact match for the
-** number of parameters and preferred encoding.
**
** ^An application-defined function is permitted to call other
** SQLite interfaces. However, such calls must not
@@ -3761,6 +4273,17 @@ SQLITE_API int sqlite3_create_function16(
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
);
+SQLITE_API int sqlite3_create_function_v2(
+ sqlite3 *db,
+ const char *zFunctionName,
+ int nArg,
+ int eTextRep,
+ void *pApp,
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
+ void (*xStep)(sqlite3_context*,int,sqlite3_value**),
+ void (*xFinal)(sqlite3_context*),
+ void(*xDestroy)(void*)
+);
/*
** CAPI3REF: Text Encodings
@@ -3780,7 +4303,7 @@ SQLITE_API int sqlite3_create_function16(
** DEPRECATED
**
** These functions are [deprecated]. In order to maintain
-** backwards compatibility with older code, these functions continue
+** backwards compatibility with older code, these functions continue
** to be supported. However, new applications should avoid
** the use of these functions. To help encourage people to avoid
** using these functions, we are not going to tell you what they do.
@@ -3804,7 +4327,7 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
** The xFunc (for scalar functions) or xStep (for aggregates) parameters
** to [sqlite3_create_function()] and [sqlite3_create_function16()]
** define callbacks that implement the SQL functions and aggregates.
-** The 4th parameter to these callbacks is an array of pointers to
+** The 3rd parameter to these callbacks is an array of pointers to
** [protected sqlite3_value] objects. There is one [sqlite3_value] object for
** each parameter to the SQL function. These routines are used to
** extract values from the [sqlite3_value] objects.
@@ -3855,10 +4378,10 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
/*
** CAPI3REF: Obtain Aggregate Function Context
**
-** Implementions of aggregate SQL functions use this
+** Implementations of aggregate SQL functions use this
** routine to allocate memory for storing their state.
**
-** ^The first time the sqlite3_aggregate_context(C,N) routine is called
+** ^The first time the sqlite3_aggregate_context(C,N) routine is called
** for a particular aggregate function, SQLite
** allocates N of memory, zeroes out that memory, and returns a pointer
** to the new memory. ^On second and subsequent calls to
@@ -3880,7 +4403,7 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
** the same aggregate function instance will not resize the memory
** allocation.)^
**
-** ^SQLite automatically frees the memory allocated by
+** ^SQLite automatically frees the memory allocated by
** sqlite3_aggregate_context() when the aggregate query concludes.
**
** The first parameter must be a copy of the
@@ -4107,69 +4630,102 @@ SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
/*
** CAPI3REF: Define New Collating Sequences
**
-** These functions are used to add new collation sequences to the
-** [database connection] specified as the first argument.
+** ^These functions add, remove, or modify a [collation] associated
+** with the [database connection] specified as the first argument.
**
-** ^The name of the new collation sequence is specified as a UTF-8 string
+** ^The name of the collation is a UTF-8 string
** for sqlite3_create_collation() and sqlite3_create_collation_v2()
-** and a UTF-16 string for sqlite3_create_collation16(). ^In all cases
-** the name is passed as the second function argument.
+** and a UTF-16 string in native byte order for sqlite3_create_collation16().
+** ^Collation names that compare equal according to [sqlite3_strnicmp()] are
+** considered to be the same name.
**
-** ^The third argument may be one of the constants [SQLITE_UTF8],
-** [SQLITE_UTF16LE], or [SQLITE_UTF16BE], indicating that the user-supplied
-** routine expects to be passed pointers to strings encoded using UTF-8,
-** UTF-16 little-endian, or UTF-16 big-endian, respectively. ^The
-** third argument might also be [SQLITE_UTF16] to indicate that the routine
-** expects pointers to be UTF-16 strings in the native byte order, or the
-** argument can be [SQLITE_UTF16_ALIGNED] if the
-** the routine expects pointers to 16-bit word aligned strings
-** of UTF-16 in the native byte order.
+** ^(The third argument (eTextRep) must be one of the constants:
+**
+** - [SQLITE_UTF8],
+**
- [SQLITE_UTF16LE],
+**
- [SQLITE_UTF16BE],
+**
- [SQLITE_UTF16], or
+**
- [SQLITE_UTF16_ALIGNED].
+**
)^
+** ^The eTextRep argument determines the encoding of strings passed
+** to the collating function callback, xCallback.
+** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep
+** force strings to be UTF16 with native byte order.
+** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin
+** on an even byte address.
**
-** A pointer to the user supplied routine must be passed as the fifth
-** argument. ^If it is NULL, this is the same as deleting the collation
-** sequence (so that SQLite cannot call it anymore).
-** ^Each time the application supplied function is invoked, it is passed
-** as its first parameter a copy of the void* passed as the fourth argument
-** to sqlite3_create_collation() or sqlite3_create_collation16().
+** ^The fourth argument, pArg, is an application data pointer that is passed
+** through as the first argument to the collating function callback.
**
-** ^The remaining arguments to the application-supplied routine are two strings,
-** each represented by a (length, data) pair and encoded in the encoding
-** that was passed as the third argument when the collation sequence was
-** registered. The application defined collation routine should
-** return negative, zero or positive if the first string is less than,
-** equal to, or greater than the second string. i.e. (STRING1 - STRING2).
+** ^The fifth argument, xCallback, is a pointer to the collating function.
+** ^Multiple collating functions can be registered using the same name but
+** with different eTextRep parameters and SQLite will use whichever
+** function requires the least amount of data transformation.
+** ^If the xCallback argument is NULL then the collating function is
+** deleted. ^When all collating functions having the same name are deleted,
+** that collation is no longer usable.
+**
+** ^The collating function callback is invoked with a copy of the pArg
+** application data pointer and with two strings in the encoding specified
+** by the eTextRep argument. The collating function must return an
+** integer that is negative, zero, or positive
+** if the first string is less than, equal to, or greater than the second,
+** respectively. A collating function must always return the same answer
+** given the same inputs. If two or more collating functions are registered
+** to the same collation name (using different eTextRep values) then all
+** must give an equivalent answer when invoked with equivalent strings.
+** The collating function must obey the following properties for all
+** strings A, B, and C:
+**
+**
+** - If A==B then B==A.
+**
- If A==B and B==C then A==C.
+**
- If A<B THEN B>A.
+**
- If A<B and B<C then A<C.
+**
+**
+** If a collating function fails any of the above constraints and that
+** collating function is registered and used, then the behavior of SQLite
+** is undefined.
**
** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation()
-** except that it takes an extra argument which is a destructor for
-** the collation. ^The destructor is called when the collation is
-** destroyed and is passed a copy of the fourth parameter void* pointer
-** of the sqlite3_create_collation_v2().
-** ^Collations are destroyed when they are overridden by later calls to the
-** collation creation functions or when the [database connection] is closed
-** using [sqlite3_close()].
+** with the addition that the xDestroy callback is invoked on pArg when
+** the collating function is deleted.
+** ^Collating functions are deleted when they are overridden by later
+** calls to the collation creation functions or when the
+** [database connection] is closed using [sqlite3_close()].
+**
+** ^The xDestroy callback is not called if the
+** sqlite3_create_collation_v2() function fails. Applications that invoke
+** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should
+** check the return code and dispose of the application data pointer
+** themselves rather than expecting SQLite to deal with it for them.
+** This is different from every other SQLite interface. The inconsistency
+** is unfortunate but cannot be changed without breaking backwards
+** compatibility.
**
** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()].
*/
SQLITE_API int sqlite3_create_collation(
- sqlite3*,
- const char *zName,
- int eTextRep,
- void*,
+ sqlite3*,
+ const char *zName,
+ int eTextRep,
+ void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*)
);
SQLITE_API int sqlite3_create_collation_v2(
- sqlite3*,
- const char *zName,
- int eTextRep,
- void*,
+ sqlite3*,
+ const char *zName,
+ int eTextRep,
+ void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*),
void(*xDestroy)(void*)
);
SQLITE_API int sqlite3_create_collation16(
- sqlite3*,
+ sqlite3*,
const void *zName,
- int eTextRep,
- void*,
+ int eTextRep,
+ void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*)
);
@@ -4200,17 +4756,17 @@ SQLITE_API int sqlite3_create_collation16(
** [sqlite3_create_collation_v2()].
*/
SQLITE_API int sqlite3_collation_needed(
- sqlite3*,
- void*,
+ sqlite3*,
+ void*,
void(*)(void*,sqlite3*,int eTextRep,const char*)
);
SQLITE_API int sqlite3_collation_needed16(
- sqlite3*,
+ sqlite3*,
void*,
void(*)(void*,sqlite3*,int eTextRep,const void*)
);
-#if SQLITE_HAS_CODEC
+#ifdef SQLITE_HAS_CODEC
/*
** Specify the key for an encrypted database. This routine should be
** called right after sqlite3_open().
@@ -4237,7 +4793,7 @@ SQLITE_API int sqlite3_rekey(
);
/*
-** Specify the activation key for a SEE database. Unless
+** Specify the activation key for a SEE database. Unless
** activated, none of the SEE routines will work.
*/
SQLITE_API void sqlite3_activate_see(
@@ -4247,7 +4803,7 @@ SQLITE_API void sqlite3_activate_see(
#ifdef SQLITE_ENABLE_CEROD
/*
-** Specify the activation key for a CEROD database. Unless
+** Specify the activation key for a CEROD database. Unless
** activated, none of the CEROD routines will work.
*/
SQLITE_API void sqlite3_activate_cerod(
@@ -4258,16 +4814,19 @@ SQLITE_API void sqlite3_activate_cerod(
/*
** CAPI3REF: Suspend Execution For A Short Time
**
-** ^The sqlite3_sleep() function causes the current thread to suspend execution
+** The sqlite3_sleep() function causes the current thread to suspend execution
** for at least a number of milliseconds specified in its parameter.
**
-** ^If the operating system does not support sleep requests with
+** If the operating system does not support sleep requests with
** millisecond time resolution, then the time will be rounded up to
-** the nearest second. ^The number of milliseconds of sleep actually
+** the nearest second. The number of milliseconds of sleep actually
** requested from the operating system is returned.
**
** ^SQLite implements this interface by calling the xSleep()
-** method of the default [sqlite3_vfs] object.
+** method of the default [sqlite3_vfs] object. If the xSleep() method
+** of the default VFS is not implemented correctly, or not implemented at
+** all, then the behavior of sqlite3_sleep() may deviate from the description
+** in the previous paragraphs.
*/
SQLITE_API int sqlite3_sleep(int);
@@ -4293,7 +4852,7 @@ SQLITE_API int sqlite3_sleep(int);
** ^The [temp_store_directory pragma] may modify this variable and cause
** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore,
** the [temp_store_directory pragma] always assumes that any string
-** that this variable points to is held in memory obtained from
+** that this variable points to is held in memory obtained from
** [sqlite3_malloc] and the pragma may attempt to free that memory
** using [sqlite3_free].
** Hence, if this variable is modified directly, either it should be
@@ -4393,8 +4952,6 @@ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
** an error or constraint causes an implicit rollback to occur.
** ^The rollback callback is not invoked if a transaction is
** automatically rolled back because the database connection is closed.
-** ^The rollback callback is not invoked if a transaction is
-** rolled back because a commit callback returned non-zero.
**
** See also the [sqlite3_update_hook()] interface.
*/
@@ -4448,7 +5005,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** interfaces.
*/
SQLITE_API void *sqlite3_update_hook(
- sqlite3*,
+ sqlite3*,
void(*)(void *,int ,char const *,char const *,sqlite3_int64),
void*
);
@@ -4491,40 +5048,73 @@ SQLITE_API int sqlite3_enable_shared_cache(int);
** pages to improve performance is an example of non-essential memory.
** ^sqlite3_release_memory() returns the number of bytes actually freed,
** which might be more or less than the amount requested.
+** ^The sqlite3_release_memory() routine is a no-op returning zero
+** if SQLite is not compiled with [SQLITE_ENABLE_MEMORY_MANAGEMENT].
*/
SQLITE_API int sqlite3_release_memory(int);
/*
** CAPI3REF: Impose A Limit On Heap Size
**
-** ^The sqlite3_soft_heap_limit() interface places a "soft" limit
-** on the amount of heap memory that may be allocated by SQLite.
-** ^If an internal allocation is requested that would exceed the
-** soft heap limit, [sqlite3_release_memory()] is invoked one or
-** more times to free up some space before the allocation is performed.
+** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the
+** soft limit on the amount of heap memory that may be allocated by SQLite.
+** ^SQLite strives to keep heap memory utilization below the soft heap
+** limit by reducing the number of pages held in the page cache
+** as heap memory usages approaches the limit.
+** ^The soft heap limit is "soft" because even though SQLite strives to stay
+** below the limit, it will exceed the limit rather than generate
+** an [SQLITE_NOMEM] error. In other words, the soft heap limit
+** is advisory only.
**
-** ^The limit is called "soft" because if [sqlite3_release_memory()]
-** cannot free sufficient memory to prevent the limit from being exceeded,
-** the memory is allocated anyway and the current operation proceeds.
+** ^The return value from sqlite3_soft_heap_limit64() is the size of
+** the soft heap limit prior to the call. ^If the argument N is negative
+** then no change is made to the soft heap limit. Hence, the current
+** size of the soft heap limit can be determined by invoking
+** sqlite3_soft_heap_limit64() with a negative argument.
**
-** ^A negative or zero value for N means that there is no soft heap limit and
-** [sqlite3_release_memory()] will only be called when memory is exhausted.
-** ^The default value for the soft heap limit is zero.
+** ^If the argument N is zero then the soft heap limit is disabled.
**
-** ^(SQLite makes a best effort to honor the soft heap limit.
-** But if the soft heap limit cannot be honored, execution will
-** continue without error or notification.)^ This is why the limit is
-** called a "soft" limit. It is advisory only.
+** ^(The soft heap limit is not enforced in the current implementation
+** if one or more of following conditions are true:
**
-** Prior to SQLite version 3.5.0, this routine only constrained the memory
-** allocated by a single thread - the same thread in which this routine
-** runs. Beginning with SQLite version 3.5.0, the soft heap limit is
-** applied to all threads. The value specified for the soft heap limit
-** is an upper bound on the total memory allocation for all threads. In
-** version 3.5.0 there is no mechanism for limiting the heap usage for
-** individual threads.
+**
+** - The soft heap limit is set to zero.
+**
- Memory accounting is disabled using a combination of the
+** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and
+** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option.
+**
- An alternative page cache implementation is specified using
+** [sqlite3_config]([SQLITE_CONFIG_PCACHE],...).
+**
- The page cache allocates from its own memory pool supplied
+** by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than
+** from the heap.
+**
)^
+**
+** Beginning with SQLite version 3.7.3, the soft heap limit is enforced
+** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT]
+** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT],
+** the soft heap limit is enforced on every memory allocation. Without
+** [SQLITE_ENABLE_MEMORY_MANAGEMENT], the soft heap limit is only enforced
+** when memory is allocated by the page cache. Testing suggests that because
+** the page cache is the predominate memory user in SQLite, most
+** applications will achieve adequate soft heap limit enforcement without
+** the use of [SQLITE_ENABLE_MEMORY_MANAGEMENT].
+**
+** The circumstances under which SQLite will enforce the soft heap limit may
+** changes in future releases of SQLite.
*/
-SQLITE_API void sqlite3_soft_heap_limit(int);
+SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
+
+/*
+** CAPI3REF: Deprecated Soft Heap Limit Interface
+** DEPRECATED
+**
+** This is a deprecated version of the [sqlite3_soft_heap_limit64()]
+** interface. This routine is provided for historical compatibility
+** only. All new applications should use the
+** [sqlite3_soft_heap_limit64()] interface rather than this one.
+*/
+SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
+
/*
** CAPI3REF: Extract Metadata About A Column Of A Table
@@ -4648,40 +5238,51 @@ SQLITE_API int sqlite3_load_extension(
SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
/*
-** CAPI3REF: Automatically Load An Extensions
+** CAPI3REF: Automatically Load Statically Linked Extensions
**
-** ^This API can be invoked at program startup in order to register
-** one or more statically linked extensions that will be available
-** to all new [database connections].
+** ^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
+** that is to be automatically loaded into all new database connections.
**
-** ^(This routine stores a pointer to the extension entry point
-** in an array that is obtained from [sqlite3_malloc()]. That memory
-** is deallocated by [sqlite3_reset_auto_extension()].)^
+** ^(Even though the function prototype shows that xEntryPoint() takes
+** no arguments and returns void, SQLite invokes xEntryPoint() with three
+** arguments and expects and integer result as if the signature of the
+** entry point where as follows:
**
-** ^This function registers an extension entry point that is
-** automatically invoked whenever a new [database connection]
-** is opened using [sqlite3_open()], [sqlite3_open16()],
-** or [sqlite3_open_v2()].
-** ^Duplicate extensions are detected so calling this routine
-** multiple times with the same extension is harmless.
-** ^Automatic extensions apply across all threads.
+**
+** int xEntryPoint(
+** sqlite3 *db,
+** const char **pzErrMsg,
+** const struct sqlite3_api_routines *pThunk
+** );
+**
)^
+**
+** If the xEntryPoint routine encounters an error, it should make *pzErrMsg
+** point to an appropriate error message (obtained from [sqlite3_mprintf()])
+** and return an appropriate [error code]. ^SQLite ensures that *pzErrMsg
+** is NULL before calling the xEntryPoint(). ^SQLite will invoke
+** [sqlite3_free()] on *pzErrMsg after xEntryPoint() returns. ^If any
+** xEntryPoint() returns an error, the [sqlite3_open()], [sqlite3_open16()],
+** or [sqlite3_open_v2()] call that provoked the xEntryPoint() will fail.
+**
+** ^Calling sqlite3_auto_extension(X) with an entry point X that is already
+** on the list of automatic extensions is a harmless no-op. ^No entry point
+** will be called more than once for each database connection that is opened.
+**
+** See also: [sqlite3_reset_auto_extension()].
*/
SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
/*
** CAPI3REF: Reset Automatic Extension Loading
**
-** ^(This function disables all previously registered automatic
-** extensions. It undoes the effect of all prior
-** [sqlite3_auto_extension()] calls.)^
-**
-** ^This function disables automatic extensions in all threads.
+** ^This interface disables all automatic extensions previously
+** registered using [sqlite3_auto_extension()].
*/
SQLITE_API void sqlite3_reset_auto_extension(void);
/*
-****** EXPERIMENTAL - subject to change without notice **************
-**
** The interface to the virtual-table mechanism is currently considered
** to be experimental. The interface might change in incompatible ways.
** If this is a problem for you, do not use the interface at this time.
@@ -4701,10 +5302,9 @@ typedef struct sqlite3_module sqlite3_module;
/*
** CAPI3REF: Virtual Table Object
** KEYWORDS: sqlite3_module {virtual table module}
-** EXPERIMENTAL
**
-** This structure, sometimes called a a "virtual table module",
-** defines the implementation of a [virtual tables].
+** This structure, sometimes called a "virtual table module",
+** defines the implementation of a [virtual tables].
** This structure consists mostly of methods for the module.
**
** ^A virtual table module is created by filling in a persistent
@@ -4743,14 +5343,19 @@ struct sqlite3_module {
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
void **ppArg);
int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
+ /* The methods above are in version 1 of the sqlite_module object. Those
+ ** below are for version 2 and greater. */
+ int (*xSavepoint)(sqlite3_vtab *pVTab, int);
+ int (*xRelease)(sqlite3_vtab *pVTab, int);
+ int (*xRollbackTo)(sqlite3_vtab *pVTab, int);
};
/*
** CAPI3REF: Virtual Table Indexing Information
** KEYWORDS: sqlite3_index_info
-** EXPERIMENTAL
**
-** The sqlite3_index_info structure and its substructures is used to
+** The sqlite3_index_info structure and its substructures is used as part
+** of the [virtual table] interface to
** pass information into and receive the reply from the [xBestIndex]
** method of a [virtual table module]. The fields under **Inputs** are the
** inputs to xBestIndex and are read-only. xBestIndex inserts its
@@ -4758,10 +5363,12 @@ struct sqlite3_module {
**
** ^(The aConstraint[] array records WHERE clause constraints of the form:
**
-** column OP expr
+** column OP expr
**
** where OP is =, <, <=, >, or >=.)^ ^(The particular operator is
-** stored in aConstraint[].op.)^ ^(The index of the column is stored in
+** stored in aConstraint[].op using one of the
+** [SQLITE_INDEX_CONSTRAINT_EQ | SQLITE_INDEX_CONSTRAINT_ values].)^
+** ^(The index of the column is stored in
** aConstraint[].iColumn.)^ ^(aConstraint[].usable is TRUE if the
** expr on the right-hand side can be evaluated (and thus the constraint
** is usable) and false if it cannot.)^
@@ -4821,6 +5428,15 @@ struct sqlite3_index_info {
int orderByConsumed; /* True if output is already ordered */
double estimatedCost; /* Estimated cost of using this index */
};
+
+/*
+** CAPI3REF: Virtual Table Constraint Operator Codes
+**
+** These macros defined the allowed values for the
+** [sqlite3_index_info].aConstraint[].op field. Each value represents
+** an operator that is part of a constraint term in the wHERE clause of
+** a query that uses a [virtual table].
+*/
#define SQLITE_INDEX_CONSTRAINT_EQ 2
#define SQLITE_INDEX_CONSTRAINT_GT 4
#define SQLITE_INDEX_CONSTRAINT_LE 8
@@ -4830,7 +5446,6 @@ struct sqlite3_index_info {
/*
** CAPI3REF: Register A Virtual Table Implementation
-** EXPERIMENTAL
**
** ^These routines are used to register a new [virtual table module] name.
** ^Module names must be registered before
@@ -4838,7 +5453,7 @@ struct sqlite3_index_info {
** preexisting [virtual table] for the module.
**
** ^The module name is registered on the [database connection] specified
-** by the first parameter. ^The name of the module is given by the
+** by the first parameter. ^The name of the module is given by the
** second parameter. ^The third parameter is a pointer to
** the implementation of the [virtual table module]. ^The fourth
** parameter is an arbitrary client data pointer that is passed through
@@ -4848,17 +5463,19 @@ struct sqlite3_index_info {
** ^The sqlite3_create_module_v2() interface has a fifth parameter which
** is a pointer to a destructor for the pClientData. ^SQLite will
** invoke the destructor function (if it is not NULL) when SQLite
-** no longer needs the pClientData pointer. ^The sqlite3_create_module()
+** no longer needs the pClientData pointer. ^The destructor will also
+** be invoked if the call to sqlite3_create_module_v2() fails.
+** ^The sqlite3_create_module()
** interface is equivalent to sqlite3_create_module_v2() with a NULL
** destructor.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_create_module(
+SQLITE_API int sqlite3_create_module(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
void *pClientData /* Client data for xCreate/xConnect */
);
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_create_module_v2(
+SQLITE_API int sqlite3_create_module_v2(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
@@ -4869,7 +5486,6 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_create_module_v2(
/*
** CAPI3REF: Virtual Table Instance Object
** KEYWORDS: sqlite3_vtab
-** EXPERIMENTAL
**
** Every [virtual table module] implementation uses a subclass
** of this object to describe a particular instance
@@ -4895,7 +5511,6 @@ struct sqlite3_vtab {
/*
** CAPI3REF: Virtual Table Cursor Object
** KEYWORDS: sqlite3_vtab_cursor {virtual table cursor}
-** EXPERIMENTAL
**
** Every [virtual table module] implementation uses a subclass of the
** following structure to describe cursors that point into the
@@ -4917,21 +5532,19 @@ struct sqlite3_vtab_cursor {
/*
** CAPI3REF: Declare The Schema Of A Virtual Table
-** EXPERIMENTAL
**
** ^The [xCreate] and [xConnect] methods of a
** [virtual table module] call this interface
** to declare the format (the names and datatypes of the columns) of
** the virtual tables they implement.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
+SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
/*
** CAPI3REF: Overload A Function For A Virtual Table
-** EXPERIMENTAL
**
** ^(Virtual tables can provide alternative implementations of functions
-** using the [xFindFunction] method of the [virtual table module].
+** using the [xFindFunction] method of the [virtual table module].
** But global versions of those functions
** must exist in order to be overloaded.)^
**
@@ -4943,7 +5556,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_declare_vtab(sqlite3*, const char *zS
** purpose is to be a placeholder function that can be overloaded
** by a [virtual table].
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
+SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
/*
** The interface to the virtual-table mechanism defined above (back up
@@ -4953,8 +5566,6 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_overload_function(sqlite3*, const cha
**
** When the virtual-table mechanism stabilizes, we will declare the
** interface fixed, support it indefinitely, and remove this comment.
-**
-****** EXPERIMENTAL - subject to change without notice **************
*/
/*
@@ -4984,8 +5595,8 @@ typedef struct sqlite3_blob sqlite3_blob;
**
** ^If the flags parameter is non-zero, then the BLOB is opened for read
** and write access. ^If it is zero, the BLOB is opened for read access.
-** ^It is not possible to open a column that is part of an index or primary
-** key for writing. ^If [foreign key constraints] are enabled, it is
+** ^It is not possible to open a column that is part of an index or primary
+** key for writing. ^If [foreign key constraints] are enabled, it is
** not possible to open a column that is part of a [child key] for writing.
**
** ^Note that the database name is not the filename that contains
@@ -5009,7 +5620,7 @@ typedef struct sqlite3_blob sqlite3_blob;
** This is true if any column of the row is changed, even a column
** other than the one the BLOB handle is open on.)^
** ^Calls to [sqlite3_blob_read()] and [sqlite3_blob_write()] for
-** a expired BLOB handle fail with an return code of [SQLITE_ABORT].
+** an expired BLOB handle fail with a return code of [SQLITE_ABORT].
** ^(Changes written into a BLOB prior to the BLOB expiring are not
** rolled back by the expiration of the BLOB. Such changes will eventually
** commit if the transaction continues to completion.)^
@@ -5037,6 +5648,30 @@ SQLITE_API int sqlite3_blob_open(
sqlite3_blob **ppBlob
);
+/*
+** CAPI3REF: Move a BLOB Handle to a New Row
+**
+** ^This function is used to move an existing blob handle so that it points
+** to a different row of the same database table. ^The new row is identified
+** by the rowid value passed as the second argument. Only the row can be
+** changed. ^The database, table and column on which the blob handle is open
+** remain the same. Moving an existing blob handle to a new row can be
+** faster than closing the existing handle and opening a new one.
+**
+** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] -
+** it must exist and there must be either a blob or text value stored in
+** the nominated column.)^ ^If the new row is not present in the table, or if
+** it does not contain a blob or text value, or if another error occurs, an
+** SQLite error code is returned and the blob handle is considered aborted.
+** ^All subsequent calls to [sqlite3_blob_read()], [sqlite3_blob_write()] or
+** [sqlite3_blob_reopen()] on an aborted blob handle immediately return
+** SQLITE_ABORT. ^Calling [sqlite3_blob_bytes()] on an aborted blob handle
+** always returns zero.
+**
+** ^This function sets the database handle error code and message.
+*/
+SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
+
/*
** CAPI3REF: Close A BLOB Handle
**
@@ -5064,7 +5699,7 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
/*
** CAPI3REF: Return The Size Of An Open BLOB
**
-** ^Returns the size in bytes of the BLOB accessible via the
+** ^Returns the size in bytes of the BLOB accessible via the
** successfully opened [BLOB handle] in its only argument. ^The
** incremental blob I/O routines can only read or overwriting existing
** blob content; they cannot change the size of a blob.
@@ -5297,7 +5932,6 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
/*
** CAPI3REF: Mutex Methods Object
-** EXPERIMENTAL
**
** An instance of this structure defines the low-level routines
** used to allocate and use mutexes.
@@ -5314,7 +5948,7 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
**
** ^The xMutexInit method defined by this structure is invoked as
** part of system initialization by the sqlite3_initialize() function.
-** ^The xMutexInit routine is calle by SQLite exactly once for each
+** ^The xMutexInit routine is called by SQLite exactly once for each
** effective call to [sqlite3_initialize()].
**
** ^The xMutexEnd method defined by this structure is invoked as
@@ -5347,7 +5981,7 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
** it is passed a NULL pointer).
**
** The xMutexInit() method must be threadsafe. ^It must be harmless to
-** invoke xMutexInit() mutiple times within the same process and without
+** invoke xMutexInit() multiple times within the same process and without
** intervening calls to xMutexEnd(). Second and subsequent calls to
** xMutexInit() must be no-ops.
**
@@ -5396,7 +6030,7 @@ struct sqlite3_mutex_methods {
**
** ^If the argument to sqlite3_mutex_held() is a NULL pointer then
** the routine should return 1. This seems counter-intuitive since
-** clearly the mutex cannot be held if it does not exist. But the
+** clearly the mutex cannot be held if it does not exist. But
** the reason the mutex does not exist is because the build is not
** using mutexes. And we do not want the assert() containing the
** call to sqlite3_mutex_held() to fail, so a non-zero return is
@@ -5426,12 +6060,13 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */
#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */
#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */
-#define SQLITE_MUTEX_STATIC_LRU2 7 /* lru page list */
+#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
+#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
/*
** CAPI3REF: Retrieve the mutex for a database connection
**
-** ^This interface returns a pointer the [sqlite3_mutex] object that
+** ^This interface returns a pointer the [sqlite3_mutex] object that
** serializes access to the [database connection] given in the argument
** when the [threading mode] is Serialized.
** ^If the [threading mode] is Single-thread or Multi-thread then this
@@ -5445,7 +6080,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
** ^The [sqlite3_file_control()] interface makes a direct call to the
** xFileControl method for the [sqlite3_io_methods] object associated
** with a particular database identified by the second argument. ^The
-** name of the database "main" for the main database or "temp" for the
+** name of the database is "main" for the main database or "temp" for the
** TEMP database, or the name that appears after the AS keyword for
** databases that are added using the [ATTACH] SQL command.
** ^A NULL pointer can be used in place of "main" to refer to the
@@ -5455,6 +6090,12 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
** the xFileControl method. ^The return value of the xFileControl
** method becomes the return value of this routine.
**
+** ^The SQLITE_FCNTL_FILE_POINTER value for the op parameter causes
+** a pointer to the underlying [sqlite3_file] object to be written into
+** the space pointed to by the 4th parameter. ^The SQLITE_FCNTL_FILE_POINTER
+** case is a short-circuit path which does not actually invoke the
+** underlying sqlite3_io_methods.xFileControl method.
+**
** ^If the second parameter (zDbName) does not match the name of any
** open database file, then SQLITE_ERROR is returned. ^This error
** code is not remembered and will not be recalled by [sqlite3_errcode()]
@@ -5510,17 +6151,19 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_RESERVE 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16
-#define SQLITE_TESTCTRL_LAST 16
+#define SQLITE_TESTCTRL_PGHDRSZ 17
+#define SQLITE_TESTCTRL_SCRATCHMALLOC 18
+#define SQLITE_TESTCTRL_LOCALTIME_FAULT 19
+#define SQLITE_TESTCTRL_LAST 19
/*
** CAPI3REF: SQLite Runtime Status
-** EXPERIMENTAL
**
** ^This interface is used to retrieve runtime status information
-** about the preformance of SQLite, and optionally to reset various
+** about the performance of SQLite, and optionally to reset various
** highwater marks. ^The first argument is an integer code for
** the specific parameter to measure. ^(Recognized integer codes
-** are of the form [SQLITE_STATUS_MEMORY_USED | SQLITE_STATUS_...].)^
+** are of the form [status parameters | SQLITE_STATUS_...].)^
** ^The current value of the parameter is returned into *pCurrent.
** ^The highest recorded value is returned in *pHighwater. ^If the
** resetFlag is true, then the highest record value is reset after
@@ -5530,7 +6173,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
** ^(Other parameters record only the highwater mark and not the current
** value. For these latter parameters nothing is written into *pCurrent.)^
**
-** ^The sqlite3_db_status() routine returns SQLITE_OK on success and a
+** ^The sqlite3_status() routine returns SQLITE_OK on success and a
** non-zero [error code] on failure.
**
** This routine is threadsafe but is not atomic. This routine can be
@@ -5542,18 +6185,18 @@ SQLITE_API int sqlite3_test_control(int op, ...);
**
** See also: [sqlite3_db_status()]
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
+SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
/*
** CAPI3REF: Status Parameters
-** EXPERIMENTAL
+** KEYWORDS: {status parameters}
**
** These integer constants designate various run-time status parameters
** that can be returned by [sqlite3_status()].
**
**
-** ^(- SQLITE_STATUS_MEMORY_USED
+** [[SQLITE_STATUS_MEMORY_USED]] ^(- SQLITE_STATUS_MEMORY_USED
** - This parameter is the current amount of memory checked out
** using [sqlite3_malloc()], either directly or indirectly. The
** figure includes calls made to [sqlite3_malloc()] by the application
@@ -5563,35 +6206,40 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_status(int op, int *pCurrent, int *pH
** this parameter. The amount returned is the sum of the allocation
** sizes as reported by the xSize method in [sqlite3_mem_methods].
)^
**
-** ^(- SQLITE_STATUS_MALLOC_SIZE
+** [[SQLITE_STATUS_MALLOC_SIZE]] ^(- SQLITE_STATUS_MALLOC_SIZE
** - This parameter records the largest memory allocation request
** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their
** internal equivalents). Only the value returned in the
-** *pHighwater parameter to [sqlite3_status()] is of interest.
+** *pHighwater parameter to [sqlite3_status()] is of interest.
** The value written into the *pCurrent parameter is undefined.
)^
**
-** ^(- SQLITE_STATUS_PAGECACHE_USED
+** [[SQLITE_STATUS_MALLOC_COUNT]] ^(- SQLITE_STATUS_MALLOC_COUNT
+** - This parameter records the number of separate memory allocations
+** currently checked out.
)^
+**
+** [[SQLITE_STATUS_PAGECACHE_USED]] ^(- SQLITE_STATUS_PAGECACHE_USED
** - This parameter returns the number of pages used out of the
-** [pagecache memory allocator] that was configured using
+** [pagecache memory allocator] that was configured using
** [SQLITE_CONFIG_PAGECACHE]. The
** value returned is in pages, not in bytes.
)^
**
+** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]]
** ^(- SQLITE_STATUS_PAGECACHE_OVERFLOW
** - This parameter returns the number of bytes of page cache
-** allocation which could not be statisfied by the [SQLITE_CONFIG_PAGECACHE]
+** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE]
** buffer and where forced to overflow to [sqlite3_malloc()]. The
** returned value includes allocations that overflowed because they
** where too large (they were larger than the "sz" parameter to
** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because
** no space was left in the page cache.
)^
**
-** ^(- SQLITE_STATUS_PAGECACHE_SIZE
+** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(- SQLITE_STATUS_PAGECACHE_SIZE
** - This parameter records the largest memory allocation request
** handed to [pagecache memory allocator]. Only the value returned in the
-** *pHighwater parameter to [sqlite3_status()] is of interest.
+** *pHighwater parameter to [sqlite3_status()] is of interest.
** The value written into the *pCurrent parameter is undefined.
)^
**
-** ^(- SQLITE_STATUS_SCRATCH_USED
+** [[SQLITE_STATUS_SCRATCH_USED]] ^(- SQLITE_STATUS_SCRATCH_USED
** - This parameter returns the number of allocations used out of the
** [scratch memory allocator] configured using
** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not
@@ -5599,9 +6247,9 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_status(int op, int *pCurrent, int *pH
** outstanding at time, this parameter also reports the number of threads
** using scratch memory at the same time.
)^
**
-** ^(- SQLITE_STATUS_SCRATCH_OVERFLOW
+** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(- SQLITE_STATUS_SCRATCH_OVERFLOW
** - This parameter returns the number of bytes of scratch memory
-** allocation which could not be statisfied by the [SQLITE_CONFIG_SCRATCH]
+** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH]
** buffer and where forced to overflow to [sqlite3_malloc()]. The values
** returned include overflows because the requested allocation was too
** larger (that is, because the requested allocation was larger than the
@@ -5609,13 +6257,13 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_status(int op, int *pCurrent, int *pH
** slots were available.
**
)^
**
-** ^(- SQLITE_STATUS_SCRATCH_SIZE
+** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(- SQLITE_STATUS_SCRATCH_SIZE
** - This parameter records the largest memory allocation request
** handed to [scratch memory allocator]. Only the value returned in the
-** *pHighwater parameter to [sqlite3_status()] is of interest.
+** *pHighwater parameter to [sqlite3_status()] is of interest.
** The value written into the *pCurrent parameter is undefined.
)^
**
-** ^(- SQLITE_STATUS_PARSER_STACK
+** [[SQLITE_STATUS_PARSER_STACK]] ^(- SQLITE_STATUS_PARSER_STACK
** - This parameter records the deepest parser stack. It is only
** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].
)^
**
@@ -5631,30 +6279,35 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_status(int op, int *pCurrent, int *pH
#define SQLITE_STATUS_PARSER_STACK 6
#define SQLITE_STATUS_PAGECACHE_SIZE 7
#define SQLITE_STATUS_SCRATCH_SIZE 8
+#define SQLITE_STATUS_MALLOC_COUNT 9
/*
** CAPI3REF: Database Connection Status
-** EXPERIMENTAL
**
-** ^This interface is used to retrieve runtime status information
+** ^This interface is used to retrieve runtime status information
** about a single [database connection]. ^The first argument is the
** database connection object to be interrogated. ^The second argument
-** is the parameter to interrogate. ^Currently, the only allowed value
-** for the second parameter is [SQLITE_DBSTATUS_LOOKASIDE_USED].
-** Additional options will likely appear in future releases of SQLite.
+** is an integer constant, taken from the set of
+** [SQLITE_DBSTATUS options], that
+** determines the parameter to interrogate. The set of
+** [SQLITE_DBSTATUS options] is likely
+** to grow in future releases of SQLite.
**
** ^The current value of the requested parameter is written into *pCur
** and the highest instantaneous value is written into *pHiwtr. ^If
** the resetFlg is true, then the highest instantaneous value is
** reset back down to the current value.
**
+** ^The sqlite3_db_status() routine returns SQLITE_OK on success and a
+** non-zero [error code] on failure.
+**
** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
+SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
/*
** CAPI3REF: Status Parameters for database connections
-** EXPERIMENTAL
+** KEYWORDS: {SQLITE_DBSTATUS options}
**
** These constants are the available integer "verbs" that can be passed as
** the second argument to the [sqlite3_db_status()] interface.
@@ -5666,31 +6319,79 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_db_status(sqlite3*, int op, int *pCur
** if a discontinued or unsupported verb is invoked.
**
**
-** ^(- SQLITE_DBSTATUS_LOOKASIDE_USED
+** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(- SQLITE_DBSTATUS_LOOKASIDE_USED
** - This parameter returns the number of lookaside memory slots currently
** checked out.
)^
+**
+** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(- SQLITE_DBSTATUS_LOOKASIDE_HIT
+** - This parameter returns the number malloc attempts that were
+** satisfied using lookaside memory. Only the high-water value is meaningful;
+** the current value is always zero.)^
+**
+** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]]
+** ^(
- SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE
+** - This parameter returns the number malloc attempts that might have
+** been satisfied using lookaside memory but failed due to the amount of
+** memory requested being larger than the lookaside slot size.
+** Only the high-water value is meaningful;
+** the current value is always zero.)^
+**
+** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]]
+** ^(
- SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL
+** - This parameter returns the number malloc attempts that might have
+** been satisfied using lookaside memory but failed due to all lookaside
+** memory already being in use.
+** Only the high-water value is meaningful;
+** the current value is always zero.)^
+**
+** [[SQLITE_DBSTATUS_CACHE_USED]] ^(
- SQLITE_DBSTATUS_CACHE_USED
+** - This parameter returns the approximate number of of bytes of heap
+** memory used by all pager caches associated with the database connection.)^
+** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
+**
+** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(
- SQLITE_DBSTATUS_SCHEMA_USED
+** - This parameter returns the approximate number of of bytes of heap
+** memory used to store the schema for all databases associated
+** with the connection - main, temp, and any [ATTACH]-ed databases.)^
+** ^The full amount of memory used by the schemas is reported, even if the
+** schema memory is shared with other database connections due to
+** [shared cache mode] being enabled.
+** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0.
+**
+** [[SQLITE_DBSTATUS_STMT_USED]] ^(
- SQLITE_DBSTATUS_STMT_USED
+** - This parameter returns the approximate number of of bytes of heap
+** and lookaside memory used by all prepared statements associated with
+** the database connection.)^
+** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0.
+**
**
*/
-#define SQLITE_DBSTATUS_LOOKASIDE_USED 0
+#define SQLITE_DBSTATUS_LOOKASIDE_USED 0
+#define SQLITE_DBSTATUS_CACHE_USED 1
+#define SQLITE_DBSTATUS_SCHEMA_USED 2
+#define SQLITE_DBSTATUS_STMT_USED 3
+#define SQLITE_DBSTATUS_LOOKASIDE_HIT 4
+#define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5
+#define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6
+#define SQLITE_DBSTATUS_MAX 6 /* Largest defined DBSTATUS */
/*
** CAPI3REF: Prepared Statement Status
-** EXPERIMENTAL
**
** ^(Each prepared statement maintains various
-** [SQLITE_STMTSTATUS_SORT | counters] that measure the number
+** [SQLITE_STMTSTATUS counters] that measure the number
** of times it has performed specific operations.)^ These counters can
** be used to monitor the performance characteristics of the prepared
** statements. For example, if the number of table steps greatly exceeds
** the number of table searches or result rows, that would tend to indicate
** that the prepared statement is using a full table scan rather than
-** an index.
+** an index.
**
** ^(This interface is used to retrieve and reset counter values from
** a [prepared statement]. The first argument is the prepared statement
** object to be interrogated. The second argument
-** is an integer code for a specific [SQLITE_STMTSTATUS_SORT | counter]
+** is an integer code for a specific [SQLITE_STMTSTATUS counter]
** to be interrogated.)^
** ^The current value of the requested counter is returned.
** ^If the resetFlg is true, then the counter is reset to zero after this
@@ -5698,36 +6399,43 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_db_status(sqlite3*, int op, int *pCur
**
** See also: [sqlite3_status()] and [sqlite3_db_status()].
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
+SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
/*
** CAPI3REF: Status Parameters for prepared statements
-** EXPERIMENTAL
+** KEYWORDS: {SQLITE_STMTSTATUS counter} {SQLITE_STMTSTATUS counters}
**
** These preprocessor macros define integer codes that name counter
** values associated with the [sqlite3_stmt_status()] interface.
** The meanings of the various counters are as follows:
**
**
-** - SQLITE_STMTSTATUS_FULLSCAN_STEP
+** [[SQLITE_STMTSTATUS_FULLSCAN_STEP]] - SQLITE_STMTSTATUS_FULLSCAN_STEP
** - ^This is the number of times that SQLite has stepped forward in
** a table as part of a full table scan. Large numbers for this counter
-** may indicate opportunities for performance improvement through
+** may indicate opportunities for performance improvement through
** careful use of indices.
**
-** - SQLITE_STMTSTATUS_SORT
+** [[SQLITE_STMTSTATUS_SORT]] - SQLITE_STMTSTATUS_SORT
** - ^This is the number of sort operations that have occurred.
** A non-zero value in this counter may indicate an opportunity to
** improvement performance through careful use of indices.
**
+** [[SQLITE_STMTSTATUS_AUTOINDEX]] - SQLITE_STMTSTATUS_AUTOINDEX
+** - ^This is the number of rows inserted into transient indices that
+** were created automatically in order to help joins run faster.
+** A non-zero value in this counter may indicate an opportunity to
+** improvement performance by adding permanent indices that do not
+** need to be reinitialized each time the statement is run.
+**
**
*/
#define SQLITE_STMTSTATUS_FULLSCAN_STEP 1
#define SQLITE_STMTSTATUS_SORT 2
+#define SQLITE_STMTSTATUS_AUTOINDEX 3
/*
** CAPI3REF: Custom Page Cache Object
-** EXPERIMENTAL
**
** The sqlite3_pcache type is opaque. It is implemented by
** the pluggable module. The SQLite core has no knowledge of
@@ -5742,36 +6450,47 @@ typedef struct sqlite3_pcache sqlite3_pcache;
/*
** CAPI3REF: Application Defined Page Cache.
** KEYWORDS: {page cache}
-** EXPERIMENTAL
**
** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE], ...) interface can
-** register an alternative page cache implementation by passing in an
-** instance of the sqlite3_pcache_methods structure.)^ The majority of the
-** heap memory used by SQLite is used by the page cache to cache data read
-** from, or ready to be written to, the database file. By implementing a
-** custom page cache using this API, an application can control more
-** precisely the amount of memory consumed by SQLite, the way in which
-** that memory is allocated and released, and the policies used to
-** determine exactly which parts of a database file are cached and for
+** register an alternative page cache implementation by passing in an
+** instance of the sqlite3_pcache_methods structure.)^
+** In many applications, most of the heap memory allocated by
+** SQLite is used for the page cache.
+** By implementing a
+** custom page cache using this API, an application can better control
+** the amount of memory consumed by SQLite, the way in which
+** that memory is allocated and released, and the policies used to
+** determine exactly which parts of a database file are cached and for
** how long.
**
+** The alternative page cache mechanism is an
+** extreme measure that is only needed by the most demanding applications.
+** The built-in page cache is recommended for most uses.
+**
** ^(The contents of the sqlite3_pcache_methods structure are copied to an
** internal buffer by SQLite within the call to [sqlite3_config]. Hence
** the application may discard the parameter after the call to
** [sqlite3_config()] returns.)^
**
-** ^The xInit() method is called once for each call to [sqlite3_initialize()]
+** [[the xInit() page cache method]]
+** ^(The xInit() method is called once for each effective
+** call to [sqlite3_initialize()])^
** (usually only once during the lifetime of the process). ^(The xInit()
** method is passed a copy of the sqlite3_pcache_methods.pArg value.)^
-** ^The xInit() method can set up up global structures and/or any mutexes
-** required by the custom page cache implementation.
+** The intent of the xInit() method is to set up global data structures
+** required by the custom page cache implementation.
+** ^(If the xInit() method is NULL, then the
+** built-in default page cache is used instead of the application defined
+** page cache.)^
**
-** ^The xShutdown() method is called from within [sqlite3_shutdown()],
-** if the application invokes this API. It can be used to clean up
+** [[the xShutdown() page cache method]]
+** ^The xShutdown() method is called by [sqlite3_shutdown()].
+** It can be used to clean up
** any outstanding resources before process shutdown, if required.
+** ^The xShutdown() method may be NULL.
**
-** ^SQLite holds a [SQLITE_MUTEX_RECURSIVE] mutex when it invokes
-** the xInit method, so the xInit method need not be threadsafe. ^The
+** ^SQLite automatically serializes calls to the xInit method,
+** so the xInit method need not be threadsafe. ^The
** xShutdown method is only called from [sqlite3_shutdown()] so it does
** not need to be threadsafe either. All other methods must be threadsafe
** in multithreaded applications.
@@ -5779,47 +6498,56 @@ typedef struct sqlite3_pcache sqlite3_pcache;
** ^SQLite will never invoke xInit() more than once without an intervening
** call to xShutdown().
**
-** ^The xCreate() method is used to construct a new cache instance. SQLite
-** will typically create one cache instance for each open database file,
+** [[the xCreate() page cache methods]]
+** ^SQLite invokes the xCreate() method to construct a new cache instance.
+** SQLite will typically create one cache instance for each open database file,
** though this is not guaranteed. ^The
** first parameter, szPage, is the size in bytes of the pages that must
** be allocated by the cache. ^szPage will not be a power of two. ^szPage
** will the page size of the database file that is to be cached plus an
-** increment (here called "R") of about 100 or 200. ^SQLite will use the
+** increment (here called "R") of less than 250. SQLite will use the
** extra R bytes on each page to store metadata about the underlying
** database page on disk. The value of R depends
** on the SQLite version, the target platform, and how SQLite was compiled.
-** ^R is constant for a particular build of SQLite. ^The second argument to
+** ^(R is constant for a particular build of SQLite. Except, there are two
+** distinct values of R when SQLite is compiled with the proprietary
+** ZIPVFS extension.)^ ^The second argument to
** xCreate(), bPurgeable, is true if the cache being created will
** be used to cache database pages of a file stored on disk, or
-** false if it is used for an in-memory database. ^The cache implementation
+** false if it is used for an in-memory database. The cache implementation
** does not have to do anything special based with the value of bPurgeable;
** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will
** never invoke xUnpin() except to deliberately delete a page.
-** ^In other words, a cache created with bPurgeable set to false will
+** ^In other words, calls to xUnpin() on a cache with bPurgeable set to
+** false will always have the "discard" flag set to true.
+** ^Hence, a cache created with bPurgeable false will
** never contain any unpinned pages.
**
+** [[the xCachesize() page cache method]]
** ^(The xCachesize() method may be called at any time by SQLite to set the
** suggested maximum cache-size (number of pages stored by) the cache
** instance passed as the first argument. This is the value configured using
-** the SQLite "[PRAGMA cache_size]" command.)^ ^As with the bPurgeable
+** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable
** parameter, the implementation is not required to do anything with this
** value; it is advisory only.
**
-** ^The xPagecount() method should return the number of pages currently
-** stored in the cache.
-**
-** ^The xFetch() method is used to fetch a page and return a pointer to it.
-** ^A 'page', in this context, is a buffer of szPage bytes aligned at an
-** 8-byte boundary. ^The page to be fetched is determined by the key. ^The
-** mimimum key value is 1. After it has been retrieved using xFetch, the page
+** [[the xPagecount() page cache methods]]
+** The xPagecount() method must return the number of pages currently
+** stored in the cache, both pinned and unpinned.
+**
+** [[the xFetch() page cache methods]]
+** The xFetch() method locates a page in the cache and returns a pointer to
+** the page, or a NULL pointer.
+** A "page", in this context, means a buffer of szPage bytes aligned at an
+** 8-byte boundary. The page to be fetched is determined by the key. ^The
+** minimum key value is 1. After it has been retrieved using xFetch, the page
** is considered to be "pinned".
**
-** ^If the requested page is already in the page cache, then the page cache
+** If the requested page is already in the page cache, then the page cache
** implementation must return a pointer to the page buffer with its content
-** intact. ^(If the requested page is not already in the cache, then the
-** behavior of the cache implementation is determined by the value of the
-** createFlag parameter passed to xFetch, according to the following table:
+** intact. If the requested page is not already in the cache, then the
+** cache implementation should use the value of the createFlag
+** parameter to help it determined what action to take:
**
**
** createFlag | Behaviour when page is not already in cache
@@ -5828,39 +6556,41 @@ typedef struct sqlite3_pcache sqlite3_pcache;
** Otherwise return NULL.
** |
---|
2 | Make every effort to allocate a new page. Only return
** NULL if allocating a new page is effectively impossible.
-** |
)^
+**
**
-** SQLite will normally invoke xFetch() with a createFlag of 0 or 1. If
-** a call to xFetch() with createFlag==1 returns NULL, then SQLite will
+** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1. SQLite
+** will only use a createFlag of 2 after a prior call with a createFlag of 1
+** failed.)^ In between the to xFetch() calls, SQLite may
** attempt to unpin one or more cache pages by spilling the content of
-** pinned pages to disk and synching the operating system disk cache. After
-** attempting to unpin pages, the xFetch() method will be invoked again with
-** a createFlag of 2.
+** pinned pages to disk and synching the operating system disk cache.
**
+** [[the xUnpin() page cache method]]
** ^xUnpin() is called by SQLite with a pointer to a currently pinned page
-** as its second argument. ^(If the third parameter, discard, is non-zero,
-** then the page should be evicted from the cache. In this case SQLite
-** assumes that the next time the page is retrieved from the cache using
-** the xFetch() method, it will be zeroed.)^ ^If the discard parameter is
-** zero, then the page is considered to be unpinned. ^The cache implementation
+** as its second argument. If the third parameter, discard, is non-zero,
+** then the page must be evicted from the cache.
+** ^If the discard parameter is
+** zero, then the page may be discarded or retained at the discretion of
+** page cache implementation. ^The page cache implementation
** may choose to evict unpinned pages at any time.
**
-** ^(The cache is not required to perform any reference counting. A single
-** call to xUnpin() unpins the page regardless of the number of prior calls
-** to xFetch().)^
+** The cache must not perform any reference counting. A single
+** call to xUnpin() unpins the page regardless of the number of prior calls
+** to xFetch().
**
-** ^The xRekey() method is used to change the key value associated with the
-** page passed as the second argument from oldKey to newKey. ^If the cache
-** previously contains an entry associated with newKey, it should be
+** [[the xRekey() page cache methods]]
+** The xRekey() method is used to change the key value associated with the
+** page passed as the second argument. If the cache
+** previously contains an entry associated with newKey, it must be
** discarded. ^Any prior cache entry associated with newKey is guaranteed not
** to be pinned.
**
-** ^When SQLite calls the xTruncate() method, the cache must discard all
+** When SQLite calls the xTruncate() method, the cache must discard all
** existing cache entries with page numbers (keys) greater than or equal
-** to the value of the iLimit parameter passed to xTruncate(). ^If any
+** to the value of the iLimit parameter passed to xTruncate(). If any
** of these pages are pinned, they are implicitly unpinned, meaning that
** they can be safely discarded.
**
+** [[the xDestroy() page cache method]]
** ^The xDestroy() method is used to delete a cache allocated by xCreate().
** All resources associated with the specified cache should be freed. ^After
** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*]
@@ -5884,7 +6614,6 @@ struct sqlite3_pcache_methods {
/*
** CAPI3REF: Online Backup Object
-** EXPERIMENTAL
**
** The sqlite3_backup object records state information about an ongoing
** online backup operation. ^The sqlite3_backup object is created by
@@ -5897,50 +6626,50 @@ typedef struct sqlite3_backup sqlite3_backup;
/*
** CAPI3REF: Online Backup API.
-** EXPERIMENTAL
**
** The backup API copies the content of one database into another.
** It is useful either for creating backups of databases or
-** for copying in-memory databases to or from persistent files.
+** for copying in-memory databases to or from persistent files.
**
** See Also: [Using the SQLite Online Backup API]
**
-** ^Exclusive access is required to the destination database for the
-** duration of the operation. ^However the source database is only
-** read-locked while it is actually being read; it is not locked
-** continuously for the entire backup operation. ^Thus, the backup may be
-** performed on a live source database without preventing other users from
+** ^SQLite holds a write transaction open on the destination database file
+** for the duration of the backup operation.
+** ^The source database is read-locked only while it is being read;
+** it is not locked continuously for the entire backup operation.
+** ^Thus, the backup may be performed on a live source database without
+** preventing other database connections from
** reading or writing to the source database while the backup is underway.
-**
-** ^(To perform a backup operation:
+**
+** ^(To perform a backup operation:
**
** - sqlite3_backup_init() is called once to initialize the
-** backup,
-**
- sqlite3_backup_step() is called one or more times to transfer
+** backup,
+**
- sqlite3_backup_step() is called one or more times to transfer
** the data between the two databases, and finally
-**
- sqlite3_backup_finish() is called to release all resources
-** associated with the backup operation.
+**
- sqlite3_backup_finish() is called to release all resources
+** associated with the backup operation.
**
)^
** There should be exactly one call to sqlite3_backup_finish() for each
** successful call to sqlite3_backup_init().
**
-** sqlite3_backup_init()
+** [[sqlite3_backup_init()]] sqlite3_backup_init()
**
-** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the
-** [database connection] associated with the destination database
+** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the
+** [database connection] associated with the destination database
** and the database name, respectively.
** ^The database name is "main" for the main database, "temp" for the
** temporary database, or the name specified after the AS keyword in
** an [ATTACH] statement for an attached database.
-** ^The S and M arguments passed to
+** ^The S and M arguments passed to
** sqlite3_backup_init(D,N,S,M) identify the [database connection]
** and database name of the source database, respectively.
** ^The source and destination [database connections] (parameters S and D)
-** must be different or else sqlite3_backup_init(D,N,S,M) will file with
+** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
** an error.
**
** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is
-** returned and an error code and error message are store3d in the
+** returned and an error code and error message are stored in the
** destination [database connection] D.
** ^The error code and message for the failed call to sqlite3_backup_init()
** can be retrieved using the [sqlite3_errcode()], [sqlite3_errmsg()], and/or
@@ -5948,16 +6677,16 @@ typedef struct sqlite3_backup sqlite3_backup;
** ^A successful call to sqlite3_backup_init() returns a pointer to an
** [sqlite3_backup] object.
** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and
-** sqlite3_backup_finish() functions to perform the specified backup
+** sqlite3_backup_finish() functions to perform the specified backup
** operation.
**
-** sqlite3_backup_step()
+** [[sqlite3_backup_step()]] sqlite3_backup_step()
**
-** ^Function sqlite3_backup_step(B,N) will copy up to N pages between
+** ^Function sqlite3_backup_step(B,N) will copy up to N pages between
** the source and destination databases specified by [sqlite3_backup] object B.
-** ^If N is negative, all remaining source pages are copied.
+** ^If N is negative, all remaining source pages are copied.
** ^If sqlite3_backup_step(B,N) successfully copies N pages and there
-** are still more pages to be copied, then the function resturns [SQLITE_OK].
+** are still more pages to be copied, then the function returns [SQLITE_OK].
** ^If sqlite3_backup_step(B,N) successfully finishes copying all pages
** from source to destination, then it returns [SQLITE_DONE].
** ^If an error occurs while running sqlite3_backup_step(B,N),
@@ -5966,15 +6695,19 @@ typedef struct sqlite3_backup sqlite3_backup;
** [SQLITE_NOMEM], [SQLITE_BUSY], [SQLITE_LOCKED], or an
** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX] extended error code.
**
-** ^The sqlite3_backup_step() might return [SQLITE_READONLY] if the destination
-** database was opened read-only or if
-** the destination is an in-memory database with a different page size
-** from the source database.
+** ^(The sqlite3_backup_step() might return [SQLITE_READONLY] if
+**
+** - the destination database was opened read-only, or
+**
- the destination database is using write-ahead-log journaling
+** and the destination and source page sizes differ, or
+**
- the destination database is an in-memory database and the
+** destination and source page sizes differ.
+**
)^
**
** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then
** the [sqlite3_busy_handler | busy-handler function]
-** is invoked (if one is specified). ^If the
-** busy-handler returns non-zero before the lock is available, then
+** is invoked (if one is specified). ^If the
+** busy-handler returns non-zero before the lock is available, then
** [SQLITE_BUSY] is returned to the caller. ^In this case the call to
** sqlite3_backup_step() can be retried later. ^If the source
** [database connection]
@@ -5982,15 +6715,15 @@ typedef struct sqlite3_backup sqlite3_backup;
** is called, then [SQLITE_LOCKED] is returned immediately. ^Again, in this
** case the call to sqlite3_backup_step() can be retried later on. ^(If
** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX], [SQLITE_NOMEM], or
-** [SQLITE_READONLY] is returned, then
-** there is no point in retrying the call to sqlite3_backup_step(). These
-** errors are considered fatal.)^ The application must accept
-** that the backup operation has failed and pass the backup operation handle
+** [SQLITE_READONLY] is returned, then
+** there is no point in retrying the call to sqlite3_backup_step(). These
+** errors are considered fatal.)^ The application must accept
+** that the backup operation has failed and pass the backup operation handle
** to the sqlite3_backup_finish() to release associated resources.
**
** ^The first call to sqlite3_backup_step() obtains an exclusive lock
-** on the destination file. ^The exclusive lock is not released until either
-** sqlite3_backup_finish() is called or the backup operation is complete
+** on the destination file. ^The exclusive lock is not released until either
+** sqlite3_backup_finish() is called or the backup operation is complete
** and sqlite3_backup_step() returns [SQLITE_DONE]. ^Every call to
** sqlite3_backup_step() obtains a [shared lock] on the source database that
** lasts for the duration of the sqlite3_backup_step() call.
@@ -5999,18 +6732,18 @@ typedef struct sqlite3_backup sqlite3_backup;
** through the backup process. ^If the source database is modified by an
** external process or via a database connection other than the one being
** used by the backup operation, then the backup will be automatically
-** restarted by the next call to sqlite3_backup_step(). ^If the source
+** restarted by the next call to sqlite3_backup_step(). ^If the source
** database is modified by the using the same database connection as is used
** by the backup operation, then the backup database is automatically
** updated at the same time.
**
-** sqlite3_backup_finish()
+** [[sqlite3_backup_finish()]] sqlite3_backup_finish()
**
-** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the
+** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the
** application wishes to abandon the backup operation, the application
** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish().
** ^The sqlite3_backup_finish() interfaces releases all
-** resources associated with the [sqlite3_backup] object.
+** resources associated with the [sqlite3_backup] object.
** ^If sqlite3_backup_step() has not yet returned [SQLITE_DONE], then any
** active write-transaction on the destination database is rolled back.
** The [sqlite3_backup] object is invalid
@@ -6027,11 +6760,12 @@ typedef struct sqlite3_backup sqlite3_backup;
** is not a permanent error and does not affect the return value of
** sqlite3_backup_finish().
**
-** sqlite3_backup_remaining(), sqlite3_backup_pagecount()
+** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]]
+** sqlite3_backup_remaining() and sqlite3_backup_pagecount()
**
** ^Each call to sqlite3_backup_step() sets two values inside
** the [sqlite3_backup] object: the number of pages still to be backed
-** up and the total number of pages in the source databae file.
+** up and the total number of pages in the source database file.
** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces
** retrieve these two values, respectively.
**
@@ -6049,8 +6783,8 @@ typedef struct sqlite3_backup sqlite3_backup;
** connections, then the source database connection may be used concurrently
** from within other threads.
**
-** However, the application must guarantee that the destination
-** [database connection] is not passed to any other API (by any thread) after
+** However, the application must guarantee that the destination
+** [database connection] is not passed to any other API (by any thread) after
** sqlite3_backup_init() is called and before the corresponding call to
** sqlite3_backup_finish(). SQLite does not currently check to see
** if the application incorrectly accesses the destination [database connection]
@@ -6061,11 +6795,11 @@ typedef struct sqlite3_backup sqlite3_backup;
** If running in [shared cache mode], the application must
** guarantee that the shared cache used by the destination database
** is not accessed while the backup is running. In practice this means
-** that the application must guarantee that the disk file being
+** that the application must guarantee that the disk file being
** backed up to is not accessed by any connection within the process,
** not just the specific connection that was passed to sqlite3_backup_init().
**
-** The [sqlite3_backup] object itself is partially threadsafe. Multiple
+** The [sqlite3_backup] object itself is partially threadsafe. Multiple
** threads may safely make multiple concurrent calls to sqlite3_backup_step().
** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount()
** APIs are not strictly speaking threadsafe. If they are invoked at the
@@ -6085,13 +6819,12 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
/*
** CAPI3REF: Unlock Notification
-** EXPERIMENTAL
**
** ^When running in shared-cache mode, a database operation may fail with
** an [SQLITE_LOCKED] error if the required locks on the shared-cache or
** individual tables within the shared-cache cannot be obtained. See
-** [SQLite Shared-Cache Mode] for a description of shared-cache locking.
-** ^This API may be used to register a callback that SQLite will invoke
+** [SQLite Shared-Cache Mode] for a description of shared-cache locking.
+** ^This API may be used to register a callback that SQLite will invoke
** when the connection currently holding the required lock relinquishes it.
** ^This API is only available if the library was compiled with the
** [SQLITE_ENABLE_UNLOCK_NOTIFY] C-preprocessor symbol defined.
@@ -6099,14 +6832,14 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
** See Also: [Using the SQLite Unlock Notification Feature].
**
** ^Shared-cache locks are released when a database connection concludes
-** its current transaction, either by committing it or rolling it back.
+** its current transaction, either by committing it or rolling it back.
**
** ^When a connection (known as the blocked connection) fails to obtain a
** shared-cache lock and SQLITE_LOCKED is returned to the caller, the
** identity of the database connection (the blocking connection) that
-** has locked the required resource is stored internally. ^After an
+** has locked the required resource is stored internally. ^After an
** application receives an SQLITE_LOCKED error, it may call the
-** sqlite3_unlock_notify() method with the blocked connection handle as
+** sqlite3_unlock_notify() method with the blocked connection handle as
** the first argument to register for a callback that will be invoked
** when the blocking connections current transaction is concluded. ^The
** callback is invoked from within the [sqlite3_step] or [sqlite3_close]
@@ -6120,15 +6853,15 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
**
** ^If the blocked connection is attempting to obtain a write-lock on a
** shared-cache table, and more than one other connection currently holds
-** a read-lock on the same table, then SQLite arbitrarily selects one of
+** a read-lock on the same table, then SQLite arbitrarily selects one of
** the other connections to use as the blocking connection.
**
-** ^(There may be at most one unlock-notify callback registered by a
+** ^(There may be at most one unlock-notify callback registered by a
** blocked connection. If sqlite3_unlock_notify() is called when the
** blocked connection already has a registered unlock-notify callback,
** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is
** called with a NULL pointer as its second argument, then any existing
-** unlock-notify callback is cancelled. ^The blocked connections
+** unlock-notify callback is canceled. ^The blocked connections
** unlock-notify callback may also be canceled by closing the blocked
** connection using [sqlite3_close()].
**
@@ -6141,7 +6874,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
**
** Callback Invocation Details
**
-** When an unlock-notify callback is registered, the application provides a
+** When an unlock-notify callback is registered, the application provides a
** single void* pointer that is passed to the callback when it is invoked.
** However, the signature of the callback function allows SQLite to pass
** it an array of void* context pointers. The first argument passed to
@@ -6154,12 +6887,12 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
** same callback function, then instead of invoking the callback function
** multiple times, it is invoked once with the set of void* context pointers
** specified by the blocked connections bundled together into an array.
-** This gives the application an opportunity to prioritize any actions
+** This gives the application an opportunity to prioritize any actions
** related to the set of unblocked database connections.
**
** Deadlock Detection
**
-** Assuming that after registering for an unlock-notify callback a
+** Assuming that after registering for an unlock-notify callback a
** database waits for the callback to be issued before taking any further
** action (a reasonable assumption), then using this API may cause the
** application to deadlock. For example, if connection X is waiting for
@@ -6182,7 +6915,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
**
** The "DROP TABLE" Exception
**
-** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost
+** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost
** always appropriate to call sqlite3_unlock_notify(). There is however,
** one exception. When executing a "DROP TABLE" or "DROP INDEX" statement,
** SQLite checks if there are any currently executing SELECT statements
@@ -6195,7 +6928,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
** One way around this problem is to check the extended error code returned
** by an sqlite3_step() call. ^(If there is a blocking connection, then the
** extended error code is set to SQLITE_LOCKED_SHAREDCACHE. Otherwise, in
-** the special "DROP TABLE/INDEX" case, the extended error code is just
+** the special "DROP TABLE/INDEX" case, the extended error code is just
** SQLITE_LOCKED.)^
*/
SQLITE_API int sqlite3_unlock_notify(
@@ -6207,23 +6940,21 @@ SQLITE_API int sqlite3_unlock_notify(
/*
** CAPI3REF: String Comparison
-** EXPERIMENTAL
**
** ^The [sqlite3_strnicmp()] API allows applications and extensions to
** compare the contents of two buffers containing UTF-8 strings in a
-** case-indendent fashion, using the same definition of case independence
+** case-independent fashion, using the same definition of case independence
** that SQLite uses internally when comparing identifiers.
*/
SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
/*
** CAPI3REF: Error Logging Interface
-** EXPERIMENTAL
**
** ^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
-** passed through to [sqlite3_vmprintf()] to generate the final output string.
+** used with [sqlite3_snprintf()] to generate the final output string.
**
** The sqlite3_log() interface is intended for use by extensions such as
** virtual tables, collating functions, and SQL functions. While there is
@@ -6240,6 +6971,270 @@ SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
*/
SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
+/*
+** CAPI3REF: Write-Ahead Log Commit Hook
+**
+** ^The [sqlite3_wal_hook()] function is used to register a callback that
+** will be invoked each time a database connection commits data to a
+** [write-ahead log] (i.e. whenever a transaction is committed in
+** [journal_mode | journal_mode=WAL mode]).
+**
+** ^The callback is invoked by SQLite after the commit has taken place and
+** the associated write-lock on the database released, so the implementation
+** may read, write or [checkpoint] the database as required.
+**
+** ^The first parameter passed to the callback function when it is invoked
+** is a copy of the third parameter passed to sqlite3_wal_hook() when
+** registering the callback. ^The second is a copy of the database handle.
+** ^The third parameter is the name of the database that was written to -
+** either "main" or the name of an [ATTACH]-ed database. ^The fourth parameter
+** is the number of pages currently in the write-ahead log file,
+** including those that were just committed.
+**
+** The callback function should normally return [SQLITE_OK]. ^If an error
+** code is returned, that error will propagate back up through the
+** SQLite code base to cause the statement that provoked the callback
+** to report an error, though the commit will have still occurred. If the
+** callback returns [SQLITE_ROW] or [SQLITE_DONE], or if it returns a value
+** that does not correspond to any valid SQLite error code, the results
+** are undefined.
+**
+** A single database handle may have at most a single write-ahead log callback
+** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any
+** previously registered write-ahead log callback. ^Note that the
+** [sqlite3_wal_autocheckpoint()] interface and the
+** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
+** those overwrite any prior [sqlite3_wal_hook()] settings.
+*/
+SQLITE_API void *sqlite3_wal_hook(
+ sqlite3*,
+ int(*)(void *,sqlite3*,const char*,int),
+ void*
+);
+
+/*
+** CAPI3REF: Configure an auto-checkpoint
+**
+** ^The [sqlite3_wal_autocheckpoint(D,N)] is a wrapper around
+** [sqlite3_wal_hook()] that causes any database on [database connection] D
+** to automatically [checkpoint]
+** after committing a transaction if there are N or
+** more frames in the [write-ahead log] file. ^Passing zero or
+** a negative value as the nFrame parameter disables automatic
+** checkpoints entirely.
+**
+** ^The callback registered by this function replaces any existing callback
+** registered using [sqlite3_wal_hook()]. ^Likewise, registering a callback
+** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism
+** configured by this function.
+**
+** ^The [wal_autocheckpoint pragma] can be used to invoke this interface
+** from SQL.
+**
+** ^Every new [database connection] defaults to having the auto-checkpoint
+** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT]
+** pages. The use of this interface
+** is only necessary if the default setting is found to be suboptimal
+** for a particular application.
+*/
+SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
+
+/*
+** CAPI3REF: Checkpoint a database
+**
+** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X
+** on [database connection] D to be [checkpointed]. ^If X is NULL or an
+** empty string, then a checkpoint is run on all databases of
+** connection D. ^If the database connection D is not in
+** [WAL | write-ahead log mode] then this interface is a harmless no-op.
+**
+** ^The [wal_checkpoint pragma] can be used to invoke this interface
+** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the
+** [wal_autocheckpoint pragma] can be used to cause this interface to be
+** run whenever the WAL reaches a certain size threshold.
+**
+** See also: [sqlite3_wal_checkpoint_v2()]
+*/
+SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
+
+/*
+** CAPI3REF: Checkpoint a database
+**
+** Run a checkpoint operation on WAL database zDb attached to database
+** handle db. The specific operation is determined by the value of the
+** eMode parameter:
+**
+**
+** - SQLITE_CHECKPOINT_PASSIVE
-
+** Checkpoint as many frames as possible without waiting for any database
+** readers or writers to finish. Sync the db file if all frames in the log
+** are checkpointed. This mode is the same as calling
+** sqlite3_wal_checkpoint(). The busy-handler callback is never invoked.
+**
+**
- SQLITE_CHECKPOINT_FULL
-
+** This mode blocks (calls the busy-handler callback) until there is no
+** database writer and all readers are reading from the most recent database
+** snapshot. It then checkpoints all frames in the log file and syncs the
+** database file. This call blocks database writers while it is running,
+** but not database readers.
+**
+**
- SQLITE_CHECKPOINT_RESTART
-
+** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after
+** checkpointing the log file it blocks (calls the busy-handler callback)
+** until all readers are reading from the database file only. This ensures
+** that the next client to write to the database file restarts the log file
+** from the beginning. This call blocks database writers while it is running,
+** but not database readers.
+**
+**
+** If pnLog is not NULL, then *pnLog is set to the total number of frames in
+** the log file before returning. If pnCkpt is not NULL, then *pnCkpt is set to
+** the total number of checkpointed frames (including any that were already
+** checkpointed when this function is called). *pnLog and *pnCkpt may be
+** populated even if sqlite3_wal_checkpoint_v2() returns other than SQLITE_OK.
+** If no values are available because of an error, they are both set to -1
+** before returning to communicate this to the caller.
+**
+** All calls obtain an exclusive "checkpoint" lock on the database file. If
+** any other process is running a checkpoint operation at the same time, the
+** lock cannot be obtained and SQLITE_BUSY is returned. Even if there is a
+** busy-handler configured, it will not be invoked in this case.
+**
+** The SQLITE_CHECKPOINT_FULL and RESTART modes also obtain the exclusive
+** "writer" lock on the database file. If the writer lock cannot be obtained
+** immediately, and a busy-handler is configured, it is invoked and the writer
+** lock retried until either the busy-handler returns 0 or the lock is
+** successfully obtained. The busy-handler is also invoked while waiting for
+** database readers as described above. If the busy-handler returns 0 before
+** the writer lock is obtained or while waiting for database readers, the
+** checkpoint operation proceeds from that point in the same way as
+** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible
+** without blocking any further. SQLITE_BUSY is returned in this case.
+**
+** If parameter zDb is NULL or points to a zero length string, then the
+** specified operation is attempted on all WAL databases. In this case the
+** values written to output parameters *pnLog and *pnCkpt are undefined. If
+** an SQLITE_BUSY error is encountered when processing one or more of the
+** attached WAL databases, the operation is still attempted on any remaining
+** attached databases and SQLITE_BUSY is returned to the caller. If any other
+** error occurs while processing an attached database, processing is abandoned
+** and the error code returned to the caller immediately. If no error
+** (SQLITE_BUSY or otherwise) is encountered while processing the attached
+** databases, SQLITE_OK is returned.
+**
+** If database zDb is the name of an attached database that is not in WAL
+** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. If
+** zDb is not NULL (or a zero length string) and is not the name of any
+** attached database, SQLITE_ERROR is returned to the caller.
+*/
+SQLITE_API int sqlite3_wal_checkpoint_v2(
+ sqlite3 *db, /* Database handle */
+ const char *zDb, /* Name of attached database (or NULL) */
+ int eMode, /* SQLITE_CHECKPOINT_* value */
+ int *pnLog, /* OUT: Size of WAL log in frames */
+ int *pnCkpt /* OUT: Total number of frames checkpointed */
+);
+
+/*
+** CAPI3REF: Checkpoint operation parameters
+**
+** These constants can be used as the 3rd parameter to
+** [sqlite3_wal_checkpoint_v2()]. See the [sqlite3_wal_checkpoint_v2()]
+** documentation for additional information about the meaning and use of
+** each of these values.
+*/
+#define SQLITE_CHECKPOINT_PASSIVE 0
+#define SQLITE_CHECKPOINT_FULL 1
+#define SQLITE_CHECKPOINT_RESTART 2
+
+/*
+** CAPI3REF: Virtual Table Interface Configuration
+**
+** This function may be called by either the [xConnect] or [xCreate] method
+** of a [virtual table] implementation to configure
+** various facets of the virtual table interface.
+**
+** If this interface is invoked outside the context of an xConnect or
+** xCreate virtual table method then the behavior is undefined.
+**
+** At present, there is only one option that may be configured using
+** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options
+** may be added in the future.
+*/
+SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
+
+/*
+** CAPI3REF: Virtual Table Configuration Options
+**
+** These macros define the various options to the
+** [sqlite3_vtab_config()] interface that [virtual table] implementations
+** can use to customize and optimize their behavior.
+**
+**
+** - SQLITE_VTAB_CONSTRAINT_SUPPORT
+**
- Calls of the form
+** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported,
+** where X is an integer. If X is zero, then the [virtual table] whose
+** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not
+** support constraints. In this configuration (which is the default) if
+** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire
+** statement is rolled back as if [ON CONFLICT | OR ABORT] had been
+** specified as part of the users SQL statement, regardless of the actual
+** ON CONFLICT mode specified.
+**
+** If X is non-zero, then the virtual table implementation guarantees
+** that if [xUpdate] returns [SQLITE_CONSTRAINT], it will do so before
+** any modifications to internal or persistent data structures have been made.
+** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite
+** is able to roll back a statement or database transaction, and abandon
+** or continue processing the current SQL statement as appropriate.
+** If the ON CONFLICT mode is REPLACE and the [xUpdate] method returns
+** [SQLITE_CONSTRAINT], SQLite handles this as if the ON CONFLICT mode
+** had been ABORT.
+**
+** Virtual table implementations that are required to handle OR REPLACE
+** must do so within the [xUpdate] method. If a call to the
+** [sqlite3_vtab_on_conflict()] function indicates that the current ON
+** CONFLICT policy is REPLACE, the virtual table implementation should
+** silently replace the appropriate rows within the xUpdate callback and
+** return SQLITE_OK. Or, if this is not possible, it may return
+** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT
+** constraint handling.
+**
+*/
+#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
+
+/*
+** CAPI3REF: Determine The Virtual Table Conflict Policy
+**
+** This function may only be called from within a call to the [xUpdate] method
+** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The
+** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL],
+** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode
+** of the SQL statement that triggered the call to the [xUpdate] method of the
+** [virtual table].
+*/
+SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
+
+/*
+** CAPI3REF: Conflict resolution modes
+**
+** These constants are returned by [sqlite3_vtab_on_conflict()] to
+** inform a [virtual table] implementation what the [ON CONFLICT] mode
+** is for the SQL statement being evaluated.
+**
+** Note that the [SQLITE_IGNORE] constant is also used as a potential
+** return value from the [sqlite3_set_authorizer()] callback and that
+** [SQLITE_ABORT] is also a [result code].
+*/
+#define SQLITE_ROLLBACK 1
+/* #define SQLITE_IGNORE 2 // Also used by sqlite3_authorizer() callback */
+#define SQLITE_FAIL 3
+/* #define SQLITE_ABORT 4 // Also an error code */
+#define SQLITE_REPLACE 5
+
+
+
/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
@@ -6253,6 +7248,62 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
#endif
#endif
+/*
+** 2010 August 30
+**
+** 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.
+**
+*************************************************************************
+*/
+
+#ifndef _SQLITE3RTREE_H_
+#define _SQLITE3RTREE_H_
+
+
+#if 0
+extern "C" {
+#endif
+
+typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry;
+
+/*
+** Register a geometry callback named zGeom that can be used as part of an
+** R-Tree geometry query as follows:
+**
+** SELECT ... FROM WHERE MATCH $zGeom(... params ...)
+*/
+SQLITE_API int sqlite3_rtree_geometry_callback(
+ sqlite3 *db,
+ const char *zGeom,
+ int (*xGeom)(sqlite3_rtree_geometry *, int nCoord, double *aCoord, int *pRes),
+ void *pContext
+);
+
+
+/*
+** A pointer to a structure of the following type is passed as the first
+** argument to callbacks registered using rtree_geometry_callback().
+*/
+struct sqlite3_rtree_geometry {
+ void *pContext; /* Copy of pContext passed to s_r_g_c() */
+ int nParam; /* Size of array aParam[] */
+ double *aParam; /* Parameters passed to SQL geom function */
+ void *pUser; /* Callback implementation user data */
+ void (*xDelUser)(void *); /* Called by SQLite to clean up pUser */
+};
+
+
+#if 0
+} /* end of the 'extern "C"' block */
+#endif
+
+#endif /* ifndef _SQLITE3RTREE_H_ */
+
/************** End of sqlite3.h *********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
@@ -6295,7 +7346,7 @@ typedef struct HashElem HashElem;
** element pointed to plus the next _ht.count-1 elements in the list.
**
** Hash.htsize and Hash.ht may be zero. In that case lookup is done
-** by a linear search of the global list. For small tables, the
+** by a linear search of the global list. For small tables, the
** Hash.ht table is never allocated because if there are few elements
** in the table, it is faster to do a linear search than to manage
** the hash table.
@@ -6310,7 +7361,7 @@ struct Hash {
} *ht;
};
-/* Each element in the hash table is an instance of the following
+/* Each element in the hash table is an instance of the following
** structure. All elements are stored on a single doubly-linked list.
**
** Again, this structure is intended to be opaque, but it can't really
@@ -6531,6 +7582,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
*/
#ifdef SQLITE_OMIT_FLOATING_POINT
# define double sqlite_int64
+# define float sqlite_int64
# define LONGDOUBLE_TYPE sqlite_int64
# ifndef SQLITE_BIG_DBL
# define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50)
@@ -6546,7 +7598,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
/*
** OMIT_TEMPDB is set to 1 if SQLITE_OMIT_TEMPDB is defined, or 0
-** afterward. Having this macro allows us to cause the C compiler
+** afterward. Having this macro allows us to cause the C compiler
** to omit code used by TEMP tables without messy #ifndef statements.
*/
#ifdef SQLITE_OMIT_TEMPDB
@@ -6689,7 +7741,7 @@ SQLITE_PRIVATE const int sqlite3one;
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
-/*
+/*
** Round up a number to the next larger multiple of 8. This is used
** to force 8-byte alignment on 64-bit architectures.
*/
@@ -6718,7 +7770,7 @@ SQLITE_PRIVATE const int sqlite3one;
/*
** An instance of the following structure is used to store the busy-handler
-** callback for a given sqlite handle.
+** callback for a given sqlite handle.
**
** The sqlite.busyHandler member of the sqlite struct contains the busy
** callback for the database handle. Each pager opened via the sqlite
@@ -6783,16 +7835,16 @@ struct BusyHandler {
SQLITE_API int sqlite3_wsd_init(int N, int J);
SQLITE_API void *sqlite3_wsd_find(void *K, int L);
#else
- #define SQLITE_WSD
+ #define SQLITE_WSD
#define GLOBAL(t,v) v
#define sqlite3GlobalConfig sqlite3Config
#endif
/*
** The following macros are used to suppress compiler warnings and to
-** make it clear to human readers when a function parameter is deliberately
+** make it clear to human readers when a function parameter is deliberately
** left unused within the body of a function. This usually happens when
-** a function is called via a function pointer. For example the
+** a function is called via a function pointer. For example the
** implementation of an SQL aggregate step callback may not use the
** parameter indicating the number of arguments passed to the aggregate,
** if it knows that this is enforced elsewhere.
@@ -6822,6 +7874,7 @@ typedef struct Expr Expr;
typedef struct ExprList ExprList;
typedef struct ExprSpan ExprSpan;
typedef struct FKey FKey;
+typedef struct FuncDestructor FuncDestructor;
typedef struct FuncDef FuncDef;
typedef struct FuncDefHash FuncDefHash;
typedef struct IdList IdList;
@@ -6847,13 +7900,14 @@ typedef struct TriggerPrg TriggerPrg;
typedef struct TriggerStep TriggerStep;
typedef struct UnpackedRecord UnpackedRecord;
typedef struct VTable VTable;
+typedef struct VtabCtx VtabCtx;
typedef struct Walker Walker;
typedef struct WherePlan WherePlan;
typedef struct WhereInfo WhereInfo;
typedef struct WhereLevel WhereLevel;
/*
-** Defer sourcing vdbe.h and btree.h until after the "u8" and
+** Defer sourcing vdbe.h and btree.h until after the "u8" and
** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque
** pointer types (i.e. FuncDef) defined above.
*/
@@ -6900,21 +7954,10 @@ typedef struct WhereLevel WhereLevel;
typedef struct Btree Btree;
typedef struct BtCursor BtCursor;
typedef struct BtShared BtShared;
-typedef struct BtreeMutexArray BtreeMutexArray;
-
-/*
-** This structure records all of the Btrees that need to hold
-** a mutex before we enter sqlite3VdbeExec(). The Btrees are
-** are placed in aBtree[] in order of aBtree[]->pBt. That way,
-** we can always lock and unlock them all quickly.
-*/
-struct BtreeMutexArray {
- int nMutex;
- Btree *aBtree[SQLITE_MAX_ATTACHED+1];
-};
SQLITE_PRIVATE int sqlite3BtreeOpen(
+ sqlite3_vfs *pVfs, /* VFS to use with this b-tree */
const char *zFilename, /* Name of database file to open */
sqlite3 *db, /* Associated database connection */
Btree **ppBtree, /* Return open Btree* here */
@@ -6928,27 +7971,27 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
** NOTE: These values must match the corresponding PAGER_ values in
** pager.h.
*/
-#define BTREE_OMIT_JOURNAL 1 /* Do not use journal. No argument */
+#define BTREE_OMIT_JOURNAL 1 /* Do not create or use a rollback journal */
#define BTREE_NO_READLOCK 2 /* Omit readlocks on readonly files */
-#define BTREE_MEMORY 4 /* In-memory DB. No argument */
-#define BTREE_READONLY 8 /* Open the database in read-only mode */
-#define BTREE_READWRITE 16 /* Open for both reading and writing */
-#define BTREE_CREATE 32 /* Create the database if it does not exist */
+#define BTREE_MEMORY 4 /* This is an in-memory DB */
+#define BTREE_SINGLE 8 /* The file contains at most 1 b-tree */
+#define BTREE_UNORDERED 16 /* Use of a hash implementation is OK */
SQLITE_PRIVATE int sqlite3BtreeClose(Btree*);
SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int);
-SQLITE_PRIVATE int sqlite3BtreeSetSafetyLevel(Btree*,int,int);
+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);
SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int);
+SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree*);
SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree*,int);
SQLITE_PRIVATE int sqlite3BtreeGetReserve(Btree*);
SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int);
SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *);
SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int);
SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
-SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*);
+SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int);
SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*);
SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*);
SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree*,int);
@@ -6968,11 +8011,17 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *, Btree *);
SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *);
/* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR
-** of the following flags:
+** of the flags shown below.
+**
+** Every SQLite table must have either BTREE_INTKEY or BTREE_BLOBKEY set.
+** With BTREE_INTKEY, the table key is a 64-bit integer and arbitrary data
+** is stored in the leaves. (BTREE_INTKEY is used for SQL tables.) With
+** BTREE_BLOBKEY, the key is an arbitrary BLOB and no content is stored
+** anywhere - the key is the content. (BTREE_BLOBKEY is used for SQL
+** indices.)
*/
#define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */
-#define BTREE_ZERODATA 2 /* Table has keys only - no data */
-#define BTREE_LEAFDATA 4 /* Data stored in leaves only. Implies INTKEY */
+#define BTREE_BLOBKEY 2 /* Table has keys only - no data */
SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*);
SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*);
@@ -6983,7 +8032,7 @@ SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
/*
** The second parameter to sqlite3BtreeGetMeta or sqlite3BtreeUpdateMeta
-** should be one of the following values. The integer values are assigned
+** should be one of the following values. The integer values are assigned
** to constants so that the offset of the corresponding field in an
** SQLite database header may be found using the following formula:
**
@@ -7046,6 +8095,8 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
SQLITE_PRIVATE void sqlite3BtreeCacheOverflow(BtCursor *);
SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *);
+SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
+
#ifndef NDEBUG
SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*);
#endif
@@ -7059,6 +8110,10 @@ SQLITE_PRIVATE int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
SQLITE_PRIVATE void sqlite3BtreeCursorList(Btree*);
#endif
+#ifndef SQLITE_OMIT_WAL
+SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*, int, int *, int *);
+#endif
+
/*
** If we are not using shared cache, then there is no need to
** use mutexes to access the BtShared structures. So make the
@@ -7068,35 +8123,33 @@ SQLITE_PRIVATE void sqlite3BtreeCursorList(Btree*);
SQLITE_PRIVATE void sqlite3BtreeEnter(Btree*);
SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3*);
#else
-# define sqlite3BtreeEnter(X)
+# define sqlite3BtreeEnter(X)
# define sqlite3BtreeEnterAll(X)
#endif
#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE
+SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*);
SQLITE_PRIVATE void sqlite3BtreeLeave(Btree*);
SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*);
SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor*);
SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3*);
-SQLITE_PRIVATE void sqlite3BtreeMutexArrayEnter(BtreeMutexArray*);
-SQLITE_PRIVATE void sqlite3BtreeMutexArrayLeave(BtreeMutexArray*);
-SQLITE_PRIVATE void sqlite3BtreeMutexArrayInsert(BtreeMutexArray*, Btree*);
#ifndef NDEBUG
/* These routines are used inside assert() statements only. */
SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree*);
SQLITE_PRIVATE int sqlite3BtreeHoldsAllMutexes(sqlite3*);
+SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*);
#endif
#else
+# define sqlite3BtreeSharable(X) 0
# define sqlite3BtreeLeave(X)
# define sqlite3BtreeEnterCursor(X)
# define sqlite3BtreeLeaveCursor(X)
# define sqlite3BtreeLeaveAll(X)
-# define sqlite3BtreeMutexArrayEnter(X)
-# define sqlite3BtreeMutexArrayLeave(X)
-# define sqlite3BtreeMutexArrayInsert(X,Y)
# define sqlite3BtreeHoldsMutex(X) 1
# define sqlite3BtreeHoldsAllMutexes(X) 1
+# define sqlite3SchemaMutexHeld(X,Y,Z) 1
#endif
@@ -7125,6 +8178,7 @@ SQLITE_PRIVATE int sqlite3BtreeHoldsAllMutexes(sqlite3*);
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
+/* #include */
/*
** A single VDBE is an opaque structure named "Vdbe". Only routines
@@ -7168,6 +8222,7 @@ struct VdbeOp {
KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */
int *ai; /* Used when p4type is P4_INTARRAY */
SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */
+ int (*xAdvance)(BtCursor *, int *);
} p4;
#ifdef SQLITE_DEBUG
char *zComment; /* Comment to improve readability */
@@ -7188,8 +8243,8 @@ struct SubProgram {
int nOp; /* Elements in aOp[] */
int nMem; /* Number of memory cells required */
int nCsr; /* Number of cursors required */
- int nRef; /* Number of pointers to this structure */
void *token; /* id that may be used to recursive triggers */
+ SubProgram *pNext; /* Next sub-program already visited */
};
/*
@@ -7215,7 +8270,7 @@ typedef struct VdbeOpList VdbeOpList;
#define P4_KEYINFO (-6) /* P4 is a pointer to a KeyInfo structure */
#define P4_VDBEFUNC (-7) /* P4 is a pointer to a VdbeFunc structure */
#define P4_MEM (-8) /* P4 is a pointer to a Mem* structure */
-#define P4_TRANSIENT (-9) /* P4 is a pointer to a transient string */
+#define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */
#define P4_VTAB (-10) /* P4 is a pointer to an sqlite3_vtab structure */
#define P4_MPRINTF (-11) /* P4 is a string obtained from sqlite3_mprintf() */
#define P4_REAL (-12) /* P4 is a 64-bit floating point value */
@@ -7223,6 +8278,7 @@ typedef struct VdbeOpList VdbeOpList;
#define P4_INT32 (-14) /* P4 is a 32-bit signed integer */
#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
#define P4_SUBPROGRAM (-18) /* P4 is a pointer to a SubProgram structure */
+#define P4_ADVANCE (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */
/* When adding a P4 argument using P4_KEYINFO, a copy of the KeyInfo structure
** is made. That copy is freed when the Vdbe is finalized. But if the
@@ -7235,7 +8291,7 @@ typedef struct VdbeOpList VdbeOpList;
#define P4_KEYINFO_STATIC (-17)
/*
-** The Vdbe.aColName array contains 5n Mem structures, where n is the
+** The Vdbe.aColName array contains 5n Mem structures, where n is the
** number of columns of data returned by the statement.
*/
#define COLNAME_NAME 0
@@ -7255,7 +8311,7 @@ typedef struct VdbeOpList VdbeOpList;
/*
** The following macro converts a relative address in the p2 field
-** of a VdbeOp structure into a negative number so that
+** of a VdbeOp structure into a negative number so that
** sqlite3VdbeAddOpList() knows that the address is relative. Calling
** the macro again restores the address.
*/
@@ -7320,102 +8376,105 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_Or 68 /* same as TK_OR */
#define OP_Not 19 /* same as TK_NOT */
#define OP_BitNot 93 /* same as TK_BITNOT */
-#define OP_If 26
-#define OP_IfNot 27
+#define OP_Once 26
+#define OP_If 27
+#define OP_IfNot 28
#define OP_IsNull 73 /* same as TK_ISNULL */
#define OP_NotNull 74 /* same as TK_NOTNULL */
-#define OP_Column 28
-#define OP_Affinity 29
-#define OP_MakeRecord 30
-#define OP_Count 31
-#define OP_Savepoint 32
-#define OP_AutoCommit 33
-#define OP_Transaction 34
-#define OP_ReadCookie 35
-#define OP_SetCookie 36
-#define OP_VerifyCookie 37
-#define OP_OpenRead 38
-#define OP_OpenWrite 39
-#define OP_OpenEphemeral 40
-#define OP_OpenPseudo 41
-#define OP_Close 42
-#define OP_SeekLt 43
-#define OP_SeekLe 44
-#define OP_SeekGe 45
-#define OP_SeekGt 46
-#define OP_Seek 47
-#define OP_NotFound 48
-#define OP_Found 49
-#define OP_IsUnique 50
-#define OP_NotExists 51
-#define OP_Sequence 52
-#define OP_NewRowid 53
-#define OP_Insert 54
-#define OP_InsertInt 55
-#define OP_Delete 56
-#define OP_ResetCount 57
-#define OP_RowKey 58
-#define OP_RowData 59
-#define OP_Rowid 60
-#define OP_NullRow 61
-#define OP_Last 62
-#define OP_Sort 63
-#define OP_Rewind 64
-#define OP_Prev 65
-#define OP_Next 66
-#define OP_IdxInsert 67
-#define OP_IdxDelete 70
-#define OP_IdxRowid 71
-#define OP_IdxLT 72
-#define OP_IdxGE 81
-#define OP_Destroy 92
-#define OP_Clear 95
-#define OP_CreateIndex 96
-#define OP_CreateTable 97
-#define OP_ParseSchema 98
-#define OP_LoadAnalysis 99
-#define OP_DropTable 100
-#define OP_DropIndex 101
-#define OP_DropTrigger 102
-#define OP_IntegrityCk 103
-#define OP_RowSetAdd 104
-#define OP_RowSetRead 105
-#define OP_RowSetTest 106
-#define OP_Program 107
-#define OP_Param 108
-#define OP_FkCounter 109
-#define OP_FkIfZero 110
-#define OP_MemMax 111
-#define OP_IfPos 112
-#define OP_IfNeg 113
-#define OP_IfZero 114
-#define OP_AggStep 115
-#define OP_AggFinal 116
-#define OP_Vacuum 117
-#define OP_IncrVacuum 118
-#define OP_Expire 119
-#define OP_TableLock 120
-#define OP_VBegin 121
-#define OP_VCreate 122
-#define OP_VDestroy 123
-#define OP_VOpen 124
-#define OP_VFilter 125
-#define OP_VColumn 126
-#define OP_VNext 127
-#define OP_VRename 128
-#define OP_VUpdate 129
-#define OP_Pagecount 131
-#define OP_Trace 132
-#define OP_Noop 133
-#define OP_Explain 134
-
-/* The following opcode values are never used */
-#define OP_NotUsed_135 135
-#define OP_NotUsed_136 136
-#define OP_NotUsed_137 137
-#define OP_NotUsed_138 138
-#define OP_NotUsed_139 139
-#define OP_NotUsed_140 140
+#define OP_Column 29
+#define OP_Affinity 30
+#define OP_MakeRecord 31
+#define OP_Count 32
+#define OP_Savepoint 33
+#define OP_AutoCommit 34
+#define OP_Transaction 35
+#define OP_ReadCookie 36
+#define OP_SetCookie 37
+#define OP_VerifyCookie 38
+#define OP_OpenRead 39
+#define OP_OpenWrite 40
+#define OP_OpenAutoindex 41
+#define OP_OpenEphemeral 42
+#define OP_SorterOpen 43
+#define OP_OpenPseudo 44
+#define OP_Close 45
+#define OP_SeekLt 46
+#define OP_SeekLe 47
+#define OP_SeekGe 48
+#define OP_SeekGt 49
+#define OP_Seek 50
+#define OP_NotFound 51
+#define OP_Found 52
+#define OP_IsUnique 53
+#define OP_NotExists 54
+#define OP_Sequence 55
+#define OP_NewRowid 56
+#define OP_Insert 57
+#define OP_InsertInt 58
+#define OP_Delete 59
+#define OP_ResetCount 60
+#define OP_SorterCompare 61
+#define OP_SorterData 62
+#define OP_RowKey 63
+#define OP_RowData 64
+#define OP_Rowid 65
+#define OP_NullRow 66
+#define OP_Last 67
+#define OP_SorterSort 70
+#define OP_Sort 71
+#define OP_Rewind 72
+#define OP_SorterNext 81
+#define OP_Prev 92
+#define OP_Next 95
+#define OP_SorterInsert 96
+#define OP_IdxInsert 97
+#define OP_IdxDelete 98
+#define OP_IdxRowid 99
+#define OP_IdxLT 100
+#define OP_IdxGE 101
+#define OP_Destroy 102
+#define OP_Clear 103
+#define OP_CreateIndex 104
+#define OP_CreateTable 105
+#define OP_ParseSchema 106
+#define OP_LoadAnalysis 107
+#define OP_DropTable 108
+#define OP_DropIndex 109
+#define OP_DropTrigger 110
+#define OP_IntegrityCk 111
+#define OP_RowSetAdd 112
+#define OP_RowSetRead 113
+#define OP_RowSetTest 114
+#define OP_Program 115
+#define OP_Param 116
+#define OP_FkCounter 117
+#define OP_FkIfZero 118
+#define OP_MemMax 119
+#define OP_IfPos 120
+#define OP_IfNeg 121
+#define OP_IfZero 122
+#define OP_AggStep 123
+#define OP_AggFinal 124
+#define OP_Checkpoint 125
+#define OP_JournalMode 126
+#define OP_Vacuum 127
+#define OP_IncrVacuum 128
+#define OP_Expire 129
+#define OP_TableLock 131
+#define OP_VBegin 132
+#define OP_VCreate 133
+#define OP_VDestroy 134
+#define OP_VOpen 135
+#define OP_VFilter 136
+#define OP_VColumn 137
+#define OP_VNext 138
+#define OP_VRename 139
+#define OP_VUpdate 140
+#define OP_Pagecount 146
+#define OP_MaxPgcnt 147
+#define OP_Trace 148
+#define OP_Noop 149
+#define OP_Explain 150
/* Properties such as "out2" or "jump" that are specified in
@@ -7431,24 +8490,24 @@ typedef struct VdbeOpList VdbeOpList;
#define OPFLG_OUT3 0x0040 /* out3: P3 is an output */
#define OPFLG_INITIALIZER {\
/* 0 */ 0x00, 0x01, 0x05, 0x04, 0x04, 0x10, 0x00, 0x02,\
-/* 8 */ 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x24, 0x24,\
+/* 8 */ 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x24, 0x24,\
/* 16 */ 0x00, 0x00, 0x00, 0x24, 0x04, 0x05, 0x04, 0x00,\
-/* 24 */ 0x00, 0x01, 0x05, 0x05, 0x00, 0x00, 0x00, 0x02,\
-/* 32 */ 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00,\
-/* 40 */ 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x08,\
-/* 48 */ 0x11, 0x11, 0x11, 0x11, 0x02, 0x02, 0x00, 0x00,\
-/* 56 */ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x01,\
-/* 64 */ 0x01, 0x01, 0x01, 0x08, 0x4c, 0x4c, 0x00, 0x02,\
+/* 24 */ 0x00, 0x01, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00,\
+/* 32 */ 0x02, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,\
+/* 40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11,\
+/* 48 */ 0x11, 0x11, 0x08, 0x11, 0x11, 0x11, 0x11, 0x02,\
+/* 56 */ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 64 */ 0x00, 0x02, 0x00, 0x01, 0x4c, 0x4c, 0x01, 0x01,\
/* 72 */ 0x01, 0x05, 0x05, 0x15, 0x15, 0x15, 0x15, 0x15,\
/* 80 */ 0x15, 0x01, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c,\
-/* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x02, 0x24, 0x02, 0x00,\
-/* 96 */ 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 104 */ 0x0c, 0x45, 0x15, 0x01, 0x02, 0x00, 0x01, 0x08,\
-/* 112 */ 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,\
-/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,\
-/* 128 */ 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,\
-/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04,\
-/* 144 */ 0x04, 0x04,}
+/* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x01, 0x24, 0x02, 0x01,\
+/* 96 */ 0x08, 0x08, 0x00, 0x02, 0x01, 0x01, 0x02, 0x00,\
+/* 104 */ 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 112 */ 0x0c, 0x45, 0x15, 0x01, 0x02, 0x00, 0x01, 0x08,\
+/* 120 */ 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00,\
+/* 128 */ 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 136 */ 0x01, 0x00, 0x01, 0x00, 0x00, 0x04, 0x04, 0x04,\
+/* 144 */ 0x04, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00,}
/************** End of opcodes.h *********************************************/
/************** Continuing where we left off in vdbe.h ***********************/
@@ -7465,19 +8524,21 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
-SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
-SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
-SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3);
+SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
+SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1);
+SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2);
+SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3);
SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u8 P5);
SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr);
-SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N);
+SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe*, int addr);
SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N);
SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int);
SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*);
-SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int,int);
+SQLITE_PRIVATE void sqlite3VdbeDeleteObject(sqlite3*,Vdbe*);
+SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,Parse*);
SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe*, int);
SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe*);
@@ -7486,6 +8547,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *, int);
SQLITE_PRIVATE void sqlite3VdbeTrace(Vdbe*,FILE*);
#endif
SQLITE_PRIVATE void sqlite3VdbeResetStepResult(Vdbe*);
+SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe*);
SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe*,int);
SQLITE_PRIVATE int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*));
@@ -7494,16 +8556,19 @@ SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int);
SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe*,Vdbe*);
SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*);
-SQLITE_PRIVATE void sqlite3VdbeProgramDelete(sqlite3 *, SubProgram *, int);
SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetValue(Vdbe*, int, u8);
SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe*, int);
#ifndef SQLITE_OMIT_TRACE
SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*);
#endif
-SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,char*,int);
-SQLITE_PRIVATE void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord*);
+SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*);
SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);
+SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **);
+
+#ifndef SQLITE_OMIT_TRIGGER
+SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
+#endif
#ifndef NDEBUG
@@ -7542,8 +8607,8 @@ SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
#define _PAGER_H_
/*
-** Default maximum size for persistent journal files. A negative
-** value means no limit. This value may be overridden using the
+** Default maximum size for persistent journal files. A negative
+** value means no limit. This value may be overridden using the
** sqlite3PagerJournalSizeLimit() API. See also "PRAGMA journal_size_limit".
*/
#ifndef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
@@ -7569,9 +8634,9 @@ typedef struct PgHdr DbPage;
/*
** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is
** reserved for working around a windows/posix incompatibility). It is
-** used in the journal to signify that the remainder of the journal file
+** used in the journal to signify that the remainder of the journal file
** is devoted to storing a master journal name - there are no more pages to
-** roll back. See comments for function writeMasterJournal() in pager.c
+** roll back. See comments for function writeMasterJournal() in pager.c
** for details.
*/
#define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1))
@@ -7583,6 +8648,7 @@ typedef struct PgHdr DbPage;
*/
#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
#define PAGER_NO_READLOCK 0x0002 /* Omit readlocks on readonly files */
+#define PAGER_MEMORY 0x0004 /* In-memory database */
/*
** Valid values for the second argument to sqlite3PagerLockingMode().
@@ -7592,22 +8658,23 @@ typedef struct PgHdr DbPage;
#define PAGER_LOCKINGMODE_EXCLUSIVE 1
/*
-** Valid values for the second argument to sqlite3PagerJournalMode().
+** Numeric constants that encode the journalmode.
*/
-#define PAGER_JOURNALMODE_QUERY -1
+#define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */
#define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */
#define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */
#define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */
#define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */
#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
+#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
/*
** The remainder of this file contains the declarations of the functions
-** that make up the Pager sub-system API. See source code comments for
+** that make up the Pager sub-system API. See source code comments for
** a detailed description of each routine.
*/
-/* Open and close a Pager connection. */
+/* Open and close a Pager connection. */
SQLITE_PRIVATE int sqlite3PagerOpen(
sqlite3_vfs*,
Pager **ppPager,
@@ -7622,16 +8689,18 @@ SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
/* Functions used to configure a Pager object. */
SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
-SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u16*, int);
+SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);
SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int);
SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
-SQLITE_PRIVATE void sqlite3PagerSetSafetyLevel(Pager*,int,int);
+SQLITE_PRIVATE void sqlite3PagerSetSafetyLevel(Pager*,int,int,int);
SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int);
-SQLITE_PRIVATE int sqlite3PagerJournalMode(Pager *, int);
+SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int);
+SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*);
+SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager*);
SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager*);
-/* Functions used to obtain and release page references. */
+/* Functions used to obtain and release page references. */
SQLITE_PRIVATE int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
#define sqlite3PagerGet(A,B,C) sqlite3PagerAcquire(A,B,C,0)
SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
@@ -7643,13 +8712,14 @@ SQLITE_PRIVATE int sqlite3PagerWrite(DbPage*);
SQLITE_PRIVATE void sqlite3PagerDontWrite(DbPage*);
SQLITE_PRIVATE int sqlite3PagerMovepage(Pager*,DbPage*,Pgno,int);
SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage*);
-SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *);
-SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *);
+SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *);
+SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *);
/* Functions used to manage pager transactions and savepoints. */
-SQLITE_PRIVATE int sqlite3PagerPagecount(Pager*, int*);
+SQLITE_PRIVATE void sqlite3PagerPagecount(Pager*, int*);
SQLITE_PRIVATE int sqlite3PagerBegin(Pager*, int exFlag, int);
SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, int);
+SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager*);
SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager);
SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager*);
SQLITE_PRIVATE int sqlite3PagerRollback(Pager*);
@@ -7657,9 +8727,16 @@ 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);
+
/* Functions used to query pager state and configuration. */
SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
+SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*);
SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager*);
SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
@@ -7671,6 +8748,10 @@ SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
/* Functions used to truncate the database file. */
SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL)
+SQLITE_PRIVATE void *sqlite3PagerCodec(DbPage *);
+#endif
+
/* Functions to support testing and debugging. */
#if !defined(NDEBUG) || defined(SQLITE_TEST)
SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*);
@@ -7704,7 +8785,7 @@ SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*);
**
*************************************************************************
** This header file defines the interface that the sqlite page cache
-** subsystem.
+** subsystem.
*/
#ifndef _PCACHE_H_
@@ -7777,7 +8858,7 @@ SQLITE_PRIVATE void sqlite3PcacheSetPageSize(PCache *, int);
SQLITE_PRIVATE int sqlite3PcacheSize(void);
/* One release per successful fetch. Page is pinned until released.
-** Reference counted.
+** Reference counted.
*/
SQLITE_PRIVATE int sqlite3PcacheFetch(PCache*, Pgno, int createFlag, PgHdr**);
SQLITE_PRIVATE void sqlite3PcacheRelease(PgHdr*);
@@ -7818,7 +8899,7 @@ SQLITE_PRIVATE int sqlite3PcachePagecount(PCache*);
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
/* Iterate through all dirty pages currently stored in the cache. This
-** interface is only available if SQLITE_CHECK_PAGES is defined when the
+** interface is only available if SQLITE_CHECK_PAGES is defined when the
** library is built.
*/
SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *));
@@ -7878,8 +8959,8 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
/*
** Figure out if we are dealing with Unix, Windows, or some other
** operating system. After the following block of preprocess macros,
-** all of SQLITE_OS_UNIX, SQLITE_OS_WIN, SQLITE_OS_OS2, and SQLITE_OS_OTHER
-** will defined to either 1 or 0. One of the four will be 1. The other
+** all of SQLITE_OS_UNIX, SQLITE_OS_WIN, SQLITE_OS_OS2, and SQLITE_OS_OTHER
+** will defined to either 1 or 0. One of the four will be 1. The other
** three will be 0.
*/
#if defined(SQLITE_OS_OTHER)
@@ -7981,10 +9062,10 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
** 2006-10-31: The default prefix used to be "sqlite_". But then
** Mcafee started using SQLite in their anti-virus product and it
** started putting files with the "sqlite" name in the c:/temp folder.
-** This annoyed many windows users. Those users would then do a
+** This annoyed many windows users. Those users would then do a
** Google search for "sqlite", find the telephone numbers of the
** developers and call to wake them up at night and complain.
-** For this reason, the default name prefix is changed to be "sqlite"
+** For this reason, the default name prefix is changed to be "sqlite"
** spelled backwards. So the temp files are still identified, but
** anybody smart enough to figure out the code is also likely smart
** enough to know that calling the developer will not help get rid
@@ -8025,9 +9106,9 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
** UnlockFile().
**
** LockFile() prevents not just writing but also reading by other processes.
-** A SHARED_LOCK is obtained by locking a single randomly-chosen
-** byte out of a specific range of bytes. The lock byte is obtained at
-** random so two separate readers can probably access the file at the
+** A SHARED_LOCK is obtained by locking a single randomly-chosen
+** byte out of a specific range of bytes. The lock byte is obtained at
+** random so two separate readers can probably access the file at the
** same time, unless they are unlucky and choose the same lock byte.
** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range.
** There can only be one writer. A RESERVED_LOCK is obtained by locking
@@ -8046,7 +9127,7 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
** The following #defines specify the range of bytes used for locking.
** SHARED_SIZE is the number of bytes available in the pool from which
** a random byte is selected for a shared lock. The pool of bytes for
-** shared locks begins at SHARED_FIRST.
+** shared locks begins at SHARED_FIRST.
**
** The same locking strategy and
** byte ranges are used for Unix. This leaves open the possiblity of having
@@ -8062,7 +9143,7 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
** that all locks will fit on a single page even at the minimum page size.
** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE
** is set high so that we don't have to allocate an unused page except
-** for very large databases. But one should test the page skipping logic
+** for very large databases. But one should test the page skipping logic
** by setting PENDING_BYTE low and running the entire regression suite.
**
** Changing the value of PENDING_BYTE results in a subtly incompatible
@@ -8072,7 +9153,11 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
** 1GB boundary.
**
*/
-#define PENDING_BYTE sqlite3PendingByte
+#ifdef SQLITE_OMIT_WSD
+# define PENDING_BYTE (0x40000000)
+#else
+# define PENDING_BYTE sqlite3PendingByte
+#endif
#define RESERVED_BYTE (PENDING_BYTE+1)
#define SHARED_FIRST (PENDING_BYTE+2)
#define SHARED_SIZE 510
@@ -8082,8 +9167,8 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
*/
SQLITE_PRIVATE int sqlite3OsInit(void);
-/*
-** Functions for accessing sqlite3_file methods
+/*
+** Functions for accessing sqlite3_file methods
*/
SQLITE_PRIVATE int sqlite3OsClose(sqlite3_file*);
SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
@@ -8098,9 +9183,13 @@ SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file*,int,void*);
#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id);
SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
+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);
-/*
-** Functions for accessing sqlite3_vfs methods
+/*
+** Functions for accessing sqlite3_vfs methods
*/
SQLITE_PRIVATE int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *);
SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *, const char *, int);
@@ -8114,10 +9203,10 @@ SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *, void *);
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *, int);
-SQLITE_PRIVATE int sqlite3OsCurrentTime(sqlite3_vfs *, double*);
+SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
/*
-** Convenience functions for opening and closing files using
+** Convenience functions for opening and closing files using
** sqlite3_malloc() to obtain space for the file-handle structure.
*/
SQLITE_PRIVATE int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*);
@@ -8194,8 +9283,8 @@ SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *);
#define sqlite3_mutex_enter(X)
#define sqlite3_mutex_try(X) SQLITE_OK
#define sqlite3_mutex_leave(X)
-#define sqlite3_mutex_held(X) 1
-#define sqlite3_mutex_notheld(X) 1
+#define sqlite3_mutex_held(X) ((void)(X),1)
+#define sqlite3_mutex_notheld(X) ((void)(X),1)
#define sqlite3MutexAlloc(X) ((sqlite3_mutex*)8)
#define sqlite3MutexInit() SQLITE_OK
#define sqlite3MutexEnd()
@@ -8223,16 +9312,23 @@ struct Db {
/*
** An instance of the following structure stores a database schema.
**
-** If there are no virtual tables configured in this schema, the
-** Schema.db variable is set to NULL. After the first virtual table
-** has been added, it is set to point to the database connection
-** used to create the connection. Once a virtual table has been
-** added to the Schema structure and the Schema.db variable populated,
-** only that database connection may use the Schema to prepare
-** statements.
+** Most Schema objects are associated with a Btree. The exception is
+** the Schema for the TEMP databaes (sqlite3.aDb[1]) which is free-standing.
+** In shared cache mode, a single Schema object can be shared by multiple
+** Btrees that refer to the same underlying BtShared object.
+**
+** Schema objects are automatically deallocated when the last Btree that
+** references them is destroyed. The TEMP Schema is manually freed by
+** sqlite3_close().
+*
+** A thread must be holding a mutex on the corresponding Btree in order
+** to access Schema content. This implies that the thread must also be
+** holding a mutex on the sqlite3 connection pointer that owns the Btree.
+** For a TEMP Schema, only the connection mutex is required.
*/
struct Schema {
int schema_cookie; /* Database schema version number for this file */
+ int iGeneration; /* Generation counter. Incremented with each change */
Hash tblHash; /* All tables indexed by name */
Hash idxHash; /* All (named) indices indexed by name */
Hash trigHash; /* All triggers indexed by name */
@@ -8242,13 +9338,10 @@ struct Schema {
u8 enc; /* Text encoding used by this database */
u16 flags; /* Flags associated with this schema */
int cache_size; /* Number of pages to use in the cache */
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- sqlite3 *db; /* "Owner" connection. See comment above */
-#endif
};
/*
-** These macros can be used to test, set, or clear bits in the
+** These macros can be used to test, set, or clear bits in the
** Db.pSchema->flags field.
*/
#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))==(P))
@@ -8302,6 +9395,7 @@ struct Lookaside {
u8 bMalloced; /* True if pStart obtained from sqlite3_malloc() */
int nOut; /* Number of buffers currently checked out */
int mxOut; /* Highwater mark for nOut */
+ int anStat[3]; /* 0: hits. 1: size misses. 2: full misses */
LookasideSlot *pFree; /* List of available buffers */
void *pStart; /* First byte of available memory space */
void *pEnd; /* First byte past end of available space */
@@ -8351,16 +9445,16 @@ struct sqlite3 {
int nDb; /* Number of backends currently in use */
Db *aDb; /* All backends */
int flags; /* Miscellaneous flags. See below */
- int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
+ unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
int errCode; /* Most recent error code (SQLITE_*) */
int errMask; /* & result codes with this before returning */
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 */
u8 dfltLockMode; /* Default locking-mode for attached dbs */
- u8 dfltJournalMode; /* Default journal mode for attached dbs */
signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */
u8 suppressErr; /* Do not issue error messages if true */
+ u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */
int nextPagesize; /* Pagesize after VACUUM if >0 */
int nTable; /* Number of tables in the database */
CollSeq *pDfltColl; /* The default collating sequence (BINARY) */
@@ -8381,16 +9475,21 @@ struct sqlite3 {
struct Vdbe *pVdbe; /* List of active virtual machines */
int activeVdbeCnt; /* Number of VDBEs currently executing */
int writeVdbeCnt; /* Number of active VDBEs that are writing */
+ int vdbeExecCnt; /* Number of nested calls to VdbeExec() */
void (*xTrace)(void*,const char*); /* Trace function */
void *pTraceArg; /* Argument to the trace function */
void (*xProfile)(void*,const char*,u64); /* Profiling function */
void *pProfileArg; /* Argument to profile function */
- void *pCommitArg; /* Argument to xCommitCallback() */
+ void *pCommitArg; /* Argument to xCommitCallback() */
int (*xCommitCallback)(void*); /* Invoked at every commit. */
- void *pRollbackArg; /* Argument to xRollbackCallback() */
+ void *pRollbackArg; /* Argument to xRollbackCallback() */
void (*xRollbackCallback)(void*); /* Invoked at every commit. */
void *pUpdateArg;
void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64);
+#ifndef SQLITE_OMIT_WAL
+ int (*xWalCallback)(void *, sqlite3 *, const char *, int);
+ void *pWalArg;
+#endif
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*);
void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*);
void *pCollNeededArg;
@@ -8414,7 +9513,7 @@ struct sqlite3 {
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
Hash aModule; /* populated by sqlite3_create_module() */
- Table *pVTab; /* vtab with active Connect/Create method */
+ VtabCtx *pVtabCtx; /* Context for active vtab connect/create */
VTable **aVTrans; /* Virtual tables with open transactions */
int nVTrans; /* Allocated size of aVTrans */
VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */
@@ -8429,10 +9528,11 @@ struct sqlite3 {
int nStatement; /* Number of nested statement-transactions */
u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */
i64 nDeferredCons; /* Net deferred constraints this transaction. */
+ int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
- /* The following variables are all protected by the STATIC_MASTER
- ** mutex, not by sqlite3.mutex. They are used by code in notify.c.
+ /* The following variables are all protected by the STATIC_MASTER
+ ** mutex, not by sqlite3.mutex. They are used by code in notify.c.
**
** When X.pUnlockConnection==Y, that means that X is waiting for Y to
** unlock so that it can proceed.
@@ -8469,17 +9569,21 @@ struct sqlite3 {
#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 */
-#define SQLITE_NoReadlock 0x00020000 /* Readlocks are omitted when
+#define SQLITE_NoReadlock 0x00020000 /* Readlocks are omitted when
** accessing read-only databases */
#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_LoadExtension 0x00400000 /* Enable load_extension */
+#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
@@ -8491,7 +9595,11 @@ struct sqlite3 {
#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_OptMask 0x1f /* Mask of all disablable opts */
+#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 */
/*
** Possible values for the sqlite.magic field.
@@ -8521,6 +9629,27 @@ struct FuncDef {
void (*xFinalize)(sqlite3_context*); /* Aggregate finalizer */
char *zName; /* SQL name of the function. */
FuncDef *pHash; /* Next with a different name but the same hash */
+ FuncDestructor *pDestructor; /* Reference counted destructor function */
+};
+
+/*
+** This structure encapsulates a user-function destructor callback (as
+** configured using create_function_v2()) and a reference counter. When
+** create_function_v2() is called to create a function with a destructor,
+** a single object of this type is allocated. FuncDestructor.nRef is set to
+** the number of FuncDef objects created (either 1 or 3, depending on whether
+** or not the specified encoding is SQLITE_ANY). The FuncDef.pDestructor
+** member of each of the new FuncDef objects is set to point to the allocated
+** FuncDestructor.
+**
+** Thereafter, when one of the FuncDef objects is deleted, the reference
+** count on this object is decremented. When it reaches 0, the destructor
+** is invoked and the FuncDestructor structure freed.
+*/
+struct FuncDestructor {
+ int nRef;
+ void (*xDestroy)(void *);
+ void *pUserData;
};
/*
@@ -8539,10 +9668,10 @@ struct FuncDef {
** used to create the initializers for the FuncDef structures.
**
** FUNCTION(zName, nArg, iArg, bNC, xFunc)
-** Used to create a scalar function definition of a function zName
+** Used to create a scalar function definition of a function zName
** implemented by C function xFunc that accepts nArg arguments. The
** value passed as iArg is cast to a (void*) and made available
-** as the user-data (sqlite3_user_data()) for the function. If
+** as the user-data (sqlite3_user_data()) for the function. If
** argument bNC is true, then the SQLITE_FUNC_NEEDCOLL flag is set.
**
** AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal)
@@ -8552,8 +9681,8 @@ struct FuncDef {
** FUNCTION().
**
** LIKEFUNC(zName, nArg, pArg, flags)
-** Used to create a scalar function definition of a function zName
-** that accepts nArg arguments and is implemented by a call to C
+** Used to create a scalar function definition of a function zName
+** that accepts nArg arguments and is implemented by a call to C
** function likeFunc. Argument pArg is cast to a (void *) and made
** available as the function user-data (sqlite3_user_data()). The
** FuncDef.flags variable is set to the value passed as the flags
@@ -8561,15 +9690,15 @@ struct FuncDef {
*/
#define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
{nArg, SQLITE_UTF8, bNC*SQLITE_FUNC_NEEDCOLL, \
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0}
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
#define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
{nArg, SQLITE_UTF8, bNC*SQLITE_FUNC_NEEDCOLL, \
- pArg, 0, xFunc, 0, 0, #zName, 0}
+ pArg, 0, xFunc, 0, 0, #zName, 0, 0}
#define LIKEFUNC(zName, nArg, arg, flags) \
- {nArg, SQLITE_UTF8, flags, (void *)arg, 0, likeFunc, 0, 0, #zName, 0}
+ {nArg, SQLITE_UTF8, flags, (void *)arg, 0, likeFunc, 0, 0, #zName, 0, 0}
#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
{nArg, SQLITE_UTF8, nc*SQLITE_FUNC_NEEDCOLL, \
- SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0}
+ SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
/*
** All current savepoints are stored in a linked list starting at
@@ -8671,7 +9800,7 @@ struct CollSeq {
**
** These used to have mnemonic name like 'i' for SQLITE_AFF_INTEGER and
** 't' for SQLITE_AFF_TEXT. But we can save a little space and improve
-** the speed a little by numbering the values consecutively.
+** the speed a little by numbering the values consecutively.
**
** But rather than start with 0 or 1, we begin with 'a'. That way,
** when multiple affinity types are concatenated into a string and
@@ -8690,7 +9819,7 @@ struct CollSeq {
/*
** The SQLITE_AFF_MASK values masks off the significant bits of an
-** affinity value.
+** affinity value.
*/
#define SQLITE_AFF_MASK 0x67
@@ -8704,20 +9833,20 @@ struct CollSeq {
/*
** An object of this type is created for each virtual table present in
-** the database schema.
+** the database schema.
**
** If the database schema is shared, then there is one instance of this
** structure for each database connection (sqlite3*) that uses the shared
** schema. This is because each database connection requires its own unique
-** instance of the sqlite3_vtab* handle used to access the virtual table
-** implementation. sqlite3_vtab* handles can not be shared between
-** database connections, even when the rest of the in-memory database
+** instance of the sqlite3_vtab* handle used to access the virtual table
+** implementation. sqlite3_vtab* handles can not be shared between
+** database connections, even when the rest of the in-memory database
** schema is shared, as the implementation often stores the database
** connection handle passed to it via the xConnect() or xCreate() method
** during initialization internally. This database connection handle may
-** then used by the virtual table implementation to access real tables
-** within the database. So that they appear as part of the callers
-** transaction, these accesses need to be made via the same database
+** then be used by the virtual table implementation to access real tables
+** within the database. So that they appear as part of the callers
+** transaction, these accesses need to be made via the same database
** connection as that used to execute SQL operations on the virtual table.
**
** All VTable objects that correspond to a single table in a shared
@@ -8729,19 +9858,19 @@ struct CollSeq {
** sqlite3_vtab* handle in the compiled query.
**
** When an in-memory Table object is deleted (for example when the
-** schema is being reloaded for some reason), the VTable objects are not
-** deleted and the sqlite3_vtab* handles are not xDisconnect()ed
+** schema is being reloaded for some reason), the VTable objects are not
+** deleted and the sqlite3_vtab* handles are not xDisconnect()ed
** immediately. Instead, they are moved from the Table.pVTable list to
** another linked list headed by the sqlite3.pDisconnect member of the
-** corresponding sqlite3 structure. They are then deleted/xDisconnected
+** corresponding sqlite3 structure. They are then deleted/xDisconnected
** next time a statement is prepared using said sqlite3*. This is done
** to avoid deadlock issues involving multiple sqlite3.mutex mutexes.
** Refer to comments above function sqlite3VtabUnlockList() for an
** explanation as to why it is safe to add an entry to an sqlite3.pDisconnect
** list without holding the corresponding sqlite3.mutex mutex.
**
-** The memory for objects of this type is always allocated by
-** sqlite3DbMalloc(), using the connection handle stored in VTable.db as
+** The memory for objects of this type is always allocated by
+** sqlite3DbMalloc(), using the connection handle stored in VTable.db as
** the first argument.
*/
struct VTable {
@@ -8749,6 +9878,8 @@ struct VTable {
Module *pMod; /* Pointer to module implementation */
sqlite3_vtab *pVtab; /* Pointer to vtab instance */
int nRef; /* Number of pointers to this structure */
+ u8 bConstraint; /* True if constraints are supported */
+ int iSavepoint; /* Depth of the SAVEPOINT stack */
VTable *pNext; /* Next in linked list (see above) */
};
@@ -8776,20 +9907,20 @@ struct VTable {
** in sqlite.aDb[]. 0 is for the main database and 1 is for the file that
** holds temporary tables and indices. If TF_Ephemeral is set
** then the table is stored in a file that is automatically deleted
-** when the VDBE cursor to the table is closed. In this case Table.tnum
+** when the VDBE cursor to the table is closed. In this case Table.tnum
** refers VDBE cursor number that holds the table open, not to the root
** page number. Transient tables are used to hold the results of a
-** sub-query that appears instead of a real table name in the FROM clause
+** sub-query that appears instead of a real table name in the FROM clause
** of a SELECT statement.
*/
struct Table {
- sqlite3 *dbMem; /* DB connection used for lookaside allocations. */
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) */
+ unsigned 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 */
@@ -8894,7 +10025,7 @@ struct FKey {
** key is set to NULL. CASCADE means that a DELETE or UPDATE of the
** referenced table row is propagated into the row that holds the
** foreign key.
-**
+**
** The following symbolic values are used to record which type
** of action to take.
*/
@@ -8915,14 +10046,14 @@ struct FKey {
/*
** An instance of the following structure is passed as the first
-** argument to sqlite3VdbeKeyCompare and is used to control the
+** argument to sqlite3VdbeKeyCompare and is used to control the
** comparison of the two index keys.
*/
struct KeyInfo {
sqlite3 *db; /* The database connection */
- u8 enc; /* Text encoding - one of the TEXT_Utf* values */
+ u8 enc; /* Text encoding - one of the SQLITE_UTF* values */
u16 nField; /* Number of entries in aColl[] */
- u8 *aSortOrder; /* If defined an aSortOrder[i] is true, sort DESC */
+ u8 *aSortOrder; /* Sort order for each column. May be NULL */
CollSeq *aColl[1]; /* Collating sequence for each term of the key */
};
@@ -8972,7 +10103,7 @@ struct UnpackedRecord {
** In the Table structure describing Ex1, nCol==3 because there are
** three columns in the table. In the Index structure describing
** Ex2, nColumn==2 since 2 of the 3 columns of Ex1 are indexed.
-** The value of aiColumn is {2, 0}. aiColumn[0]==2 because the
+** The value of aiColumn is {2, 0}. aiColumn[0]==2 because the
** first column to be indexed (c3) has an index of 2 in Ex1.aCol[].
** The second column to be indexed (c1) has an index of 0 in
** Ex1.aCol[], hence Ex2.aiColumn[1]==0.
@@ -8980,7 +10111,7 @@ struct UnpackedRecord {
** The Index.onError field determines whether or not the indexed columns
** must be unique and what to do if they are not. When Index.onError=OE_None,
** it means this is not a unique index. Otherwise it is a unique index
-** and the value of Index.onError indicate the which conflict resolution
+** and the value of Index.onError indicate the which conflict resolution
** algorithm to employ whenever an attempt is made to insert a non-unique
** element.
*/
@@ -8993,6 +10124,7 @@ struct 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 *zColAff; /* String defining the affinity of each column */
Index *pNext; /* The next index associated with the same table */
Schema *pSchema; /* Schema containing this index */
@@ -9002,7 +10134,7 @@ struct Index {
};
/*
-** Each sample stored in the sqlite_stat2 table is represented in memory
+** Each sample stored in the sqlite_stat2 table is represented in memory
** using a structure of this type.
*/
struct IndexSample {
@@ -9046,6 +10178,7 @@ struct AggInfo {
u8 useSortingIdx; /* In direct mode, reference the sorting index rather
** than the source table */
int sortingIdx; /* Cursor number of the sorting index */
+ int sortingIdxPTab; /* Cursor number of pseudo-table */
ExprList *pGroupBy; /* The group by clause */
int nSortingColumn; /* Number of columns in the sorting index */
struct AggInfo_col { /* For each column used in source tables */
@@ -9097,9 +10230,9 @@ typedef int ynVar;
** to represent the greater-than-or-equal-to operator in the expression
** tree.
**
-** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB,
+** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB,
** or TK_STRING), then Expr.token contains the text of the SQL literal. If
-** the expression is a variable (TK_VARIABLE), then Expr.token contains the
+** the expression is a variable (TK_VARIABLE), then Expr.token contains the
** variable name. Finally, if the expression is an SQL function (TK_FUNCTION),
** then Expr.token contains the name of the function.
**
@@ -9110,7 +10243,7 @@ typedef int ynVar;
** a CASE expression or an IN expression of the form " IN (, ...)".
** Expr.x.pSelect is used if the expression is a sub-select or an expression of
** the form " IN (SELECT ...)". If the EP_xIsSelect bit is set in the
-** Expr.flags mask, then Expr.x.pSelect is valid. Otherwise, Expr.x.pList is
+** Expr.flags mask, then Expr.x.pSelect is valid. Otherwise, Expr.x.pList is
** valid.
**
** An expression of the form ID or ID.ID refers to a column in a table.
@@ -9121,8 +10254,8 @@ typedef int ynVar;
** value is also stored in the Expr.iAgg column in the aggregate so that
** it can be accessed after all aggregates are computed.
**
-** If the expression is an unbound variable marker (a question mark
-** character '?' in the original SQL) then the Expr.iTable holds the index
+** If the expression is an unbound variable marker (a question mark
+** character '?' in the original SQL) then the Expr.iTable holds the index
** number for that variable.
**
** If the expression is a subquery then Expr.iColumn holds an integer
@@ -9156,12 +10289,12 @@ struct Expr {
u16 flags; /* Various flags. EP_* See below */
union {
char *zToken; /* Token value. Zero terminated and dequoted */
- int iValue; /* Integer value if EP_IntValue */
+ int iValue; /* Non-negative integer value if EP_IntValue */
} u;
/* If the EP_TokenOnly 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.
+ ** access them will result in a segfault or malfunction.
*********************************************************************/
Expr *pLeft; /* Left subnode */
@@ -9232,7 +10365,7 @@ struct Expr {
#endif
/*
-** These macros can be used to test, set, or clear bits in the
+** These macros can be used to test, set, or clear bits in the
** Expr.flags field.
*/
#define ExprHasProperty(E,P) (((E)->flags&(P))==(P))
@@ -9241,8 +10374,8 @@ struct Expr {
#define ExprClearProperty(E,P) (E)->flags&=~(P)
/*
-** Macros to determine the number of bytes required by a normal Expr
-** struct, an Expr struct with the EP_Reduced flag set in Expr.flags
+** Macros to determine the number of bytes required by a normal Expr
+** struct, an Expr struct with the EP_Reduced flag set in Expr.flags
** and an Expr struct with the EP_TokenOnly flag set.
*/
#define EXPR_FULLSIZE sizeof(Expr) /* Full size */
@@ -9250,7 +10383,7 @@ struct Expr {
#define EXPR_TOKENONLYSIZE offsetof(Expr,pLeft) /* Fewer features */
/*
-** Flags passed to the sqlite3ExprDup() function. See the header comment
+** Flags passed to the sqlite3ExprDup() function. See the header comment
** above sqlite3ExprDup() for details.
*/
#define EXPRDUP_REDUCE 0x0001 /* Used reduced-size Expr nodes */
@@ -9342,6 +10475,9 @@ typedef u64 Bitmask;
** and the next table on the list. The parser builds the list this way.
** But sqlite3SrcListShiftJoinType() later shifts the jointypes so that each
** jointype expresses the join between the table and the previous table.
+**
+** In the colUsed field, the high-order bit (bit 63) is set if the table
+** contains more than 63 columns and the 64-th or later column is used.
*/
struct SrcList {
i16 nSrc; /* Number of tables or subqueries in the FROM clause */
@@ -9352,9 +10488,14 @@ struct SrcList {
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
Table *pTab; /* An SQL table corresponding to zName */
Select *pSelect; /* A SELECT statement used in place of a table name */
- u8 isPopulated; /* Temporary table associated with SELECT is populated */
+ 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 */
+#ifndef SQLITE_OMIT_EXPLAIN
+ u8 iSelectId; /* If pSelect!=0, the id of the sub-select in EQP */
+#endif
int iCursor; /* The VDBE cursor number used to access this table */
Expr *pOn; /* The ON clause of a join */
IdList *pUsing; /* The USING clause of a join */
@@ -9393,6 +10534,7 @@ struct SrcList {
struct WherePlan {
u32 wsFlags; /* WHERE_* flags that describe the strategy */
u32 nEq; /* Number of == constraints */
+ double nRow; /* Estimated number of rows (for EQP) */
union {
Index *pIdx; /* Index when WHERE_INDEXED is true */
struct WhereTerm *pTerm; /* WHERE clause term for OR-search */
@@ -9453,7 +10595,7 @@ struct WhereLevel {
#define WHERE_ORDERBY_MAX 0x0002 /* ORDER BY processing for max() func */
#define WHERE_ONEPASS_DESIRED 0x0004 /* Want to do one-pass UPDATE/DELETE */
#define WHERE_DUPLICATES_OK 0x0008 /* Ok to return a row more than once */
-#define WHERE_OMIT_OPEN 0x0010 /* Table cursor are already open */
+#define WHERE_OMIT_OPEN 0x0010 /* Table cursors are already open */
#define WHERE_OMIT_CLOSE 0x0020 /* Omit close of table & index cursors */
#define WHERE_FORCE_TABLE 0x0040 /* Do not use an index-only search */
#define WHERE_ONETABLE_ONLY 0x0080 /* Only code the 1st table in pTabList */
@@ -9470,15 +10612,21 @@ struct WhereInfo {
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 */
};
+#define WHERE_DISTINCT_UNIQUE 1
+#define WHERE_DISTINCT_ORDERED 2
+
/*
** A NameContext defines a context in which to resolve table and column
** names. The context consists of a list of tables (the pSrcList) field and
@@ -9488,12 +10636,12 @@ struct WhereInfo {
** pEList corresponds to the result set of a SELECT and is NULL for
** other statements.
**
-** NameContexts can be nested. When resolving names, the inner-most
+** NameContexts can be nested. When resolving names, the inner-most
** context is searched first. If no match is found, the next outer
** context is checked. If there is still no match, the next context
** is checked. This process continues until either a match is found
** or all contexts are check. When a match is found, the nRef member of
-** the context containing the match is incremented.
+** the context containing the match is incremented.
**
** Each subquery gets a new NameContext. The pNext field points to the
** NameContext in the parent query. Thus the process of scanning the
@@ -9551,6 +10699,7 @@ struct Select {
Expr *pOffset; /* OFFSET expression. NULL means not used. */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */
+ double nSelectRow; /* Estimated number of result rows */
};
/*
@@ -9563,6 +10712,7 @@ struct Select {
#define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
#define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
+#define SF_UseSorter 0x0040 /* Sort using a sorter */
/*
@@ -9598,7 +10748,7 @@ struct SelectDest {
};
/*
-** During code generation of statements that do inserts into AUTOINCREMENT
+** During code generation of statements that do inserts into AUTOINCREMENT
** tables, the following information is attached to the Table.u.autoInc.p
** pointer of each autoincrement table to record some side information that
** the code generator needs. We have to keep per-table autoincrement
@@ -9621,7 +10771,7 @@ struct AutoincInfo {
#endif
/*
-** At least one instance of the following structure is created for each
+** At least one instance of the following structure is created for each
** trigger that may be fired while parsing an INSERT, UPDATE or DELETE
** statement. All such objects are stored in the linked list headed at
** Parse.pTriggerPrg and deleted once statement compilation has been
@@ -9634,7 +10784,7 @@ struct AutoincInfo {
** values for both pTrigger and orconf.
**
** The TriggerPrg.aColmask[0] variable is set to a mask of old.* columns
-** accessed (or set to 0 for triggers fired as a result of INSERT
+** accessed (or set to 0 for triggers fired as a result of INSERT
** statements). Similarly, the TriggerPrg.aColmask[1] variable is set to
** a mask of new.* columns used by the program.
*/
@@ -9646,6 +10796,15 @@ struct TriggerPrg {
TriggerPrg *pNext; /* Next entry in Parse.pTriggerPrg list */
};
+/*
+** The yDbMask datatype for the bitmask of all attached databases.
+*/
+#if SQLITE_MAX_ATTACHED>30
+ typedef sqlite3_uint64 yDbMask;
+#else
+ typedef unsigned int yDbMask;
+#endif
+
/*
** An SQL parser context. A copy of this structure is passed through
** the parser and down into all the parser action routine in order to
@@ -9656,7 +10815,7 @@ struct TriggerPrg {
** is constant but the second part is reset at the beginning and end of
** each recursion.
**
-** The nTableLock and aTableLock variables are only used if the shared-cache
+** The nTableLock and aTableLock variables are only used if the shared-cache
** feature is enabled (if sqlite3Tsd()->useSharedData is true). They are
** used to store the set of table-locks required by the statement being
** compiled. Function sqlite3TableLock() is used to add entries to the
@@ -9694,8 +10853,8 @@ struct Parse {
int iReg; /* Reg with value of this column. 0 means none. */
int lru; /* Least recently used entry has the smallest value */
} aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */
- u32 writeMask; /* Start a write transaction on these databases */
- u32 cookieMask; /* Bitmask of schema verified databases */
+ yDbMask writeMask; /* Start a write transaction on these databases */
+ yDbMask cookieMask; /* Bitmask of schema verified databases */
u8 isMultiWrite; /* True if statement may affect/insert multiple rows */
u8 mayAbort; /* True if statement may throw an ABORT exception */
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
@@ -9717,14 +10876,14 @@ struct Parse {
u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
u8 disableTriggers; /* True to disable triggers */
+ double nQueryLoop; /* Estimated number of iterations of a query */
/* Above is constant between recursions. Below is reset before and after
** each recursion */
int nVar; /* Number of '?' variables seen in the SQL so far */
- int nVarExpr; /* Number of used slots in apVarExpr[] */
- int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */
- Expr **apVarExpr; /* Pointers to :aaa and $aaaa wildcard expressions */
+ int nzVar; /* Number of available slots in azVar[] */
+ char **azVar; /* Pointers to names of parameters */
Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */
int nAlias; /* Number of aliased result set columns */
int nAliasAlloc; /* Number of allocated slots for aAlias[] */
@@ -9745,6 +10904,11 @@ struct Parse {
int nHeight; /* Expression tree height of current sub-select */
Table *pZombieTab; /* List of Table objects to delete after code gen */
TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
+
+#ifndef SQLITE_OMIT_EXPLAIN
+ int iSelectId;
+ int iNextSelectId;
+#endif
};
#ifdef SQLITE_OMIT_VIRTUALTABLE
@@ -9774,10 +10938,10 @@ struct AuthContext {
/*
* Each trigger present in the database schema is stored as an instance of
- * struct Trigger.
+ * struct Trigger.
*
* Pointers to instances of struct Trigger are stored in two ways.
- * 1. In the "trigHash" hash table (part of the sqlite3* that represents the
+ * 1. In the "trigHash" hash table (part of the sqlite3* that represents the
* database). This allows Trigger structures to be retrieved by name.
* 2. All triggers associated with a single table form a linked list, using the
* pNext member of struct Trigger. A pointer to the first element of the
@@ -9803,7 +10967,7 @@ struct Trigger {
/*
** A trigger is either a BEFORE or an AFTER trigger. The following constants
-** determine which.
+** determine which.
**
** If there are multiple triggers, you might of some BEFORE and some AFTER.
** In that cases, the constants below can be ORed together.
@@ -9813,15 +10977,15 @@ struct Trigger {
/*
* An instance of struct TriggerStep is used to store a single SQL statement
- * that is a part of a trigger-program.
+ * that is a part of a trigger-program.
*
* Instances of struct TriggerStep are stored in a singly linked list (linked
- * using the "pNext" member) referenced by the "step_list" member of the
+ * using the "pNext" member) referenced by the "step_list" member of the
* associated struct Trigger instance. The first element of the linked list is
* the first step of the trigger-program.
- *
+ *
* The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or
- * "SELECT" statement. The meanings of the other members is determined by the
+ * "SELECT" statement. The meanings of the other members is determined by the
* value of "op" as follows:
*
* (op == TK_INSERT)
@@ -9831,7 +10995,7 @@ struct Trigger {
* target -> A token holding the quoted name of the table to insert into.
* pExprList -> If this is an INSERT INTO ... VALUES ... statement, then
* this stores values to be inserted. Otherwise NULL.
- * pIdList -> If this is an INSERT INTO ... () VALUES ...
+ * pIdList -> If this is an INSERT INTO ... () VALUES ...
* statement, then this stores the column-names to be
* inserted into.
*
@@ -9839,7 +11003,7 @@ struct Trigger {
* target -> A token holding the quoted name of the table to delete from.
* pWhere -> The WHERE clause of the DELETE statement if one is specified.
* Otherwise NULL.
- *
+ *
* (op == TK_UPDATE)
* target -> A token holding the quoted name of the table to update rows of.
* pWhere -> The WHERE clause of the UPDATE statement if one is specified.
@@ -9847,7 +11011,7 @@ struct Trigger {
* pExprList -> A list of the columns to update and the expressions to update
* them to. See sqlite3Update() documentation of "pChanges"
* argument.
- *
+ *
*/
struct TriggerStep {
u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */
@@ -9865,7 +11029,7 @@ struct TriggerStep {
/*
** The following structure contains information used by the sqliteFix...
** routines as they walk the parse tree to make database references
-** explicit.
+** explicit.
*/
typedef struct DbFixer DbFixer;
struct DbFixer {
@@ -9887,7 +11051,7 @@ struct StrAccum {
int nAlloc; /* Amount of space allocated in zText */
int mxAlloc; /* Maximum allowed string length */
u8 mallocFailed; /* Becomes true if any memory allocation fails */
- u8 useMalloc; /* True if zText is enlargeable using realloc */
+ u8 useMalloc; /* 0: none, 1: sqlite3DbMalloc, 2: sqlite3_malloc */
u8 tooBig; /* Becomes true if string size exceeds limits */
};
@@ -9911,6 +11075,7 @@ struct Sqlite3Config {
int bMemstat; /* True to enable memory status */
int bCoreMutex; /* True to enable core mutexing */
int bFullMutex; /* True to enable full mutexing */
+ int bOpenUri; /* True to interpret filenames as URIs */
int mxStrlen; /* Maximum string length */
int szLookaside; /* Default lookaside buffer size */
int nLookaside; /* Default lookaside buffer count */
@@ -9939,6 +11104,7 @@ struct Sqlite3Config {
int nRefInitMutex; /* Number of users of pInitMutex */
void (*xLog)(void*,int,const char*); /* Function for logging */
void *pLogArg; /* First argument to xLog() */
+ int bLocaltimeFault; /* True to fail localtime() calls */
};
/*
@@ -10039,7 +11205,6 @@ SQLITE_PRIVATE int sqlite3CantopenError(int);
** Internal function prototypes
*/
SQLITE_PRIVATE int sqlite3StrICmp(const char *, const char *);
-SQLITE_PRIVATE int sqlite3IsNumber(const char*, int*, u8);
SQLITE_PRIVATE int sqlite3Strlen30(const char*);
#define sqlite3StrNICmp sqlite3_strnicmp
@@ -10063,7 +11228,7 @@ SQLITE_PRIVATE void *sqlite3PageMalloc(int);
SQLITE_PRIVATE void sqlite3PageFree(void*);
SQLITE_PRIVATE void sqlite3MemSetDefault(void);
SQLITE_PRIVATE void sqlite3BenignMallocHooks(void (*)(void), void (*)(void));
-SQLITE_PRIVATE int sqlite3MemoryAlarm(void (*)(void*, sqlite3_int64, int), void*, sqlite3_int64);
+SQLITE_PRIVATE int sqlite3HeapNearlyFull(void);
/*
** On systems with ample stack space and that support alloca(), make
@@ -10076,7 +11241,7 @@ SQLITE_PRIVATE int sqlite3MemoryAlarm(void (*)(void*, sqlite3_int64, int), void*
#ifdef SQLITE_USE_ALLOCA
# define sqlite3StackAllocRaw(D,N) alloca(N)
# define sqlite3StackAllocZero(D,N) memset(alloca(N), 0, N)
-# define sqlite3StackFree(D,P)
+# define sqlite3StackFree(D,P)
#else
# define sqlite3StackAllocRaw(D,N) sqlite3DbMallocRaw(D,N)
# define sqlite3StackAllocZero(D,N) sqlite3DbMallocZero(D,N)
@@ -10092,7 +11257,8 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void);
#ifndef SQLITE_MUTEX_OMIT
-SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void);
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void);
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void);
SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int);
SQLITE_PRIVATE int sqlite3MutexInit(void);
SQLITE_PRIVATE int sqlite3MutexEnd(void);
@@ -10160,6 +11326,8 @@ SQLITE_PRIVATE void sqlite3AddColumnType(Parse*,Token*);
SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,ExprSpan*);
SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*);
SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,Select*);
+SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*,
+ sqlite3_vfs**,char**,char **);
SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32);
SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec*, u32);
@@ -10184,7 +11352,7 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse*,Table*);
#endif
SQLITE_PRIVATE void sqlite3DropTable(Parse*, SrcList*, int, int);
-SQLITE_PRIVATE void sqlite3DeleteTable(Table*);
+SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3*, Table*);
#ifndef SQLITE_OMIT_AUTOINCREMENT
SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse);
SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse);
@@ -10221,9 +11389,10 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, E
#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**, u16);
+SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**,ExprList*,u16);
SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*);
SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int);
+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);
@@ -10232,7 +11401,6 @@ SQLITE_PRIVATE void sqlite3ExprCachePop(Parse*, int);
SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse*, int, int);
SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse*);
SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse*, int, int);
-SQLITE_PRIVATE void sqlite3ExprHardCopy(Parse*,int,int);
SQLITE_PRIVATE int sqlite3ExprCode(Parse*, Expr*, int);
SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int);
@@ -10250,6 +11418,7 @@ SQLITE_PRIVATE void sqlite3Vacuum(Parse*);
SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*);
SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, Token*);
SQLITE_PRIVATE int sqlite3ExprCompare(Expr*, Expr*);
+SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList*, ExprList*);
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*);
@@ -10258,6 +11427,7 @@ SQLITE_PRIVATE void sqlite3PrngRestoreState(void);
SQLITE_PRIVATE void sqlite3PrngResetState(void);
SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*);
SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int);
+SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb);
SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int);
SQLITE_PRIVATE void sqlite3CommitTransaction(Parse*);
SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse*);
@@ -10351,26 +11521,24 @@ SQLITE_PRIVATE int sqlite3AuthReadCol(Parse*, const char *, const char *, int)
#endif
SQLITE_PRIVATE void sqlite3Attach(Parse*, Expr*, Expr*, Expr*);
SQLITE_PRIVATE void sqlite3Detach(Parse*, Expr*);
-SQLITE_PRIVATE int sqlite3BtreeFactory(sqlite3 *db, const char *zFilename,
- int omitJournal, int nCache, int flags, Btree **ppBtree);
SQLITE_PRIVATE int sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*);
SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*);
SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*);
SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*);
SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
-SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*);
+SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8);
SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
-SQLITE_PRIVATE int sqlite3FitsIn64Bits(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 int sqlite3Utf8Read(const u8*, const u8**);
+SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8*, const u8**);
/*
** Routines to read and write variable-length integers. These used to
** be defined locally, but now we use the varint routines in the util.c
** file. Code should use the MACRO forms below, as the Varint32 versions
-** are coded to assume the single byte case is already handled (which
+** are coded to assume the single byte case is already handled (which
** the MACRO form does).
*/
SQLITE_PRIVATE int sqlite3PutVarint(unsigned char*, u64);
@@ -10407,23 +11575,35 @@ SQLITE_PRIVATE void sqlite3TableAffinityStr(Vdbe *, Table *);
SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2);
SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr);
-SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*);
+SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8);
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 **);
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(Parse *pParse, Expr *, Token *);
+SQLITE_PRIVATE Expr *sqlite3ExprSetColl(Expr*, CollSeq*);
+SQLITE_PRIVATE Expr *sqlite3ExprSetCollByToken(Parse *pParse, Expr*, Token*);
SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *);
SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *, const char *);
SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int);
+SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64);
+SQLITE_PRIVATE int sqlite3SubInt64(i64*,i64);
+SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64);
+SQLITE_PRIVATE int sqlite3AbsInt32(int);
+#ifdef SQLITE_ENABLE_8_3_NAMES
+SQLITE_PRIVATE void sqlite3FileSuffix3(const char*, char*);
+#else
+# define sqlite3FileSuffix3(X,Y)
+#endif
+SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z);
SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8);
SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8);
-SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
+SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
void(*)(void*));
SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*);
SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *);
@@ -10437,13 +11617,16 @@ SQLITE_PRIVATE void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[];
SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[];
SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[];
+SQLITE_PRIVATE const Token sqlite3IntTokens[];
SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config;
SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
+#ifndef SQLITE_OMIT_WSD
SQLITE_PRIVATE int sqlite3PendingByte;
#endif
-SQLITE_PRIVATE void sqlite3RootPageMoved(Db*, int, int);
+#endif
+SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3*, int, int, int);
SQLITE_PRIVATE void sqlite3Reindex(Parse*, Token*, Token*);
-SQLITE_PRIVATE void sqlite3AlterFunctions(sqlite3*);
+SQLITE_PRIVATE void sqlite3AlterFunctions(void);
SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
@@ -10463,18 +11646,20 @@ SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*);
SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*);
SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *, const char *);
SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3*,int iDB);
-SQLITE_PRIVATE void sqlite3DeleteIndexSamples(Index*);
+SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3*,Index*);
SQLITE_PRIVATE void sqlite3DefaultRowEst(Index*);
SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3*, int);
SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);
SQLITE_PRIVATE void sqlite3MinimumFileFormat(Parse*, int, int);
-SQLITE_PRIVATE void sqlite3SchemaFree(void *);
+SQLITE_PRIVATE void sqlite3SchemaClear(void *);
SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *, Btree *);
SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *);
SQLITE_PRIVATE KeyInfo *sqlite3IndexKeyinfo(Parse *, Index *);
-SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
+SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
void (*)(sqlite3_context*,int,sqlite3_value **),
- void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*));
+ void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*),
+ FuncDestructor *pDestructor
+);
SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int);
SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *);
@@ -10521,17 +11706,19 @@ SQLITE_PRIVATE int sqlite3Utf8To8(unsigned char*);
# define sqlite3VtabRollback(X)
# define sqlite3VtabCommit(X)
# define sqlite3VtabInSync(db) 0
-# define sqlite3VtabLock(X)
+# define sqlite3VtabLock(X)
# define sqlite3VtabUnlock(X)
# define sqlite3VtabUnlockList(X)
+# define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK
#else
-SQLITE_PRIVATE void sqlite3VtabClear(Table*);
+SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table*);
SQLITE_PRIVATE int sqlite3VtabSync(sqlite3 *db, char **);
SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db);
SQLITE_PRIVATE int sqlite3VtabCommit(sqlite3 *db);
SQLITE_PRIVATE void sqlite3VtabLock(VTable *);
SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *);
SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3*);
+SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *, int, int);
# define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
#endif
SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*);
@@ -10552,12 +11739,15 @@ SQLITE_PRIVATE void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3*);
SQLITE_PRIVATE VTable *sqlite3GetVTable(sqlite3*, Table*);
+SQLITE_PRIVATE const char *sqlite3JournalModename(int);
+SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3*, int, int, int*, int*);
+SQLITE_PRIVATE int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);
/* 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
** key functionality is available. If OMIT_TRIGGER is defined but
** OMIT_FOREIGN_KEY is not, only some of the functions are no-oped. In
-** this case foreign keys are parsed, but no other functionality is
+** this case foreign keys are parsed, but no other functionality is
** provided (enforcement of FK constraints requires the triggers sub-system).
*/
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
@@ -10575,9 +11765,9 @@ SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *);
#define sqlite3FkRequired(a,b,c,d) 0
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
-SQLITE_PRIVATE void sqlite3FkDelete(Table*);
+SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *, Table*);
#else
- #define sqlite3FkDelete(a)
+ #define sqlite3FkDelete(a,b)
#endif
@@ -10647,7 +11837,7 @@ SQLITE_PRIVATE void sqlite3ParserTrace(FILE*, char *);
/*
** If the SQLITE_ENABLE IOTRACE exists then the global variable
** sqlite3IoTrace is a pointer to a printf-like routine used to
-** print I/O tracing messages.
+** print I/O tracing messages.
*/
#ifdef SQLITE_ENABLE_IOTRACE
# define IOTRACE(A) if( sqlite3IoTrace ){ sqlite3IoTrace A; }
@@ -10658,7 +11848,50 @@ SQLITE_PRIVATE void (*sqlite3IoTrace)(const char*,...);
# define sqlite3VdbeIOTraceSql(X)
#endif
+/*
+** These routines are available for the mem2.c debugging memory allocator
+** only. They are used to verify that different "types" of memory
+** allocations are properly tracked by the system.
+**
+** sqlite3MemdebugSetType() sets the "type" of an allocation to one of
+** the MEMTYPE_* macros defined below. The type must be a bitmask with
+** a single bit set.
+**
+** sqlite3MemdebugHasType() returns true if any of the bits in its second
+** argument match the type set by the previous sqlite3MemdebugSetType().
+** sqlite3MemdebugHasType() is intended for use inside assert() statements.
+**
+** sqlite3MemdebugNoType() returns true if none of the bits in its second
+** argument match the type set by the previous sqlite3MemdebugSetType().
+**
+** Perhaps the most important point is the difference between MEMTYPE_HEAP
+** and MEMTYPE_LOOKASIDE. If an allocation is MEMTYPE_LOOKASIDE, that means
+** it might have been allocated by lookaside, except the allocation was
+** too large or lookaside was already full. It is important to verify
+** that allocations that might have been satisfied by lookaside are not
+** passed back to non-lookaside free() routines. Asserts such as the
+** example above are placed on the non-lookaside free() routines to verify
+** this constraint.
+**
+** All of this is no-op for a production build. It only comes into
+** play when the SQLITE_MEMDEBUG compile-time option is used.
+*/
+#ifdef SQLITE_MEMDEBUG
+SQLITE_PRIVATE void sqlite3MemdebugSetType(void*,u8);
+SQLITE_PRIVATE int sqlite3MemdebugHasType(void*,u8);
+SQLITE_PRIVATE int sqlite3MemdebugNoType(void*,u8);
+#else
+# define sqlite3MemdebugSetType(X,Y) /* no-op */
+# define sqlite3MemdebugHasType(X,Y) 1
+# define sqlite3MemdebugNoType(X,Y) 1
#endif
+#define MEMTYPE_HEAP 0x01 /* General heap allocations */
+#define MEMTYPE_LOOKASIDE 0x02 /* Might have been lookaside memory */
+#define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */
+#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */
+#define MEMTYPE_DB 0x10 /* Uses sqlite3DbMalloc, not sqlite_malloc */
+
+#endif /* _SQLITEINT_H_ */
/************** End of sqliteInt.h *******************************************/
/************** Begin file global.c ******************************************/
@@ -10678,7 +11911,7 @@ SQLITE_PRIVATE void (*sqlite3IoTrace)(const char*,...);
*/
/* An array to map all upper-case characters into their corresponding
-** lower-case character.
+** 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
@@ -10744,7 +11977,7 @@ SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = {
** Standard function tolower() is implemented using the sqlite3UpperToLower[]
** array. tolower() is used more often than toupper() by SQLite.
**
-** Bit 0x40 is set if the character non-alphanumeric and can be used in an
+** 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
** part of an identifier is 0x46.
@@ -10792,7 +12025,9 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
};
#endif
-
+#ifndef SQLITE_USE_URI
+# define SQLITE_USE_URI 0
+#endif
/*
** The following singleton contains the global configuration for
@@ -10802,8 +12037,9 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */
1, /* bCoreMutex */
SQLITE_THREADSAFE==1, /* bFullMutex */
+ SQLITE_USE_URI, /* bOpenUri */
0x7ffffffe, /* mxStrlen */
- 100, /* szLookaside */
+ 128, /* szLookaside */
500, /* nLookaside */
{0,0,0,0,0,0,0,0}, /* m */
{0,0,0,0,0,0,0,0,0}, /* mutex */
@@ -10829,6 +12065,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, /* nRefInitMutex */
0, /* xLog */
0, /* pLogArg */
+ 0, /* bLocaltimeFault */
};
@@ -10839,6 +12076,15 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
*/
SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
+/*
+** Constant tokens for values 0 and 1.
+*/
+SQLITE_PRIVATE const Token sqlite3IntTokens[] = {
+ { "0", 1 },
+ { "1", 1 }
+};
+
+
/*
** The value of the "pending" byte must be 0x40000000 (1 byte past the
** 1-gibabyte boundary) in a compatible database. SQLite never uses
@@ -10857,13 +12103,15 @@ SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
** Changing the pending byte during operating results in undefined
** and dileterious behavior.
*/
+#ifndef SQLITE_OMIT_WSD
SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;
+#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.
+** the vdbe.c file.
*/
SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
@@ -10889,7 +12137,7 @@ SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
/*
-** An array of names of all compile-time options. This array should
+** 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
@@ -11014,6 +12262,9 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_LOCK_TRACE
"LOCK_TRACE",
#endif
+#ifdef SQLITE_MAX_SCHEMA_RETRY
+ "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
+#endif
#ifdef SQLITE_MEMDEBUG
"MEMDEBUG",
#endif
@@ -11041,6 +12292,12 @@ static const char * const azCompileOpt[] = {
#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
@@ -11062,9 +12319,11 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_OMIT_CHECK
"OMIT_CHECK",
#endif
-#ifdef SQLITE_OMIT_COMPILEOPTION_DIAGS
- "OMIT_COMPILEOPTION_DIAGS",
-#endif
+/* // redundant
+** #ifdef SQLITE_OMIT_COMPILEOPTION_DIAGS
+** "OMIT_COMPILEOPTION_DIAGS",
+** #endif
+*/
#ifdef SQLITE_OMIT_COMPLETE
"OMIT_COMPLETE",
#endif
@@ -11098,9 +12357,6 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_OMIT_GET_TABLE
"OMIT_GET_TABLE",
#endif
-#ifdef SQLITE_OMIT_GLOBALRECOVER
- "OMIT_GLOBALRECOVER",
-#endif
#ifdef SQLITE_OMIT_INCRBLOB
"OMIT_INCRBLOB",
#endif
@@ -11122,6 +12378,9 @@ 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
@@ -11179,12 +12438,18 @@ static const char * const azCompileOpt[] = {
#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_PAGECACHE_BLOCKALLOC
+ "PAGECACHE_BLOCKALLOC",
+#endif
#ifdef SQLITE_PERFORMANCE_TRACE
"PERFORMANCE_TRACE",
#endif
@@ -11271,14 +12536,467 @@ SQLITE_API const char *sqlite3_compileoption_get(int N){
** This module implements the sqlite3_status() interface and related
** functionality.
*/
+/************** Include vdbeInt.h in the middle of status.c ******************/
+/************** Begin file vdbeInt.h *****************************************/
+/*
+** 2003 September 6
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This is the header file for information that is private to the
+** VDBE. This information used to all be at the top of the single
+** source code file "vdbe.c". When that file became too big (over
+** 6000 lines long) it was split up into several smaller files and
+** this header information was factored out.
+*/
+#ifndef _VDBEINT_H_
+#define _VDBEINT_H_
+
+/*
+** SQL is translated into a sequence of instructions to be
+** executed by a virtual machine. Each instruction is an instance
+** of the following structure.
+*/
+typedef struct VdbeOp Op;
+
+/*
+** Boolean values
+*/
+typedef unsigned char Bool;
+
+/* Opaque type used by code in vdbesort.c */
+typedef struct VdbeSorter VdbeSorter;
+
+/*
+** 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.
+*/
+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 */
+ 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 */
+
+ /* 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;
+
+/*
+** 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 */
+ int pc; /* Program Counter in parent (calling) frame */
+ Op *aOp; /* Program instructions for parent frame */
+ int nOp; /* Size of aOp array */
+ Mem *aMem; /* Array of memory cells for parent frame */
+ int nMem; /* Number of entries in aMem */
+ VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
+ u16 nCursor; /* Number of entries in apCsr */
+ void *token; /* Copy of SubProgram.token */
+ int nChildMem; /* Number of memory cells for child frame */
+ int nChildCsr; /* Number of cursors for child frame */
+ i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
+ int nChange; /* Statement changes (Vdbe.nChanges) */
+ VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */
+};
+
+#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
+
+/*
+** A value for VdbeCursor.cacheValid that means the cache is always invalid.
+*/
+#define CACHE_STALE 0
+
+/*
+** Internally, the vdbe manipulates nearly all SQL values as Mem
+** structures. Each Mem struct may cache multiple representations (string,
+** integer etc.) of the same value.
+*/
+struct Mem {
+ 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
+ void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
+ char *zMalloc; /* Dynamic buffer allocated by sqlite3_malloc() */
+};
+
+/* One or more of the following flags are set to indicate the validOK
+** 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_TypeMask 0x00ff /* Mask of type bits */
+
+/* Whenever Mem contains a valid string or blob representation, one of
+** the following flags must be set to determine the memory management
+** policy for Mem.z. The MEM_Term flag tells us whether or not the
+** string is \000 or \u0000 terminated
+*/
+#define MEM_Term 0x0200 /* String rep is nul terminated */
+#define MEM_Dyn 0x0400 /* Need to call 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
+
+/*
+** Clear any existing type flags from a Mem and replace them with f
+*/
+#define MemSetTypeFlag(p, f) \
+ ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f)
+
+/*
+** Return true if a memory cell is not marked as invalid. This macro
+** is for use inside assert() statements only.
+*/
+#ifdef SQLITE_DEBUG
+#define memIsValid(M) ((M)->flags & MEM_Invalid)==0
+#endif
+
+
+/* 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 */
+};
+
+/*
+** 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 */
+ int isError; /* Error code returned by the function. */
+ CollSeq *pColl; /* Collating sequence */
+};
+
+/*
+** 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 nLabelAlloc; /* Number of slots allocated in aLabel[] */
+ 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[] */
+ 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 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() */
+ 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
+ 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 */
+};
+
+/*
+** 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);
+
+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 MemReleaseExt(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);
+
+#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(VdbeCursor *, Mem *);
+SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, VdbeCursor *, int *);
+SQLITE_PRIVATE int sqlite3VdbeSorterRewind(sqlite3 *, VdbeCursor *, int *);
+SQLITE_PRIVATE int sqlite3VdbeSorterWrite(sqlite3 *, VdbeCursor *, Mem *);
+SQLITE_PRIVATE int sqlite3VdbeSorterCompare(VdbeCursor *, Mem *, int *);
+#endif
+
+#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 sqlite3VdbeMemPrepareToChange(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 *);
+#else
+ #define sqlite3VdbeMemExpandBlob(x) SQLITE_OK
+#endif
+
+#endif /* !defined(_VDBEINT_H_) */
+
+/************** End of vdbeInt.h *********************************************/
+/************** Continuing where we left off in status.c *********************/
/*
** Variables in which to record status information.
*/
typedef struct sqlite3StatType sqlite3StatType;
static SQLITE_WSD struct sqlite3StatType {
- int nowValue[9]; /* Current value */
- int mxValue[9]; /* Maximum value */
+ int nowValue[10]; /* Current value */
+ int mxValue[10]; /* Maximum value */
} sqlite3Stat = { {0,}, {0,} };
@@ -11360,6 +13078,8 @@ SQLITE_API int sqlite3_db_status(
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;
@@ -11369,11 +13089,115 @@ SQLITE_API int sqlite3_db_status(
}
break;
}
+
+ case SQLITE_DBSTATUS_LOOKASIDE_HIT:
+ case SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE:
+ case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: {
+ testcase( op==SQLITE_DBSTATUS_LOOKASIDE_HIT );
+ testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE );
+ testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL );
+ assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 );
+ assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 );
+ *pCurrent = 0;
+ *pHighwater = db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT];
+ if( resetFlag ){
+ db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0;
+ }
+ break;
+ }
+
+ /*
+ ** Return an approximation for the amount of memory currently used
+ ** by all pagers associated with the given database connection. The
+ ** highwater mark is meaningless and is returned as zero.
+ */
+ case SQLITE_DBSTATUS_CACHE_USED: {
+ int totalUsed = 0;
+ int i;
+ sqlite3BtreeEnterAll(db);
+ for(i=0; inDb; i++){
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ){
+ Pager *pPager = sqlite3BtreePager(pBt);
+ totalUsed += sqlite3PagerMemUsed(pPager);
+ }
+ }
+ sqlite3BtreeLeaveAll(db);
+ *pCurrent = totalUsed;
+ *pHighwater = 0;
+ break;
+ }
+
+ /*
+ ** *pCurrent gets an accurate estimate of the amount of memory used
+ ** to store the schema for all databases (main, temp, and any ATTACHed
+ ** databases. *pHighwater is set to zero.
+ */
+ case SQLITE_DBSTATUS_SCHEMA_USED: {
+ int i; /* Used to iterate through schemas */
+ int nByte = 0; /* Used to accumulate return value */
+
+ sqlite3BtreeEnterAll(db);
+ db->pnBytesFreed = &nByte;
+ for(i=0; inDb; i++){
+ Schema *pSchema = db->aDb[i].pSchema;
+ if( ALWAYS(pSchema!=0) ){
+ HashElem *p;
+
+ nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * (
+ pSchema->tblHash.count
+ + pSchema->trigHash.count
+ + pSchema->idxHash.count
+ + pSchema->fkeyHash.count
+ );
+ nByte += sqlite3MallocSize(pSchema->tblHash.ht);
+ nByte += sqlite3MallocSize(pSchema->trigHash.ht);
+ nByte += sqlite3MallocSize(pSchema->idxHash.ht);
+ nByte += sqlite3MallocSize(pSchema->fkeyHash.ht);
+
+ for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
+ sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
+ }
+ for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
+ sqlite3DeleteTable(db, (Table *)sqliteHashData(p));
+ }
+ }
+ }
+ db->pnBytesFreed = 0;
+ sqlite3BtreeLeaveAll(db);
+
+ *pHighwater = 0;
+ *pCurrent = nByte;
+ break;
+ }
+
+ /*
+ ** *pCurrent gets an accurate estimate of the amount of memory used
+ ** to store all prepared statements.
+ ** *pHighwater is set to zero.
+ */
+ case SQLITE_DBSTATUS_STMT_USED: {
+ struct Vdbe *pVdbe; /* Used to iterate through VMs */
+ int nByte = 0; /* Used to accumulate return value */
+
+ db->pnBytesFreed = &nByte;
+ for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
+ sqlite3VdbeDeleteObject(db, pVdbe);
+ }
+ db->pnBytesFreed = 0;
+
+ *pHighwater = 0;
+ *pCurrent = nByte;
+
+ break;
+ }
+
default: {
- return SQLITE_ERROR;
+ rc = SQLITE_ERROR;
}
}
- return SQLITE_OK;
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
}
/************** End of status.c **********************************************/
@@ -11390,7 +13214,7 @@ SQLITE_API int sqlite3_db_status(
**
*************************************************************************
** This file contains the C functions that implement date and time
-** functions for SQLite.
+** functions for SQLite.
**
** There is only one exported symbol in this file - the function
** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
@@ -11399,7 +13223,7 @@ SQLITE_API int sqlite3_db_status(
** 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.
+** calendar system.
**
** 1970-01-01 00:00:00 is JD 2440587.5
** 2000-01-01 00:00:00 is JD 2451544.5
@@ -11423,26 +13247,12 @@ SQLITE_API int sqlite3_db_status(
** Willmann-Bell, Inc
** Richmond, Virginia (USA)
*/
+/* #include */
+/* #include */
#include
#ifndef SQLITE_OMIT_DATETIME_FUNCS
-/*
-** 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
/*
** A structure for holding a single date and time.
@@ -11510,12 +13320,6 @@ end_getDigits:
return cnt;
}
-/*
-** Read text from z[] and convert into a floating point number. Return
-** the number of digits converted.
-*/
-#define getValue sqlite3AtoF
-
/*
** Parse a timezone extension on the end of a date-time.
** The extension is of the form:
@@ -11691,10 +13495,8 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){
** Set the time to the current time reported by the VFS
*/
static void setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
- double r;
sqlite3 *db = sqlite3_context_db_handle(context);
- sqlite3OsCurrentTime(db->pVfs, &r);
- p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
+ sqlite3OsCurrentTimeInt64(db->pVfs, &p->iJD);
p->validJD = 1;
}
@@ -11705,7 +13507,7 @@ static void setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
** The following are acceptable forms for the input string:
**
** YYYY-MM-DD HH:MM:SS.FFF +/-HH:MM
-** DDDD.DD
+** DDDD.DD
** now
**
** In the first form, the +/-HH:MM is always optional. The fractional
@@ -11715,11 +13517,11 @@ static void setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
** as there is a year and date.
*/
static int parseDateOrTime(
- sqlite3_context *context,
- const char *zDate,
+ sqlite3_context *context,
+ const char *zDate,
DateTime *p
){
- int isRealNum; /* Return from sqlite3IsNumber(). Not used */
+ double r;
if( parseYyyyMmDd(zDate,p)==0 ){
return 0;
}else if( parseHhMmSs(zDate, p)==0 ){
@@ -11727,9 +13529,7 @@ static int parseDateOrTime(
}else if( sqlite3StrICmp(zDate,"now")==0){
setDateTimeToCurrent(context, p);
return 0;
- }else if( sqlite3IsNumber(zDate, &isRealNum, SQLITE_UTF8) ){
- double r;
- getValue(zDate, &r);
+ }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){
p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
p->validJD = 1;
return 0;
@@ -11798,15 +13598,85 @@ static void clearYMD_HMS_TZ(DateTime *p){
p->validTZ = 0;
}
+/*
+** On recent Windows platforms, the localtime_s() function is available
+** as part of the "Secure CRT". It is essentially equivalent to
+** localtime_r() available under most POSIX platforms, except that the
+** order of the parameters is reversed.
+**
+** See http://msdn.microsoft.com/en-us/library/a442x3ye(VS.80).aspx.
+**
+** If the user has not indicated to use localtime_r() or localtime_s()
+** already, check for an MSVC build environment that provides
+** localtime_s().
+*/
+#if !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
/*
-** Compute the difference (in milliseconds)
-** between localtime and UTC (a.k.a. GMT)
-** for the time value p where p is in UTC.
+** 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 sqlite3_int64 localtimeOffset(DateTime *p){
+static int osLocaltime(time_t *t, struct tm *pTm){
+ int rc;
+#if (!defined(HAVE_LOCALTIME_R) || !HAVE_LOCALTIME_R) \
+ && (!defined(HAVE_LOCALTIME_S) || !HAVE_LOCALTIME_S)
+ 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
+/*
+** Compute the difference (in milliseconds) between localtime and UTC
+** (a.k.a. GMT) for the time value p where p is in UTC. If no error occurs,
+** return this value and set *pRc to SQLITE_OK.
+**
+** Or, if an error does occur, set *pRc to SQLITE_ERROR. The returned value
+** is undefined in this case.
+*/
+static sqlite3_int64 localtimeOffset(
+ DateTime *p, /* Date at which to calculate offset */
+ sqlite3_context *pCtx, /* Write error here if one occurs */
+ int *pRc /* OUT: Error code. SQLITE_OK or ERROR */
+){
DateTime x, y;
time_t t;
+ struct tm sLocal;
+
+ /* Initialize the contents of sLocal to avoid a compiler warning. */
+ memset(&sLocal, 0, sizeof(sLocal));
+
x = *p;
computeYMD_HMS(&x);
if( x.Y<1971 || x.Y>=2038 ){
@@ -11824,47 +13694,23 @@ static sqlite3_int64 localtimeOffset(DateTime *p){
x.validJD = 0;
computeJD(&x);
t = (time_t)(x.iJD/1000 - 21086676*(i64)10000);
-#ifdef HAVE_LOCALTIME_R
- {
- struct tm sLocal;
- localtime_r(&t, &sLocal);
- 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;
+ if( osLocaltime(&t, &sLocal) ){
+ sqlite3_result_error(pCtx, "local time unavailable", -1);
+ *pRc = SQLITE_ERROR;
+ return 0;
}
-#elif defined(HAVE_LOCALTIME_S) && HAVE_LOCALTIME_S
- {
- struct tm sLocal;
- localtime_s(&sLocal, &t);
- 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;
- }
-#else
- {
- struct tm *pTm;
- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
- pTm = localtime(&t);
- y.Y = pTm->tm_year + 1900;
- y.M = pTm->tm_mon + 1;
- y.D = pTm->tm_mday;
- y.h = pTm->tm_hour;
- y.m = pTm->tm_min;
- y.s = pTm->tm_sec;
- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
- }
-#endif
+ 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 */
@@ -11888,9 +13734,12 @@ static sqlite3_int64 localtimeOffset(DateTime *p){
** localtime
** utc
**
-** Return 0 on success and 1 if there is any kind of error.
+** 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(const char *zMod, DateTime *p){
+static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
int rc = 1;
int n;
double r;
@@ -11910,9 +13759,8 @@ static int parseModifier(const char *zMod, DateTime *p){
*/
if( strcmp(z, "localtime")==0 ){
computeJD(p);
- p->iJD += localtimeOffset(p);
+ p->iJD += localtimeOffset(p, pCtx, &rc);
clearYMD_HMS_TZ(p);
- rc = 0;
}
break;
}
@@ -11933,11 +13781,12 @@ static int parseModifier(const char *zMod, DateTime *p){
else if( strcmp(z, "utc")==0 ){
sqlite3_int64 c1;
computeJD(p);
- c1 = localtimeOffset(p);
- p->iJD -= c1;
- clearYMD_HMS_TZ(p);
- p->iJD += c1 - localtimeOffset(p);
- rc = 0;
+ 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;
@@ -11950,8 +13799,9 @@ static int parseModifier(const char *zMod, DateTime *p){
** 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 && getValue(&z[8],&r)>0
- && (n=(int)r)==r && n>=0 && r<7 ){
+ 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;
@@ -12006,8 +13856,11 @@ static int parseModifier(const char *zMod, DateTime *p){
case '8':
case '9': {
double rRounder;
- n = getValue(z, &r);
- assert( n>=1 );
+ 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
@@ -12092,9 +13945,9 @@ static int parseModifier(const char *zMod, DateTime *p){
** then assume a default value of "now" for argv[0].
*/
static int isDate(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv,
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv,
DateTime *p
){
int i;
@@ -12114,9 +13967,8 @@ static int isDate(
}
}
for(i=1; ipVfs, &rT);
-#ifndef SQLITE_OMIT_FLOATING_POINT
- t = 86400.0*(rT - 2440587.5) + 0.5;
-#else
- /* without floating point support, rT will have
- ** already lost fractional day precision.
- */
- t = 86400 * (rT - 2440587) - 43200;
-#endif
+ sqlite3OsCurrentTimeInt64(db->pVfs, &iT);
+ t = iT/1000 - 10000*(sqlite3_int64)21086676;
#ifdef HAVE_GMTIME_R
{
struct tm sNow;
@@ -12509,7 +14354,7 @@ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
** 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
+** The following functions are instrumented for malloc() failure
** testing:
**
** sqlite3OsOpen()
@@ -12519,8 +14364,10 @@ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
** sqlite3OsLock()
**
*/
-#if defined(SQLITE_TEST) && (SQLITE_OS_WIN==0)
- #define DO_OS_MALLOC_TEST(x) if (!x || !sqlite3IsMemJournal(x)) { \
+#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); \
@@ -12583,25 +14430,43 @@ SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){
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 */
+){
+ return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp);
+}
/*
** 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,
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ sqlite3_file *pFile,
+ int flags,
int *pFlagsOut
){
int rc;
DO_OS_MALLOC_TEST(0);
- /* 0x7f3f is a mask of SQLITE_OPEN_ flags that are valid to be passed
+ /* 0x87f3f 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 & 0x7f3f, pFlagsOut);
+ rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x87f7f, pFlagsOut);
assert( rc==SQLITE_OK || pFile->pMethods==0 );
return rc;
}
@@ -12609,18 +14474,18 @@ SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dir
return pVfs->xDelete(pVfs, zPath, dirSync);
}
SQLITE_PRIVATE int sqlite3OsAccess(
- sqlite3_vfs *pVfs,
- const char *zPath,
- int flags,
+ 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,
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int nPathOut,
char *zPathOut
){
zPathOut[0] = 0;
@@ -12646,20 +14511,34 @@ SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufO
SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
return pVfs->xSleep(pVfs, nMicro);
}
-SQLITE_PRIVATE int sqlite3OsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
- return pVfs->xCurrentTime(pVfs, pTimeOut);
+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,
+ sqlite3_vfs *pVfs,
+ const char *zFile,
+ sqlite3_file **ppFile,
int flags,
int *pOutFlags
){
int rc = SQLITE_NOMEM;
sqlite3_file *pFile;
- pFile = (sqlite3_file *)sqlite3Malloc(pVfs->szOsFile);
+ pFile = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile);
if( pFile ){
rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags);
if( rc!=SQLITE_OK ){
@@ -12795,17 +14674,17 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
**
*************************************************************************
**
-** This file contains code to support the concept of "benign"
+** 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).
+** 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
+** 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.
*/
@@ -13023,7 +14902,7 @@ static int sqlite3MemSize(void *pPrior){
static void *sqlite3MemRealloc(void *pPrior, int nByte){
sqlite3_int64 *p = (sqlite3_int64*)pPrior;
assert( pPrior!=0 && nByte>0 );
- nByte = ROUND8(nByte);
+ assert( nByte==ROUND8(nByte) ); /* EV: R-46199-30249 */
p--;
p = realloc(p, nByte+8 );
if( p ){
@@ -13123,6 +15002,7 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){
# define backtrace(A,B) 1
# define backtrace_symbols_fd(A,B,C)
#endif
+/* #include */
/*
** Each memory allocation looks like this:
@@ -13142,7 +15022,8 @@ struct MemBlockHdr {
struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */
char nBacktrace; /* Number of backtraces on this alloc */
char nBacktraceSlots; /* Available backtrace slots */
- short nTitle; /* Bytes of title; includes '\0' */
+ u8 nTitle; /* Bytes of title; includes '\0' */
+ u8 eType; /* Allocation type code */
int iForeGuard; /* Guard word for sanity */
};
@@ -13164,7 +15045,7 @@ struct MemBlockHdr {
** when this module is combined with other in the amalgamation.
*/
static struct {
-
+
/*
** Mutex to control access to the memory allocation subsystem.
*/
@@ -13175,7 +15056,7 @@ static struct {
*/
struct MemBlockHdr *pFirst;
struct MemBlockHdr *pLast;
-
+
/*
** The number of levels of backtrace to save in new allocations.
*/
@@ -13188,7 +15069,7 @@ static struct {
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.
*/
@@ -13247,7 +15128,7 @@ static struct MemBlockHdr *sqlite3MemsysGetHeader(void *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
+ ** to rounding up to an 8 byte boundary to ensure
** they haven't been overwritten.
*/
while( nReserve-- > p->iSize ) assert( pU8[nReserve]==0x65 );
@@ -13350,6 +15231,7 @@ static void *sqlite3MemMalloc(int nByte){
}
mem.pLast = pHdr;
pHdr->iForeGuard = FOREGUARD;
+ pHdr->eType = MEMTYPE_HEAP;
pHdr->nBacktraceSlots = mem.nBacktrace;
pHdr->nTitle = mem.nTitle;
if( mem.nBacktrace ){
@@ -13375,7 +15257,7 @@ static void *sqlite3MemMalloc(int nByte){
p = (void*)pInt;
}
sqlite3_mutex_leave(mem.mutex);
- return p;
+ return p;
}
/*
@@ -13385,7 +15267,7 @@ static void sqlite3MemFree(void *pPrior){
struct MemBlockHdr *pHdr;
void **pBt;
char *z;
- assert( sqlite3GlobalConfig.bMemstat || sqlite3GlobalConfig.bCoreMutex==0
+ assert( sqlite3GlobalConfig.bMemstat || sqlite3GlobalConfig.bCoreMutex==0
|| mem.mutex!=0 );
pHdr = sqlite3MemsysGetHeader(pPrior);
pBt = (void**)pHdr;
@@ -13411,15 +15293,15 @@ static void sqlite3MemFree(void *pPrior){
randomFill(z, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) +
pHdr->iSize + sizeof(int) + pHdr->nTitle);
free(z);
- sqlite3_mutex_leave(mem.mutex);
+ 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
+** 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.
*/
@@ -13427,6 +15309,7 @@ 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 ){
@@ -13457,6 +15340,62 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){
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.
+**
+** This routine is designed for use within an assert() statement, to
+** verify the type of an allocation. For example:
+**
+** 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.
+**
+** This routine is designed for use within an assert() statement, to
+** verify the type of an allocation. For example:
+**
+** assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) );
+*/
+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 rc;
+}
+
/*
** Set the number of backtrace levels kept for each allocation.
** A value of zero turns off backtracing. The number is always rounded
@@ -13496,7 +15435,7 @@ SQLITE_PRIVATE void sqlite3MemdebugSync(){
}
/*
-** Open the file indicated and write a log of all unfreed memory
+** Open the file indicated and write a log of all unfreed memory
** allocations into that log.
*/
SQLITE_PRIVATE void sqlite3MemdebugDump(const char *zFilename){
@@ -13513,7 +15452,7 @@ SQLITE_PRIVATE void sqlite3MemdebugDump(const char *zFilename){
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",
+ fprintf(out, "**** %lld bytes at %p from %s ****\n",
pHdr->iSize, &pHdr[1], pHdr->nTitle ? z : "???");
if( pHdr->nBacktrace ){
fflush(out);
@@ -13526,7 +15465,7 @@ SQLITE_PRIVATE void sqlite3MemdebugDump(const char *zFilename){
fprintf(out, "COUNTS:\n");
for(i=0; i= M*(1 + log2(n)/2) - n + 1
@@ -14296,7 +16235,7 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){
*/
/*
-** This version of the memory allocator is used only when
+** This version of the memory allocator is used only when
** SQLITE_ENABLE_MEMSYS5 is defined.
*/
#ifdef SQLITE_ENABLE_MEMSYS5
@@ -14341,7 +16280,7 @@ static SQLITE_WSD struct Mem5Global {
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.
*/
@@ -14358,7 +16297,7 @@ static SQLITE_WSD struct Mem5Global {
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.
@@ -14372,7 +16311,7 @@ static SQLITE_WSD struct Mem5Global {
*/
u8 *aCtrl;
-} mem5 = { 0 };
+} mem5;
/*
** Access the static variable through a macro for SQLITE_OMIT_WSD
@@ -14456,7 +16395,7 @@ static int memsys5Size(void *p){
/*
** Find the first entry on the freelist iLogsize. Unlink that
-** entry and return its index.
+** entry and return its index.
*/
static int memsys5UnlinkFirst(int iLogsize){
int i;
@@ -14549,7 +16488,7 @@ static void memsys5FreeUnsafe(void *pOld){
u32 size, iLogsize;
int iBlock;
- /* Set iBlock to the index of the block pointed to by pOld in
+ /* 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;
@@ -14608,7 +16547,7 @@ static void *memsys5Malloc(int nBytes){
p = memsys5MallocUnsafe(nBytes);
memsys5Leave();
}
- return (void*)p;
+ return (void*)p;
}
/*
@@ -14621,14 +16560,14 @@ static void memsys5Free(void *pPrior){
assert( pPrior!=0 );
memsys5Enter();
memsys5FreeUnsafe(pPrior);
- memsys5Leave();
+ memsys5Leave();
}
/*
** Change the size of an existing memory allocation.
**
** The outer layer memory allocator prevents this routine from
-** being called with pPrior==0.
+** 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
@@ -14640,7 +16579,7 @@ static void *memsys5Realloc(void *pPrior, int nBytes){
int nOld;
void *p;
assert( pPrior!=0 );
- assert( (nBytes&(nBytes-1))==0 );
+ assert( (nBytes&(nBytes-1))==0 ); /* EV: R-46199-30249 */
assert( nBytes>=0 );
if( nBytes==0 ){
return 0;
@@ -14687,7 +16626,7 @@ static int memsys5Roundup(int n){
*/
static int memsys5Log(int iValue){
int iLog;
- for(iLog=0; (1<mem5.szAtom ){
@@ -14762,7 +16702,7 @@ static void memsys5Shutdown(void *NotUsed){
#ifdef SQLITE_TEST
/*
-** Open the file indicated and write a log of all unfreed memory
+** Open the file indicated and write a log of all unfreed memory
** allocations into that log.
*/
SQLITE_PRIVATE void sqlite3Memsys5Dump(const char *zFilename){
@@ -14804,7 +16744,7 @@ SQLITE_PRIVATE void sqlite3Memsys5Dump(const char *zFilename){
#endif
/*
-** This routine is the only routine in this file with external
+** 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.
*/
@@ -14856,25 +16796,28 @@ static SQLITE_WSD int mutexIsInit = 0;
/*
** Initialize the mutex system.
*/
-SQLITE_PRIVATE int sqlite3MutexInit(void){
+SQLITE_PRIVATE int sqlite3MutexInit(void){
int rc = SQLITE_OK;
- if( sqlite3GlobalConfig.bCoreMutex ){
- 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 *pFrom = sqlite3DefaultMutex();
- sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;
+ 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;
- memcpy(pTo, pFrom, offsetof(sqlite3_mutex_methods, xMutexAlloc));
- memcpy(&pTo->xMutexFree, &pFrom->xMutexFree,
- sizeof(*pTo) - offsetof(sqlite3_mutex_methods, xMutexFree));
- pTo->xMutexAlloc = pFrom->xMutexAlloc;
+ if( sqlite3GlobalConfig.bCoreMutex ){
+ pFrom = sqlite3DefaultMutex();
+ }else{
+ pFrom = sqlite3NoopMutex();
}
- rc = sqlite3GlobalConfig.mutex.xMutexInit();
+ 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();
#ifdef SQLITE_DEBUG
GLOBAL(int, mutexIsInit) = 1;
@@ -14951,7 +16894,7 @@ SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){
/*
** The sqlite3_mutex_leave() routine exits a mutex that was previously
-** entered by the same thread. The behavior is undefined if the mutex
+** 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.
*/
@@ -15006,25 +16949,30 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){
** called correctly.
*/
+#ifndef SQLITE_MUTEX_OMIT
-#if defined(SQLITE_MUTEX_NOOP) && !defined(SQLITE_DEBUG)
+#ifndef SQLITE_DEBUG
/*
** Stub routines for all mutex methods.
**
** This routines provide no mutual exclusion or error checking.
*/
-static int noopMutexHeld(sqlite3_mutex *p){ return 1; }
-static int noopMutexNotheld(sqlite3_mutex *p){ return 1; }
static int noopMutexInit(void){ return SQLITE_OK; }
static int noopMutexEnd(void){ return SQLITE_OK; }
-static sqlite3_mutex *noopMutexAlloc(int id){ return (sqlite3_mutex*)8; }
-static void noopMutexFree(sqlite3_mutex *p){ return; }
-static void noopMutexEnter(sqlite3_mutex *p){ return; }
-static int noopMutexTry(sqlite3_mutex *p){ return SQLITE_OK; }
-static void noopMutexLeave(sqlite3_mutex *p){ return; }
+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; }
-SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
- static sqlite3_mutex_methods sMutex = {
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void){
+ static const sqlite3_mutex_methods sMutex = {
noopMutexInit,
noopMutexEnd,
noopMutexAlloc,
@@ -15033,15 +16981,15 @@ SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
noopMutexTry,
noopMutexLeave,
- noopMutexHeld,
- noopMutexNotheld
+ 0,
+ 0,
};
return &sMutex;
}
-#endif /* defined(SQLITE_MUTEX_NOOP) && !defined(SQLITE_DEBUG) */
+#endif /* !SQLITE_DEBUG */
-#if defined(SQLITE_MUTEX_NOOP) && defined(SQLITE_DEBUG)
+#ifdef SQLITE_DEBUG
/*
** In this implementation, error checking is provided for testing
** and debugging purposes. The mutexes still do not provide any
@@ -15051,19 +16999,21 @@ SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
/*
** The mutex object
*/
-struct sqlite3_mutex {
+typedef struct sqlite3_debug_mutex {
int id; /* The mutex type */
int cnt; /* Number of entries without a matching leave */
-};
+} sqlite3_debug_mutex;
/*
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
** intended for use inside assert() statements.
*/
-static int debugMutexHeld(sqlite3_mutex *p){
+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 *p){
+static int debugMutexNotheld(sqlite3_mutex *pX){
+ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
return p==0 || p->cnt==0;
}
@@ -15076,11 +17026,11 @@ static int debugMutexEnd(void){ return SQLITE_OK; }
/*
** 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.
+** that means that a mutex could not be allocated.
*/
static sqlite3_mutex *debugMutexAlloc(int id){
- static sqlite3_mutex aStatic[6];
- sqlite3_mutex *pNew = 0;
+ static sqlite3_debug_mutex aStatic[6];
+ sqlite3_debug_mutex *pNew = 0;
switch( id ){
case SQLITE_MUTEX_FAST:
case SQLITE_MUTEX_RECURSIVE: {
@@ -15099,13 +17049,14 @@ static sqlite3_mutex *debugMutexAlloc(int id){
break;
}
}
- return pNew;
+ return (sqlite3_mutex*)pNew;
}
/*
** This routine deallocates a previously allocated mutex.
*/
-static void debugMutexFree(sqlite3_mutex *p){
+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);
@@ -15122,12 +17073,14 @@ static void debugMutexFree(sqlite3_mutex *p){
** can enter. If the same thread tries to enter any other kind of mutex
** more than once, the behavior is undefined.
*/
-static void debugMutexEnter(sqlite3_mutex *p){
- assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p) );
+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 *p){
- assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p) );
+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;
}
@@ -15138,14 +17091,15 @@ static int debugMutexTry(sqlite3_mutex *p){
** is undefined if the mutex is not currently entered or
** is not currently allocated. SQLite will never do either.
*/
-static void debugMutexLeave(sqlite3_mutex *p){
- assert( debugMutexHeld(p) );
+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(p) );
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
}
-SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
- static sqlite3_mutex_methods sMutex = {
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void){
+ static const sqlite3_mutex_methods sMutex = {
debugMutexInit,
debugMutexEnd,
debugMutexAlloc,
@@ -15160,7 +17114,18 @@ SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
return &sMutex;
}
-#endif /* defined(SQLITE_MUTEX_NOOP) && defined(SQLITE_DEBUG) */
+#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_MUTEX_NOOP */
+#endif /* SQLITE_MUTEX_OMIT */
/************** End of mutex_noop.c ******************************************/
/************** Begin file mutex_os2.c ***************************************/
@@ -15196,11 +17161,16 @@ SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
struct sqlite3_mutex {
HMTX mutex; /* Mutex controlling the lock */
int id; /* Mutex type */
- int nRef; /* Number of references */
- TID owner; /* Thread holding this mutex */
+#ifdef SQLITE_DEBUG
+ int trace; /* True to trace changes */
+#endif
};
-#define OS2_MUTEX_INITIALIZER 0,0,0,0
+#ifdef SQLITE_DEBUG
+#define SQLITE3_MUTEX_INITIALIZER { 0, 0, 0 }
+#else
+#define SQLITE3_MUTEX_INITIALIZER { 0, 0 }
+#endif
/*
** Initialize and deinitialize the mutex subsystem.
@@ -15211,16 +17181,19 @@ static int os2MutexEnd(void){ return SQLITE_OK; }
/*
** 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.
+** 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:
**
**
-** - SQLITE_MUTEX_FAST 0
-**
- SQLITE_MUTEX_RECURSIVE 1
-**
- SQLITE_MUTEX_STATIC_MASTER 2
-**
- SQLITE_MUTEX_STATIC_MEM 3
-**
- SQLITE_MUTEX_STATIC_PRNG 4
+**
- SQLITE_MUTEX_FAST
+**
- SQLITE_MUTEX_RECURSIVE
+**
- SQLITE_MUTEX_STATIC_MASTER
+**
- SQLITE_MUTEX_STATIC_MEM
+**
- SQLITE_MUTEX_STATIC_MEM2
+**
- SQLITE_MUTEX_STATIC_PRNG
+**
- SQLITE_MUTEX_STATIC_LRU
+**
- SQLITE_MUTEX_STATIC_LRU2
**
**
** The first two constants cause sqlite3_mutex_alloc() to create
@@ -15234,7 +17207,7 @@ static int os2MutexEnd(void){ return SQLITE_OK; }
** 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. Three static mutexes are
+** 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
@@ -15264,13 +17237,13 @@ static sqlite3_mutex *os2MutexAlloc(int iType){
}
default: {
static volatile int isInit = 0;
- static sqlite3_mutex staticMutexes[] = {
- { OS2_MUTEX_INITIALIZER, },
- { OS2_MUTEX_INITIALIZER, },
- { OS2_MUTEX_INITIALIZER, },
- { OS2_MUTEX_INITIALIZER, },
- { OS2_MUTEX_INITIALIZER, },
- { OS2_MUTEX_INITIALIZER, },
+ static sqlite3_mutex staticMutexes[6] = {
+ SQLITE3_MUTEX_INITIALIZER,
+ SQLITE3_MUTEX_INITIALIZER,
+ SQLITE3_MUTEX_INITIALIZER,
+ SQLITE3_MUTEX_INITIALIZER,
+ SQLITE3_MUTEX_INITIALIZER,
+ SQLITE3_MUTEX_INITIALIZER,
};
if ( !isInit ){
APIRET rc;
@@ -15316,9 +17289,14 @@ static sqlite3_mutex *os2MutexAlloc(int iType){
** SQLite is careful to deallocate every mutex that it allocates.
*/
static void os2MutexFree(sqlite3_mutex *p){
- if( p==0 ) return;
- assert( p->nRef==0 );
+#ifdef SQLITE_DEBUG
+ TID tid;
+ PID pid;
+ ULONG ulCount;
+ DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
+ assert( ulCount==0 );
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
+#endif
DosCloseMutexSem( p->mutex );
sqlite3_free( p );
}
@@ -15333,26 +17311,29 @@ static int os2MutexHeld(sqlite3_mutex *p){
PID pid;
ULONG ulCount;
PTIB ptib;
- if( p!=0 ) {
- DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
- } else {
- DosGetInfoBlocks(&ptib, NULL);
- tid = ptib->tib_ptib2->tib2_ultid;
- }
- return p==0 || (p->nRef!=0 && p->owner==tid);
+ DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
+ if( ulCount==0 || ( ulCount>1 && p->id!=SQLITE_MUTEX_RECURSIVE ) )
+ return 0;
+ DosGetInfoBlocks(&ptib, NULL);
+ return tid==ptib->tib_ptib2->tib2_ultid;
}
static int os2MutexNotheld(sqlite3_mutex *p){
TID tid;
PID pid;
ULONG ulCount;
PTIB ptib;
- if( p!= 0 ) {
- DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
- } else {
- DosGetInfoBlocks(&ptib, NULL);
- tid = ptib->tib_ptib2->tib2_ultid;
- }
- return p==0 || p->nRef==0 || p->owner!=tid;
+ DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
+ if( ulCount==0 )
+ return 1;
+ DosGetInfoBlocks(&ptib, NULL);
+ return tid!=ptib->tib_ptib2->tib2_ultid;
+}
+static void os2MutexTrace(sqlite3_mutex *p, char *pAction){
+ TID tid;
+ PID pid;
+ ULONG ulCount;
+ DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
+ printf("%s mutex %p (%d) with nRef=%ld\n", pAction, (void*)p, p->trace, ulCount);
}
#endif
@@ -15368,32 +17349,21 @@ static int os2MutexNotheld(sqlite3_mutex *p){
** more than once, the behavior is undefined.
*/
static void os2MutexEnter(sqlite3_mutex *p){
- TID tid;
- PID holder1;
- ULONG holder2;
- if( p==0 ) return;
assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) );
DosRequestMutexSem(p->mutex, SEM_INDEFINITE_WAIT);
- DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2);
- p->owner = tid;
- p->nRef++;
+#ifdef SQLITE_DEBUG
+ if( p->trace ) os2MutexTrace(p, "enter");
+#endif
}
static int os2MutexTry(sqlite3_mutex *p){
- int rc;
- TID tid;
- PID holder1;
- ULONG holder2;
- if( p==0 ) return SQLITE_OK;
+ int rc = SQLITE_BUSY;
assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) );
- if( DosRequestMutexSem(p->mutex, SEM_IMMEDIATE_RETURN) == NO_ERROR) {
- DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2);
- p->owner = tid;
- p->nRef++;
+ if( DosRequestMutexSem(p->mutex, SEM_IMMEDIATE_RETURN) == NO_ERROR ) {
rc = SQLITE_OK;
- } else {
- rc = SQLITE_BUSY;
+#ifdef SQLITE_DEBUG
+ if( p->trace ) os2MutexTrace(p, "try");
+#endif
}
-
return rc;
}
@@ -15404,20 +17374,15 @@ static int os2MutexTry(sqlite3_mutex *p){
** is not currently allocated. SQLite will never do either.
*/
static void os2MutexLeave(sqlite3_mutex *p){
- TID tid;
- PID holder1;
- ULONG holder2;
- if( p==0 ) return;
- assert( p->nRef>0 );
- DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2);
- assert( p->owner==tid );
- p->nRef--;
- assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
+ assert( os2MutexHeld(p) );
DosReleaseMutexSem(p->mutex);
+#ifdef SQLITE_DEBUG
+ if( p->trace ) os2MutexTrace(p, "leave");
+#endif
}
-SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
- static sqlite3_mutex_methods sMutex = {
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
+ static const sqlite3_mutex_methods sMutex = {
os2MutexInit,
os2MutexEnd,
os2MutexAlloc,
@@ -15428,6 +17393,9 @@ SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
#ifdef SQLITE_DEBUG
os2MutexHeld,
os2MutexNotheld
+#else
+ 0,
+ 0
#endif
};
@@ -15462,23 +17430,33 @@ SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
#include
+/*
+** 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.
+*/
+#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 */
- int nRef; /* Number of entrances */
- pthread_t owner; /* Thread that is within this mutex */
-#ifdef SQLITE_DEBUG
+ volatile int nRef; /* Number of entrances */
+ volatile pthread_t owner; /* Thread that is within this mutex */
int trace; /* True to trace changes */
#endif
};
-#ifdef SQLITE_DEBUG
+#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, 0, 0, (pthread_t)0 }
+#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
#endif
/*
@@ -15487,7 +17465,7 @@ struct sqlite3_mutex {
** 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
+** 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.
@@ -15527,7 +17505,7 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
** SQLITE_MUTEX_STATIC_MEM2
** SQLITE_MUTEX_STATIC_PRNG
** SQLITE_MUTEX_STATIC_LRU
-** SQLITE_MUTEX_STATIC_LRU2
+** SQLITE_MUTEX_STATIC_PMEM
**
**
** The first two constants cause sqlite3_mutex_alloc() to create
@@ -15550,7 +17528,7 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
**
** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
-** returns a different mutex on every call. But for the static
+** returns a different mutex on every call. But for the static
** mutex types, the same mutex is returned on every call that has
** the same type number.
*/
@@ -15580,14 +17558,18 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
pthread_mutex_init(&p->mutex, &recursiveAttr);
pthread_mutexattr_destroy(&recursiveAttr);
#endif
+#if SQLITE_MUTEX_NREF
p->id = iType;
+#endif
}
break;
}
case SQLITE_MUTEX_FAST: {
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
+#if SQLITE_MUTEX_NREF
p->id = iType;
+#endif
pthread_mutex_init(&p->mutex, 0);
}
break;
@@ -15596,7 +17578,9 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
assert( iType-2 >= 0 );
assert( iType-2 < ArraySize(staticMutexes) );
p = &staticMutexes[iType-2];
+#if SQLITE_MUTEX_NREF
p->id = iType;
+#endif
break;
}
}
@@ -15636,7 +17620,7 @@ static void pthreadMutexEnter(sqlite3_mutex *p){
** 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
+ ** 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.
@@ -15656,9 +17640,12 @@ static void pthreadMutexEnter(sqlite3_mutex *p){
/* 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
#ifdef SQLITE_DEBUG
if( p->trace ){
@@ -15676,7 +17663,7 @@ static int pthreadMutexTry(sqlite3_mutex *p){
** 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
+ ** 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.
@@ -15699,8 +17686,10 @@ static int pthreadMutexTry(sqlite3_mutex *p){
/* 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{
rc = SQLITE_BUSY;
@@ -15723,7 +17712,10 @@ static int pthreadMutexTry(sqlite3_mutex *p){
*/
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
@@ -15741,8 +17733,8 @@ static void pthreadMutexLeave(sqlite3_mutex *p){
#endif
}
-SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
- static sqlite3_mutex_methods sMutex = {
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
+ static const sqlite3_mutex_methods sMutex = {
pthreadMutexInit,
pthreadMutexEnd,
pthreadMutexAlloc,
@@ -15792,9 +17784,9 @@ SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
struct sqlite3_mutex {
CRITICAL_SECTION mutex; /* Mutex controlling the lock */
int id; /* Mutex type */
- int nRef; /* Number of enterances */
- DWORD owner; /* Thread holding this mutex */
#ifdef SQLITE_DEBUG
+ volatile int nRef; /* Number of enterances */
+ volatile DWORD owner; /* Thread holding this mutex */
int trace; /* True to trace changes */
#endif
};
@@ -15802,7 +17794,7 @@ struct sqlite3_mutex {
#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, 0L, (DWORD)0 }
+#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 }
#endif
/*
@@ -15817,9 +17809,9 @@ struct sqlite3_mutex {
** the LockFileEx() API.
**
** mutexIsNT() is only used for the TryEnterCriticalSection() API call,
-** which is only available if your application was compiled with
+** 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
+** call to TryEnterCriticalSection() is #ifdef'ed out, so #ifdef
** this out as well.
*/
#if 0
@@ -15851,7 +17843,7 @@ static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){
return p->nRef==0 || p->owner!=tid;
}
static int winMutexNotheld(sqlite3_mutex *p){
- DWORD tid = GetCurrentThreadId();
+ DWORD tid = GetCurrentThreadId();
return winMutexNotheld2(p, tid);
}
#endif
@@ -15876,7 +17868,7 @@ static int winMutex_isInit = 0;
*/
static long winMutex_lock = 0;
-static int winMutexInit(void){
+static int winMutexInit(void){
/* The first to increment to 1 does actual initialization */
if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){
int i;
@@ -15890,11 +17882,11 @@ static int winMutexInit(void){
Sleep(1);
}
}
- return SQLITE_OK;
+ return SQLITE_OK;
}
-static int winMutexEnd(void){
- /* The first to decrement to 0 does actual shutdown
+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 ){
@@ -15905,7 +17897,7 @@ static int winMutexEnd(void){
winMutex_isInit = 0;
}
}
- return SQLITE_OK;
+ return SQLITE_OK;
}
/*
@@ -15923,7 +17915,7 @@ static int winMutexEnd(void){
** SQLITE_MUTEX_STATIC_MEM2
** SQLITE_MUTEX_STATIC_PRNG
** SQLITE_MUTEX_STATIC_LRU
-** SQLITE_MUTEX_STATIC_LRU2
+** SQLITE_MUTEX_STATIC_PMEM
**
**
** The first two constants cause sqlite3_mutex_alloc() to create
@@ -15946,7 +17938,7 @@ static int winMutexEnd(void){
**
** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
-** returns a different mutex on every call. But for the static
+** returns a different mutex on every call. But for the static
** mutex types, the same mutex is returned on every call that has
** the same type number.
*/
@@ -15957,8 +17949,10 @@ static sqlite3_mutex *winMutexAlloc(int iType){
case SQLITE_MUTEX_FAST:
case SQLITE_MUTEX_RECURSIVE: {
p = sqlite3MallocZero( sizeof(*p) );
- if( p ){
+ if( p ){
+#ifdef SQLITE_DEBUG
p->id = iType;
+#endif
InitializeCriticalSection(&p->mutex);
}
break;
@@ -15968,7 +17962,9 @@ static sqlite3_mutex *winMutexAlloc(int iType){
assert( iType-2 >= 0 );
assert( iType-2 < ArraySize(winMutex_staticMutexes) );
p = &winMutex_staticMutexes[iType-2];
+#ifdef SQLITE_DEBUG
p->id = iType;
+#endif
break;
}
}
@@ -15983,7 +17979,7 @@ static sqlite3_mutex *winMutexAlloc(int iType){
*/
static void winMutexFree(sqlite3_mutex *p){
assert( p );
- assert( p->nRef==0 );
+ assert( p->nRef==0 && p->owner==0 );
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
DeleteCriticalSection(&p->mutex);
sqlite3_free(p);
@@ -16001,12 +17997,15 @@ static void winMutexFree(sqlite3_mutex *p){
** more than once, the behavior is undefined.
*/
static void winMutexEnter(sqlite3_mutex *p){
- DWORD tid = GetCurrentThreadId();
- assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
- EnterCriticalSection(&p->mutex);
- p->owner = tid;
- p->nRef++;
#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);
}
@@ -16014,14 +18013,14 @@ static void winMutexEnter(sqlite3_mutex *p){
}
static int winMutexTry(sqlite3_mutex *p){
#ifndef NDEBUG
- DWORD tid = GetCurrentThreadId();
+ 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.
+ ** fail.
**
** The TryEnterCriticalSection() interface is only available on WinNT.
** And some windows compilers complain if you try to use it without
@@ -16040,7 +18039,7 @@ static int winMutexTry(sqlite3_mutex *p){
#endif
#ifdef SQLITE_DEBUG
if( rc==SQLITE_OK && p->trace ){
- printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
+ printf("try mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
}
#endif
return rc;
@@ -16055,11 +18054,12 @@ static int winMutexTry(sqlite3_mutex *p){
static void winMutexLeave(sqlite3_mutex *p){
#ifndef NDEBUG
DWORD tid = GetCurrentThreadId();
-#endif
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 ){
@@ -16068,8 +18068,8 @@ static void winMutexLeave(sqlite3_mutex *p){
#endif
}
-SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
- static sqlite3_mutex_methods sMutex = {
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
+ static const sqlite3_mutex_methods sMutex = {
winMutexInit,
winMutexEnd,
winMutexAlloc,
@@ -16106,46 +18106,7 @@ SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
**
** Memory allocation functions used throughout sqlite.
*/
-
-/*
-** 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);
-}
-
-/*
-** Set the soft heap-size limit for the library. Passing a zero or
-** negative value indicates no limit.
-*/
-SQLITE_API void sqlite3_soft_heap_limit(int n){
- sqlite3_uint64 iLimit;
- int overage;
- if( n<0 ){
- iLimit = 0;
- }else{
- iLimit = n;
- }
-#ifndef SQLITE_OMIT_AUTOINIT
- sqlite3_initialize();
-#endif
- if( iLimit>0 ){
- sqlite3MemoryAlarm(softHeapLimitEnforcer, 0, iLimit);
- }else{
- sqlite3MemoryAlarm(0, 0, 0);
- }
- overage = (int)(sqlite3_memory_used() - (i64)n);
- if( overage>0 ){
- sqlite3_release_memory(overage);
- }
-}
+/* #include */
/*
** Attempt to release up to n bytes of non-essential memory currently
@@ -16154,23 +18115,28 @@ SQLITE_API void sqlite3_soft_heap_limit(int n){
*/
SQLITE_API int sqlite3_release_memory(int n){
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
- int nRet = 0;
- nRet += sqlite3PcacheReleaseMemory(n-nRet);
- return nRet;
+ 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 SQLITE_OK;
+ return 0;
#endif
}
+/*
+** An instance of the following object records the location of
+** each unused scratch buffer.
+*/
+typedef struct ScratchFreeslot {
+ struct ScratchFreeslot *pNext; /* Next unused scratch buffer */
+} ScratchFreeslot;
+
/*
** State information local to the memory allocation subsystem.
*/
static SQLITE_WSD struct Mem0Global {
- /* Number of free pages for scratch and page-cache memory */
- u32 nScratchFree;
- u32 nPageFree;
-
sqlite3_mutex *mutex; /* Mutex to serialize access */
/*
@@ -16184,16 +18150,99 @@ static SQLITE_WSD struct Mem0Global {
void *alarmArg;
/*
- ** Pointers to the end of sqlite3GlobalConfig.pScratch and
- ** sqlite3GlobalConfig.pPage to a block of memory that records
- ** which pages are available.
+ ** 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.
*/
- u32 *aScratchFree;
- u32 *aPageFree;
+ 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)
+/*
+** 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);
+}
+
+/*
+** Change the alarm callback
+*/
+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;
+}
+
+#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
+
+/*
+** 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
+ sqlite3_initialize();
+#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);
+ }
+ 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);
+}
+
/*
** Initialize the memory allocation subsystem.
*/
@@ -16206,36 +18255,45 @@ SQLITE_PRIVATE int sqlite3MallocInit(void){
mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
}
if( sqlite3GlobalConfig.pScratch && sqlite3GlobalConfig.szScratch>=100
- && sqlite3GlobalConfig.nScratch>=0 ){
- int i;
- sqlite3GlobalConfig.szScratch = ROUNDDOWN8(sqlite3GlobalConfig.szScratch-4);
- mem0.aScratchFree = (u32*)&((char*)sqlite3GlobalConfig.pScratch)
- [sqlite3GlobalConfig.szScratch*sqlite3GlobalConfig.nScratch];
- for(i=0; i0 ){
+ 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; ipNext = (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;
}
- if( sqlite3GlobalConfig.pPage && sqlite3GlobalConfig.szPage>=512
- && sqlite3GlobalConfig.nPage>=1 ){
- int i;
- int overhead;
- int sz = ROUNDDOWN8(sqlite3GlobalConfig.szPage);
- int n = sqlite3GlobalConfig.nPage;
- overhead = (4*n + sz - 1)/sz;
- sqlite3GlobalConfig.nPage -= overhead;
- mem0.aPageFree = (u32*)&((char*)sqlite3GlobalConfig.pPage)
- [sqlite3GlobalConfig.szPage*sqlite3GlobalConfig.nPage];
- for(i=0; i= mem0.alarmThreshold ){
+ if( nUsed >= mem0.alarmThreshold - nFull ){
+ mem0.nearlyFull = 1;
sqlite3MallocAlarm(nFull);
+ }else{
+ mem0.nearlyFull = 0;
}
}
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;
@@ -16354,7 +18388,9 @@ static int mallocWithAlarm(int n, void **pp){
*/
SQLITE_PRIVATE void *sqlite3Malloc(int n){
void *p;
- if( n<=0 || n>=0x7fffff00 ){
+ 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
@@ -16368,6 +18404,7 @@ SQLITE_PRIVATE void *sqlite3Malloc(int n){
}else{
p = sqlite3GlobalConfig.m.xMalloc(n);
}
+ assert( EIGHT_BYTE_ALIGNMENT(p) ); /* IMP: R-04675-44850 */
return p;
}
@@ -16406,88 +18443,79 @@ SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){
void *p;
assert( n>0 );
-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
- /* Verify that no more than one 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==0 );
-#endif
-
- if( 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);
- n = mallocWithAlarm(n, &p);
- if( p ) sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, n);
sqlite3_mutex_leave(mem0.mutex);
}else{
- p = sqlite3GlobalConfig.m.xMalloc(n);
+ 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);
}
+ assert( sqlite3_mutex_notheld(mem0.mutex) );
+
+
#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
- scratchAllocOut = p!=0;
+ /* 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 one scratch allocation per thread
+ /* 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 = 0;
+ assert( scratchAllocOut>=1 && scratchAllocOut<=2 );
+ scratchAllocOut--;
#endif
- if( sqlite3GlobalConfig.pScratch==0
- || p=(void*)mem0.aScratchFree ){
+ if( p>=sqlite3GlobalConfig.pScratch && ppNext = 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);
}
- }else{
- int i;
- i = (int)((u8*)p - (u8*)sqlite3GlobalConfig.pScratch);
- i /= sqlite3GlobalConfig.szScratch;
- assert( i>=0 && i=db->lookaside.pStart && plookaside.pEnd;
+ return p && p>=db->lookaside.pStart && plookaside.pEnd;
}
#else
#define isLookaside(A,B) 0
@@ -16508,13 +18536,18 @@ static int isLookaside(sqlite3 *db, void *p){
** 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( isLookaside(db, p) ){
+ 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);
}
}
@@ -16523,10 +18556,13 @@ SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
** Free memory previously obtained from sqlite3Malloc().
*/
SQLITE_API void sqlite3_free(void *p){
- if( p==0 ) return;
+ 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{
@@ -16540,27 +18576,37 @@ SQLITE_API void sqlite3_free(void *p){
*/
SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
assert( db==0 || sqlite3_mutex_held(db->mutex) );
- if( isLookaside(db, p) ){
- LookasideSlot *pBuf = (LookasideSlot*)p;
- pBuf->pNext = db->lookaside.pFree;
- db->lookaside.pFree = pBuf;
- db->lookaside.nOut--;
- }else{
- sqlite3_free(p);
+ if( db ){
+ if( db->pnBytesFreed ){
+ *db->pnBytesFreed += sqlite3DbMallocSize(db, p);
+ return;
+ }
+ if( isLookaside(db, p) ){
+ LookasideSlot *pBuf = (LookasideSlot*)p;
+ 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);
}
/*
** Change the size of an existing memory allocation
*/
SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){
- int nOld, nNew;
+ int nOld, nNew, nDiff;
void *pNew;
if( pOld==0 ){
- return sqlite3Malloc(nBytes);
+ return sqlite3Malloc(nBytes); /* IMP: R-28354-25769 */
}
if( nBytes<=0 ){
- sqlite3_free(pOld);
+ sqlite3_free(pOld); /* IMP: R-31593-10574 */
return 0;
}
if( nBytes>=0x7fffff00 ){
@@ -16568,16 +18614,22 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){
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);
- if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nNew-nOld >=
- mem0.alarmThreshold ){
- sqlite3MallocAlarm(nNew-nOld);
+ 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);
@@ -16591,6 +18643,7 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){
}else{
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
}
+ assert( EIGHT_BYTE_ALIGNMENT(pNew) ); /* IMP: R-04675-44850 */
return pNew;
}
@@ -16608,7 +18661,7 @@ SQLITE_API void *sqlite3_realloc(void *pOld, int n){
/*
** Allocate and zero memory.
-*/
+*/
SQLITE_PRIVATE void *sqlite3MallocZero(int n){
void *p = sqlite3Malloc(n);
if( p ){
@@ -16650,20 +18703,27 @@ SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, int n){
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 && n<=db->lookaside.sz
- && (pBuf = db->lookaside.pFree)!=0 ){
- db->lookaside.pFree = pBuf->pNext;
- db->lookaside.nOut++;
- if( db->lookaside.nOut>db->lookaside.mxOut ){
- db->lookaside.mxOut = db->lookaside.nOut;
+ 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;
}
- return (void*)pBuf;
}
}
#else
@@ -16675,6 +18735,8 @@ SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, int n){
if( !p && db ){
db->mallocFailed = 1;
}
+ sqlite3MemdebugSetType(p, MEMTYPE_DB |
+ ((db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
return p;
}
@@ -16700,10 +18762,16 @@ SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){
sqlite3DbFree(db, p);
}
}else{
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) );
+ 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;
@@ -16723,9 +18791,9 @@ SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, int n){
}
/*
-** Make a copy of a string in memory obtained from sqliteMalloc(). These
+** 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
+** 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.
*/
@@ -16775,13 +18843,13 @@ SQLITE_PRIVATE void sqlite3SetString(char **pz, sqlite3 *db, const char *zFormat
/*
-** This function must be called before exiting any API function (i.e.
+** 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.
+** 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())
@@ -16789,7 +18857,7 @@ SQLITE_PRIVATE void sqlite3SetString(char **pz, sqlite3 *db, const char *zFormat
*/
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
+ ** 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) );
@@ -17082,7 +19150,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
break;
}
/* Find out what flags are present */
- flag_leftjustify = flag_plussign = flag_blanksign =
+ flag_leftjustify = flag_plussign = flag_blanksign =
flag_alternateform = flag_altform2 = flag_zeropad = 0;
done = 0;
do{
@@ -17204,7 +19272,11 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
v = va_arg(ap,int);
}
if( v<0 ){
- longvalue = -v;
+ if( v==SMALLEST_INT64 ){
+ longvalue = ((u64)1)<<63;
+ }else{
+ longvalue = -v;
+ }
prefix = '-';
}else{
longvalue = v;
@@ -17567,6 +19639,7 @@ SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
return;
}
}else{
+ char *zOld = (p->zText==p->zBase ? 0 : p->zText);
i64 szNew = p->nChar;
szNew += N + 1;
if( szNew > p->mxAlloc ){
@@ -17576,10 +19649,13 @@ SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
}else{
p->nAlloc = (int)szNew;
}
- zNew = sqlite3DbMallocRaw(p->db, p->nAlloc );
+ if( p->useMalloc==1 ){
+ zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
+ }else{
+ zNew = sqlite3_realloc(zOld, p->nAlloc);
+ }
if( zNew ){
- memcpy(zNew, p->zText, p->nChar);
- sqlite3StrAccumReset(p);
+ if( zOld==0 ) memcpy(zNew, p->zText, p->nChar);
p->zText = zNew;
}else{
p->mallocFailed = 1;
@@ -17601,7 +19677,11 @@ SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){
if( p->zText ){
p->zText[p->nChar] = 0;
if( p->useMalloc && p->zText==p->zBase ){
- p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
+ 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{
@@ -17617,7 +19697,11 @@ SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){
*/
SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){
if( p->zText!=p->zBase ){
- sqlite3DbFree(p->db, p->zText);
+ if( p->useMalloc==1 ){
+ sqlite3DbFree(p->db, p->zText);
+ }else{
+ sqlite3_free(p->zText);
+ }
}
p->zText = 0;
}
@@ -17699,6 +19783,7 @@ SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){
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;
@@ -17725,21 +19810,28 @@ SQLITE_API char *sqlite3_mprintf(const char *zFormat, ...){
** 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.
+**
+** 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.
+**
+** sqlite3_vsnprintf() is the varargs version.
*/
+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;
- StrAccum acc;
-
- if( n<=0 ){
- return zBuf;
- }
- sqlite3StrAccumInit(&acc, zBuf, n, 0);
- acc.useMalloc = 0;
va_start(ap,zFormat);
- sqlite3VXPrintf(&acc, 0, zFormat, ap);
+ z = sqlite3_vsnprintf(n, zBuf, zFormat, ap);
va_end(ap);
- z = sqlite3StrAccumFinish(&acc);
return z;
}
@@ -17968,7 +20060,7 @@ SQLITE_PRIVATE void sqlite3PrngResetState(void){
** May you share freely, never taking more than you give.
**
*************************************************************************
-** This file contains routines used to translate between UTF-8,
+** This file contains routines used to translate between UTF-8,
** UTF-16, UTF-16BE, and UTF-16LE.
**
** Notes on UTF-8:
@@ -17992,429 +20084,7 @@ SQLITE_PRIVATE void sqlite3PrngResetState(void){
** 0xfe 0xff big-endian utf-16 follows
**
*/
-/************** Include vdbeInt.h in the middle of utf.c *********************/
-/************** Begin file vdbeInt.h *****************************************/
-/*
-** 2003 September 6
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This is the header file for information that is private to the
-** VDBE. This information used to all be at the top of the single
-** source code file "vdbe.c". When that file became too big (over
-** 6000 lines long) it was split up into several smaller files and
-** this header information was factored out.
-*/
-#ifndef _VDBEINT_H_
-#define _VDBEINT_H_
-
-/*
-** SQL is translated into a sequence of instructions to be
-** executed by a virtual machine. Each instruction is an instance
-** of the following structure.
-*/
-typedef struct VdbeOp Op;
-
-/*
-** Boolean values
-*/
-typedef unsigned char Bool;
-
-/*
-** 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.
-**
-** If the VdbeCursor.isTriggerRow flag is set it means that this cursor is
-** really a single row that represents the NEW or OLD pseudo-table of
-** a row trigger. The data for the row is stored in VdbeCursor.pData and
-** the rowid is in VdbeCursor.iKey.
-*/
-struct VdbeCursor {
- BtCursor *pCursor; /* The cursor structure of the backend */
- int iDb; /* Index of cursor database in db->aDb[] (or -1) */
- i64 lastRowid; /* Last rowid from a Next or NextIdx operation */
- 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 */
- i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
- Btree *pBt; /* Separate file holding temporary table */
- int pseudoTableReg; /* Register holding pseudotable content. */
- KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
- int nField; /* Number of fields in the header */
- i64 seqCount; /* Sequence counter */
- sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
- const sqlite3_module *pModule; /* Module for cursor pVtabCursor */
-
- /* 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;
-
-/*
-** 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.
-**
-** Frames are stored in a linked list headed at Vdbe.pParent. Vdbe.pParent
-** is the parent of the current frame, or zero if the current frame
-** is the main Vdbe program.
-*/
-typedef struct VdbeFrame VdbeFrame;
-struct VdbeFrame {
- Vdbe *v; /* VM this frame belongs to */
- int pc; /* Program Counter */
- Op *aOp; /* Program instructions */
- int nOp; /* Size of aOp array */
- Mem *aMem; /* Array of memory cells */
- int nMem; /* Number of entries in aMem */
- VdbeCursor **apCsr; /* Element of Vdbe cursors */
- u16 nCursor; /* Number of entries in apCsr */
- void *token; /* Copy of SubProgram.token */
- int nChildMem; /* Number of memory cells for child frame */
- int nChildCsr; /* Number of cursors for child frame */
- i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
- int nChange; /* Statement changes (Vdbe.nChanges) */
- VdbeFrame *pParent; /* Parent of this frame */
-};
-
-#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
-
-/*
-** A value for VdbeCursor.cacheValid that means the cache is always invalid.
-*/
-#define CACHE_STALE 0
-
-/*
-** Internally, the vdbe manipulates nearly all SQL values as Mem
-** structures. Each Mem struct may cache multiple representations (string,
-** integer etc.) of the same value. A value (and therefore Mem structure)
-** has the following properties:
-**
-** Each value has a manifest type. The manifest type of the value stored
-** in a Mem struct is returned by the MemType(Mem*) macro. The type is
-** one of SQLITE_NULL, SQLITE_INTEGER, SQLITE_REAL, SQLITE_TEXT or
-** SQLITE_BLOB.
-*/
-struct Mem {
- union {
- i64 i; /* Integer value. */
- 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;
- double r; /* Real value */
- sqlite3 *db; /* The associated database connection */
- char *z; /* String or BLOB value */
- 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 */
- void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
- char *zMalloc; /* Dynamic buffer allocated by sqlite3_malloc() */
-};
-
-/* One or more of the following flags are set to indicate the validOK
-** 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.
-**
-** Multiple of these values can appear in Mem.flags. But only one
-** at a time can appear in Mem.type.
-*/
-#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_TypeMask 0x00ff /* Mask of type bits */
-
-/* Whenever Mem contains a valid string or blob representation, one of
-** the following flags must be set to determine the memory management
-** policy for Mem.z. The MEM_Term flag tells us whether or not the
-** string is \000 or \u0000 terminated
-*/
-#define MEM_Term 0x0200 /* String rep is nul terminated */
-#define MEM_Dyn 0x0400 /* Need to call 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
-
-
-/*
-** 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)
-
-
-/* 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 */
-};
-
-/*
-** 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 */
- int isError; /* Error code returned by the function. */
- CollSeq *pColl; /* Collating sequence */
-};
-
-/*
-** A Set structure is used for quick testing to see if a value
-** is part of a small set. Sets are used to implement code like
-** this:
-** x.y IN ('hi','hoo','hum')
-*/
-typedef struct Set Set;
-struct Set {
- Hash hash; /* A set is just a hash table */
- HashElem *prev; /* Previously accessed hash elemen */
-};
-
-/*
-** 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_compile()
-** 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 */
- Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
- int nOp; /* Number of instructions in the program */
- int nOpAlloc; /* Number of slots allocated for aOp[] */
- Op *aOp; /* Space to hold the virtual machine's program */
- int nLabel; /* Number of labels used */
- int nLabelAlloc; /* Number of slots allocated in aLabel[] */
- int *aLabel; /* Space to hold the labels */
- Mem **apArg; /* Arguments to currently executing user function */
- Mem *aColName; /* Column names to return */
- Mem *pResultSet; /* Pointer to an array of results */
- u16 nResColumn; /* Number of columns in one row of the result set */
- u16 nCursor; /* Number of slots in apCsr[] */
- VdbeCursor **apCsr; /* One element of this array for each open cursor */
- u8 errorAction; /* Recovery action to do in case of an error */
- u8 okVar; /* True if azVar[] has been initialized */
- ynVar nVar; /* Number of entries in aVar[] */
- Mem *aVar; /* Values for the OP_Variable opcode. */
- char **azVar; /* Name of variables */
- u32 magic; /* Magic number for sanity checking */
- int nMem; /* Number of memory locations currently allocated */
- Mem *aMem; /* The memory locations */
- u32 cacheCtr; /* VdbeCursor row cache generation counter */
- int pc; /* The program counter */
- int rc; /* Value to return */
- char *zErrMsg; /* Error message written here */
- 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() */
- int nChange; /* Number of db changes made since last reset */
- int btreeMask; /* Bitmask of db->aDb[] entries referenced */
- i64 startTime; /* Time when query started - used for profiling */
- BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
- int aCounter[2]; /* Counters used by sqlite3_stmt_status() */
- char *zSql; /* Text of the SQL statement that generated this */
- void *pFree; /* Free this when deleting the vdbe */
- i64 nFkConstraint; /* Number of imm. FK constraints this VM */
- i64 nStmtDefCons; /* Number of def. constraints when stmt started */
- int iStatement; /* Statement number (or 0 if has not opened stmt) */
-#ifdef SQLITE_DEBUG
- FILE *trace; /* Write an execution trace here, if not NULL */
-#endif
- VdbeFrame *pFrame; /* Parent frame */
- int nFrame; /* Number of frames in pFrame list */
- u32 expmask; /* Binding to these vars invalidates VM */
-};
-
-/*
-** 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);
-
-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);
-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);
-
-#ifndef SQLITE_OMIT_FOREIGN_KEY
-SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *, int);
-#else
-# define sqlite3VdbeCheckFk(p,i) 0
-#endif
-
-#ifndef SQLITE_OMIT_SHARED_CACHE
-SQLITE_PRIVATE void sqlite3VdbeMutexArrayEnter(Vdbe *p);
-#else
-# define sqlite3VdbeMutexArrayEnter(p)
-#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 *);
-#else
- #define sqlite3VdbeMemExpandBlob(x) SQLITE_OK
-#endif
-
-#endif /* !defined(_VDBEINT_H_) */
-
-/************** End of vdbeInt.h *********************************************/
-/************** Continuing where we left off in utf.c ************************/
+/* #include */
#ifndef SQLITE_AMALGAMATION
/*
@@ -18542,11 +20212,11 @@ static const unsigned char sqlite3Utf8Trans1[] = {
|| (c&0xFFFFF800)==0xD800 \
|| (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \
}
-SQLITE_PRIVATE int sqlite3Utf8Read(
+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 */
){
- int c;
+ 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.
@@ -18571,7 +20241,7 @@ SQLITE_PRIVATE int sqlite3Utf8Read(
/*
** 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
@@ -18602,7 +20272,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
}
#endif
- /* If the translation is between UTF-16 little and big endian, then
+ /* 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.
*/
@@ -18682,13 +20352,13 @@ SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
if( pMem->enc==SQLITE_UTF16LE ){
/* UTF-16 Little-endian -> UTF-8 */
while( zIn UTF-8 */
while( zIn */
#ifdef SQLITE_HAVE_ISNAN
# include
#endif
@@ -18966,8 +20637,8 @@ SQLITE_PRIVATE void sqlite3UtfSelfTest(void){
*/
#ifdef SQLITE_COVERAGE_TEST
SQLITE_PRIVATE void sqlite3Coverage(int x){
- static int dummy = 0;
- dummy += x;
+ static unsigned dummy = 0;
+ dummy += (unsigned)x;
}
#endif
@@ -18993,15 +20664,15 @@ SQLITE_PRIVATE int sqlite3IsNaN(double x){
**
** 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
+ ** 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
+ ** 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
+ ** 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__
@@ -19155,6 +20826,12 @@ SQLITE_PRIVATE int sqlite3Dequote(char *z){
/*
** Some systems have stricmp(). Others have strcasecmp(). Because
** there is no consistency, we will define our own.
+**
+** IMPLEMENTATION-OF: R-20522-24639 The sqlite3_strnicmp() API allows
+** 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.
*/
SQLITE_PRIVATE int sqlite3StrICmp(const char *zLeft, const char *zRight){
register unsigned char *a, *b;
@@ -19172,121 +20849,111 @@ SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
}
/*
-** Return TRUE if z is a pure numeric string. Return FALSE and leave
-** *realnum unchanged if the string contains any character which is not
-** part of a number.
+** The string z[] is an text representation of a real number.
+** Convert this string to a double and write it into *pResult.
**
-** If the string is pure numeric, set *realnum to TRUE if the string
-** contains the '.' character or an "E+000" style exponentiation suffix.
-** Otherwise set *realnum to FALSE. Note that just becaue *realnum is
-** false does not mean that the number can be successfully converted into
-** an integer - it might be too big.
+** The string z[] is length bytes in length (bytes, not characters) and
+** uses the encoding enc. The string is not necessarily zero-terminated.
**
-** An empty string is considered non-numeric.
+** 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 sqlite3IsNumber(const char *z, int *realnum, u8 enc){
+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);
- if( enc==SQLITE_UTF16BE ) z++;
- if( *z=='-' || *z=='+' ) z += incr;
- if( !sqlite3Isdigit(*z) ){
- return 0;
- }
- z += incr;
- *realnum = 0;
- while( sqlite3Isdigit(*z) ){ z += incr; }
-#ifndef SQLITE_OMIT_FLOATING_POINT
- if( *z=='.' ){
- z += incr;
- if( !sqlite3Isdigit(*z) ) return 0;
- while( sqlite3Isdigit(*z) ){ z += incr; }
- *realnum = 1;
- }
- if( *z=='e' || *z=='E' ){
- z += incr;
- if( *z=='+' || *z=='-' ) z += incr;
- if( !sqlite3Isdigit(*z) ) return 0;
- while( sqlite3Isdigit(*z) ){ z += incr; }
- *realnum = 1;
- }
-#endif
- return *z==0;
-}
-
-/*
-** The string z[] is an ASCII representation of a real number.
-** Convert this string to a double.
-**
-** This routine assumes that z[] really is a valid number. If it
-** is not, the result is undefined.
-**
-** This routine is used instead of the library atof() function because
-** the library atof() might want to use "," as the decimal point instead
-** of "." depending on how locale is set. But that would cause problems
-** for SQL. So this routine always uses "." regardless of locale.
-*/
-SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult){
-#ifndef SQLITE_OMIT_FLOATING_POINT
- const char *zBegin = z;
+ 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 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;
+ *pResult = 0.0; /* Default return value, in case of an error */
+
+ if( enc==SQLITE_UTF16BE ) z++;
+
/* skip leading spaces */
- while( sqlite3Isspace(*z) ) z++;
+ while( z=zEnd ) return 0;
+
/* get sign of significand */
if( *z=='-' ){
sign = -1;
- z++;
+ z+=incr;
}else if( *z=='+' ){
- z++;
+ z+=incr;
}
+
/* skip leading zeroes */
- while( z[0]=='0' ) z++, nDigits++;
+ while( z=zEnd ) goto do_atof_calc;
/* if decimal point is present */
if( *z=='.' ){
- z++;
+ z+=incr;
/* copy digits from after decimal to significand
** (decrease exponent by d to shift decimal right) */
- while( sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
+ while( z=zEnd ) goto do_atof_calc;
/* if exponent is present */
if( *z=='e' || *z=='E' ){
- z++;
+ z+=incr;
+ eValid = 0;
+ if( z>=zEnd ) goto do_atof_calc;
/* get sign of exponent */
if( *z=='-' ){
esign = -1;
- z++;
+ z+=incr;
}else if( *z=='+' ){
- z++;
+ z+=incr;
}
/* copy digits to exponent */
- while( sqlite3Isdigit(*z) ){
+ while( z0 ) { scale *= 1.0e+22; e -= 22; }
@@ -19345,10 +21012,10 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult){
/* store the result */
*pResult = result;
- /* return number of characters used */
- return (int)(z - zBegin);
+ /* return true if number and no extra non-whitespace chracters after */
+ return z>=zEnd && nDigits>0 && eValid;
#else
- return sqlite3Atoi64(z, pResult);
+ return !sqlite3Atoi64(z, pResult, length, enc);
#endif /* SQLITE_OMIT_FLOATING_POINT */
}
@@ -19356,20 +21023,26 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult){
** 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")
+** compare2pow63("9223372036854775800", 1)
**
** will return -8.
*/
-static int compare2pow63(const char *zNum){
- int c;
- c = memcmp(zNum,"922337203685477580",18)*10;
+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] - '8';
+ c = zNum[18*incr] - '8';
testcase( c==(-1) );
testcase( c==0 );
testcase( c==(+1) );
@@ -19379,94 +21052,80 @@ static int compare2pow63(const char *zNum){
/*
-** Return TRUE if zNum is a 64-bit signed integer and write
-** the value of the integer into *pNum. If zNum is not an integer
-** or is an integer that is too large to be expressed with 64 bits,
-** then return false.
+** Convert zNum to a 64-bit signed integer.
**
-** When this routine was originally written it dealt with only
-** 32-bit numbers. At that time, it was much faster than the
-** atoi() library routine in RedHat 7.2.
+** 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 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){
- i64 v = 0;
- int neg;
- int i, c;
+SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
+ int incr = (enc==SQLITE_UTF8?1:2);
+ u64 u = 0;
+ int neg = 0; /* assume positive */
+ int i;
+ int c = 0;
const char *zStart;
- while( sqlite3Isspace(*zNum) ) zNum++;
- if( *zNum=='-' ){
- neg = 1;
- zNum++;
- }else if( *zNum=='+' ){
- neg = 0;
- zNum++;
- }else{
- neg = 0;
+ const char *zEnd = zNum + length;
+ if( enc==SQLITE_UTF16BE ) zNum++;
+ while( zNum='0' && c<='9'; i++){
- v = v*10 + c - '0';
+ while( zNum='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;
}
- *pNum = neg ? -v : v;
testcase( i==18 );
testcase( i==19 );
testcase( i==20 );
- if( c!=0 || (i==0 && zStart==zNum) || i>19 ){
+ if( (c!=0 && &zNum[i]19*incr ){
/* zNum is empty or contains non-numeric text or is longer
- ** than 19 digits (thus guaranting that it is too large) */
- return 0;
- }else if( i<19 ){
+ ** 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 */
- return 1;
- }else{
- /* 19-digit numbers must be no larger than 9223372036854775807 if positive
- ** or 9223372036854775808 if negative. Note that 9223372036854665808
- ** is 2^63. */
- return compare2pow63(zNum)='0' && zNum[0]<='9' ); /* zNum is an unsigned number */
-
- if( negFlag ) neg = 1-neg;
- while( *zNum=='0' ){
- zNum++; /* Skip leading zeros. Ticket #2454 */
- }
- for(i=0; zNum[i]; i++){ assert( zNum[i]>='0' && zNum[i]<='9' ); }
- testcase( i==18 );
- testcase( i==19 );
- testcase( i==20 );
- if( i<19 ){
- /* Guaranteed to fit if less than 19 digits */
- return 1;
- }else if( i>19 ){
- /* Guaranteed to be too big if greater than 19 digits */
+ assert( u<=LARGEST_INT64 );
return 0;
}else{
- /* Compare against 2^63. */
- return compare2pow63(zNum)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;
+ }
}
}
@@ -19513,6 +21172,16 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){
return 1;
}
+/*
+** Return a 32-bit integer value extracted from a string. If the
+** string is not an integer, just return 0.
+*/
+SQLITE_PRIVATE int sqlite3Atoi(const char *z){
+ int x = 0;
+ if( z ) sqlite3GetInt32(z, &x);
+ return x;
+}
+
/*
** The variable-length integer encoding is as follows:
**
@@ -19553,7 +21222,7 @@ SQLITE_PRIVATE int sqlite3PutVarint(unsigned char *p, u64 v){
v >>= 7;
}
return 9;
- }
+ }
n = 0;
do{
buf[n++] = (u8)((v & 0x7f) | 0x80);
@@ -19773,8 +21442,8 @@ SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *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
+** 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.
*/
SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
@@ -19925,13 +21594,12 @@ SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){
-#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
/*
** 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
*/
-static u8 hexToInt(int h){
+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));
@@ -19941,7 +21609,6 @@ static u8 hexToInt(int h){
#endif
return (u8)(h & 0xf);
}
-#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */
#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
/*
@@ -19958,7 +21625,7 @@ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
n--;
if( zBlob ){
for(i=0; i=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;
+
+ 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;
+}
+
+/*
+** 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.
+**
+** 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
+*/
+SQLITE_PRIVATE void sqlite3FileSuffix3(const char *zBaseFilename, char *z){
+#if SQLITE_ENABLE_8_3_NAMES<2
+ const char *zOk;
+ zOk = sqlite3_uri_parameter(zBaseFilename, "8_3_names");
+ if( zOk && sqlite3GetBoolean(zOk) )
+#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) ) memcpy(&z[i+1], &z[sz-3], 4);
+ }
+}
+#endif
+
/************** End of util.c ************************************************/
/************** Begin file hash.c ********************************************/
/*
@@ -20039,6 +21806,7 @@ SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
** This is the implementation of generic hash-tables
** used in SQLite.
*/
+/* #include */
/* Turn bulk memory into a hash table object by initializing the
** fields of the Hash structure.
@@ -20179,7 +21947,7 @@ static HashElem *findElementGivenHash(
count = pH->count;
}
while( count-- && ALWAYS(elem) ){
- if( elem->nKey==nKey && sqlite3StrNICmp(elem->pKey,pKey,nKey)==0 ){
+ if( elem->nKey==nKey && sqlite3StrNICmp(elem->pKey,pKey,nKey)==0 ){
return elem;
}
elem = elem->next;
@@ -20197,7 +21965,7 @@ static void removeElementGivenHash(
){
struct _ht *pEntry;
if( elem->prev ){
- elem->prev->next = elem->next;
+ elem->prev->next = elem->next;
}else{
pH->first = elem->next;
}
@@ -20333,53 +22101,53 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 23 */ "Permutation",
/* 24 */ "Compare",
/* 25 */ "Jump",
- /* 26 */ "If",
- /* 27 */ "IfNot",
- /* 28 */ "Column",
- /* 29 */ "Affinity",
- /* 30 */ "MakeRecord",
- /* 31 */ "Count",
- /* 32 */ "Savepoint",
- /* 33 */ "AutoCommit",
- /* 34 */ "Transaction",
- /* 35 */ "ReadCookie",
- /* 36 */ "SetCookie",
- /* 37 */ "VerifyCookie",
- /* 38 */ "OpenRead",
- /* 39 */ "OpenWrite",
- /* 40 */ "OpenEphemeral",
- /* 41 */ "OpenPseudo",
- /* 42 */ "Close",
- /* 43 */ "SeekLt",
- /* 44 */ "SeekLe",
- /* 45 */ "SeekGe",
- /* 46 */ "SeekGt",
- /* 47 */ "Seek",
- /* 48 */ "NotFound",
- /* 49 */ "Found",
- /* 50 */ "IsUnique",
- /* 51 */ "NotExists",
- /* 52 */ "Sequence",
- /* 53 */ "NewRowid",
- /* 54 */ "Insert",
- /* 55 */ "InsertInt",
- /* 56 */ "Delete",
- /* 57 */ "ResetCount",
- /* 58 */ "RowKey",
- /* 59 */ "RowData",
- /* 60 */ "Rowid",
- /* 61 */ "NullRow",
- /* 62 */ "Last",
- /* 63 */ "Sort",
- /* 64 */ "Rewind",
- /* 65 */ "Prev",
- /* 66 */ "Next",
- /* 67 */ "IdxInsert",
+ /* 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 */ "IdxDelete",
- /* 71 */ "IdxRowid",
- /* 72 */ "IdxLT",
+ /* 70 */ "SorterSort",
+ /* 71 */ "Sort",
+ /* 72 */ "Rewind",
/* 73 */ "IsNull",
/* 74 */ "NotNull",
/* 75 */ "Ne",
@@ -20388,7 +22156,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 78 */ "Le",
/* 79 */ "Lt",
/* 80 */ "Ge",
- /* 81 */ "IdxGE",
+ /* 81 */ "SorterNext",
/* 82 */ "BitAnd",
/* 83 */ "BitOr",
/* 84 */ "ShiftLeft",
@@ -20399,60 +22167,65 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 89 */ "Divide",
/* 90 */ "Remainder",
/* 91 */ "Concat",
- /* 92 */ "Destroy",
+ /* 92 */ "Prev",
/* 93 */ "BitNot",
/* 94 */ "String8",
- /* 95 */ "Clear",
- /* 96 */ "CreateIndex",
- /* 97 */ "CreateTable",
- /* 98 */ "ParseSchema",
- /* 99 */ "LoadAnalysis",
- /* 100 */ "DropTable",
- /* 101 */ "DropIndex",
- /* 102 */ "DropTrigger",
- /* 103 */ "IntegrityCk",
- /* 104 */ "RowSetAdd",
- /* 105 */ "RowSetRead",
- /* 106 */ "RowSetTest",
- /* 107 */ "Program",
- /* 108 */ "Param",
- /* 109 */ "FkCounter",
- /* 110 */ "FkIfZero",
- /* 111 */ "MemMax",
- /* 112 */ "IfPos",
- /* 113 */ "IfNeg",
- /* 114 */ "IfZero",
- /* 115 */ "AggStep",
- /* 116 */ "AggFinal",
- /* 117 */ "Vacuum",
- /* 118 */ "IncrVacuum",
- /* 119 */ "Expire",
- /* 120 */ "TableLock",
- /* 121 */ "VBegin",
- /* 122 */ "VCreate",
- /* 123 */ "VDestroy",
- /* 124 */ "VOpen",
- /* 125 */ "VFilter",
- /* 126 */ "VColumn",
- /* 127 */ "VNext",
- /* 128 */ "VRename",
- /* 129 */ "VUpdate",
+ /* 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 */ "Pagecount",
- /* 132 */ "Trace",
- /* 133 */ "Noop",
- /* 134 */ "Explain",
- /* 135 */ "NotUsed_135",
- /* 136 */ "NotUsed_136",
- /* 137 */ "NotUsed_137",
- /* 138 */ "NotUsed_138",
- /* 139 */ "NotUsed_139",
- /* 140 */ "NotUsed_140",
+ /* 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];
}
@@ -20547,25 +22320,14 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
#endif
-#ifdef SQLITE_DEBUG
-SQLITE_PRIVATE int sqlite3OSTrace = 0;
-#define OSTRACE1(X) if( sqlite3OSTrace ) sqlite3DebugPrintf(X)
-#define OSTRACE2(X,Y) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y)
-#define OSTRACE3(X,Y,Z) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z)
-#define OSTRACE4(X,Y,Z,A) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A)
-#define OSTRACE5(X,Y,Z,A,B) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A,B)
-#define OSTRACE6(X,Y,Z,A,B,C) \
- if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
-#define OSTRACE7(X,Y,Z,A,B,C,D) \
- if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
+#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 OSTRACE1(X)
-#define OSTRACE2(X,Y)
-#define OSTRACE3(X,Y,Z)
-#define OSTRACE4(X,Y,Z,A)
-#define OSTRACE5(X,Y,Z,A,B)
-#define OSTRACE6(X,Y,Z,A,B,C)
-#define OSTRACE7(X,Y,Z,A,B,C,D)
+# define OSTRACE(X)
#endif
/*
@@ -20574,8 +22336,8 @@ SQLITE_PRIVATE int sqlite3OSTrace = 0;
*/
#ifdef SQLITE_PERFORMANCE_TRACE
-/*
-** hwtime.h contains inline assembler code for implementing
+/*
+** hwtime.h contains inline assembler code for implementing
** high-performance timing routines.
*/
/************** Include hwtime.h in the middle of os_common.h ****************/
@@ -20633,7 +22395,7 @@ SQLITE_PRIVATE int sqlite3OSTrace = 0;
__asm__ __volatile__ ("rdtsc" : "=A" (val));
return val;
}
-
+
#elif (defined(__GNUC__) && defined(__ppc__))
__inline__ sqlite_uint64 sqlite3Hwtime(void){
@@ -20735,20 +22497,35 @@ SQLITE_API int sqlite3_open_file_count = 0;
/************** End of os_common.h *******************************************/
/************** Continuing where we left off in os_os2.c *********************/
+/* Forward references */
+typedef struct os2File os2File; /* The file structure */
+typedef struct os2ShmNode os2ShmNode; /* A shared descritive memory node */
+typedef struct os2ShmLink os2ShmLink; /* A connection to shared-memory */
+
/*
** The os2File structure is subclass of sqlite3_file specific for the OS/2
** protability layer.
*/
-typedef struct os2File os2File;
struct os2File {
const sqlite3_io_methods *pMethod; /* Always the first entry */
HFILE h; /* Handle for accessing the file */
- char* pathToDel; /* Name of file to delete on close, NULL if not */
- unsigned char locktype; /* Type of lock currently held on this file */
+ int flags; /* Flags provided to os2Open() */
+ int locktype; /* Type of lock currently held on this file */
+ int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */
+ char *zFullPathCp; /* Full path name of this file */
+ os2ShmLink *pShmLink; /* Instance of shared memory on this file */
};
#define LOCK_TIMEOUT 10L /* the default locking timeout */
+/*
+** Missing from some versions of the OS/2 toolkit -
+** used to allocate from high memory if possible
+*/
+#ifndef OBJ_ANY
+# define OBJ_ANY 0x00000400
+#endif
+
/*****************************************************************************
** The next group of routines implement the I/O methods specified
** by the sqlite3_io_methods object.
@@ -20758,21 +22535,24 @@ struct os2File {
** Close a file.
*/
static int os2Close( sqlite3_file *id ){
- APIRET rc = NO_ERROR;
- os2File *pFile;
- if( id && (pFile = (os2File*)id) != 0 ){
- OSTRACE2( "CLOSE %d\n", pFile->h );
- rc = DosClose( pFile->h );
- pFile->locktype = NO_LOCK;
- if( pFile->pathToDel != NULL ){
- rc = DosForceDelete( (PSZ)pFile->pathToDel );
- free( pFile->pathToDel );
- pFile->pathToDel = NULL;
- }
- id = 0;
- OpenCounter( -1 );
- }
+ APIRET rc;
+ os2File *pFile = (os2File*)id;
+ assert( id!=0 );
+ OSTRACE(( "CLOSE %d (%s)\n", pFile->h, pFile->zFullPathCp ));
+
+ rc = DosClose( pFile->h );
+
+ if( pFile->flags & SQLITE_OPEN_DELETEONCLOSE )
+ DosForceDelete( (PSZ)pFile->zFullPathCp );
+
+ free( pFile->zFullPathCp );
+ pFile->zFullPathCp = NULL;
+ pFile->locktype = NO_LOCK;
+ pFile->h = (HFILE)-1;
+ pFile->flags = 0;
+
+ OpenCounter( -1 );
return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR;
}
@@ -20792,7 +22572,7 @@ static int os2Read(
os2File *pFile = (os2File*)id;
assert( id!=0 );
SimulateIOError( return SQLITE_IOERR_READ );
- OSTRACE3( "READ %d lock=%d\n", pFile->h, pFile->locktype );
+ OSTRACE(( "READ %d lock=%d\n", pFile->h, pFile->locktype ));
if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){
return SQLITE_IOERR;
}
@@ -20825,7 +22605,7 @@ static int os2Write(
assert( id!=0 );
SimulateIOError( return SQLITE_IOERR_WRITE );
SimulateDiskfullError( return SQLITE_FULL );
- OSTRACE3( "WRITE %d lock=%d\n", pFile->h, pFile->locktype );
+ OSTRACE(( "WRITE %d lock=%d\n", pFile->h, pFile->locktype ));
if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){
return SQLITE_IOERR;
}
@@ -20845,10 +22625,21 @@ static int os2Write(
** Truncate an open file to a specified size
*/
static int os2Truncate( sqlite3_file *id, i64 nByte ){
- APIRET rc = NO_ERROR;
+ APIRET rc;
os2File *pFile = (os2File*)id;
- OSTRACE3( "TRUNCATE %d %lld\n", pFile->h, nByte );
+ assert( id!=0 );
+ OSTRACE(( "TRUNCATE %d %lld\n", pFile->h, nByte ));
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).
+ */
+ if( pFile->szChunk ){
+ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
+ }
+
rc = DosSetFileSize( pFile->h, nByte );
return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_TRUNCATE;
}
@@ -20867,7 +22658,7 @@ SQLITE_API int sqlite3_fullsync_count = 0;
*/
static int os2Sync( sqlite3_file *id, int flags ){
os2File *pFile = (os2File*)id;
- OSTRACE3( "SYNC %d lock=%d\n", pFile->h, pFile->locktype );
+ OSTRACE(( "SYNC %d lock=%d\n", pFile->h, pFile->locktype ));
#ifdef SQLITE_TEST
if( flags & SQLITE_SYNC_FULL){
sqlite3_fullsync_count++;
@@ -20917,7 +22708,7 @@ static int getReadLock( os2File *pFile ){
UnlockArea.lOffset = 0L;
UnlockArea.lRange = 0L;
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L );
- OSTRACE3( "GETREADLOCK %d res=%d\n", pFile->h, res );
+ OSTRACE(( "GETREADLOCK %d res=%d\n", pFile->h, res ));
return res;
}
@@ -20935,7 +22726,7 @@ static int unlockReadLock( os2File *id ){
UnlockArea.lOffset = SHARED_FIRST;
UnlockArea.lRange = SHARED_SIZE;
res = DosSetFileLocks( id->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L );
- OSTRACE3( "UNLOCK-READLOCK file handle=%d res=%d?\n", id->h, res );
+ OSTRACE(( "UNLOCK-READLOCK file handle=%d res=%d?\n", id->h, res ));
return res;
}
@@ -20976,14 +22767,14 @@ static int os2Lock( sqlite3_file *id, int locktype ){
memset(&LockArea, 0, sizeof(LockArea));
memset(&UnlockArea, 0, sizeof(UnlockArea));
assert( pFile!=0 );
- OSTRACE4( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype );
+ OSTRACE(( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype ));
/* If there is already a lock of this type or more restrictive on the
** os2File, do nothing. Don't use the end_lock: exit path, as
** sqlite3_mutex_enter() hasn't been called yet.
*/
if( pFile->locktype>=locktype ){
- OSTRACE3( "LOCK %d %d ok (already held)\n", pFile->h, locktype );
+ OSTRACE(( "LOCK %d %d ok (already held)\n", pFile->h, locktype ));
return SQLITE_OK;
}
@@ -21010,7 +22801,7 @@ static int os2Lock( sqlite3_file *id, int locktype ){
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 100L, 0L );
if( res == NO_ERROR ){
gotPendingLock = 1;
- OSTRACE3( "LOCK %d pending lock boolean set. res=%d\n", pFile->h, res );
+ OSTRACE(( "LOCK %d pending lock boolean set. res=%d\n", pFile->h, res ));
}
}
@@ -21022,7 +22813,7 @@ static int os2Lock( sqlite3_file *id, int locktype ){
if( res == NO_ERROR ){
newLocktype = SHARED_LOCK;
}
- OSTRACE3( "LOCK %d acquire shared lock. res=%d\n", pFile->h, res );
+ OSTRACE(( "LOCK %d acquire shared lock. res=%d\n", pFile->h, res ));
}
/* Acquire a RESERVED lock
@@ -21037,7 +22828,7 @@ static int os2Lock( sqlite3_file *id, int locktype ){
if( res == NO_ERROR ){
newLocktype = RESERVED_LOCK;
}
- OSTRACE3( "LOCK %d acquire reserved lock. res=%d\n", pFile->h, res );
+ OSTRACE(( "LOCK %d acquire reserved lock. res=%d\n", pFile->h, res ));
}
/* Acquire a PENDING lock
@@ -21045,7 +22836,8 @@ static int os2Lock( sqlite3_file *id, int locktype ){
if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){
newLocktype = PENDING_LOCK;
gotPendingLock = 0;
- OSTRACE2( "LOCK %d acquire pending lock. pending lock boolean unset.\n", pFile->h );
+ OSTRACE(( "LOCK %d acquire pending lock. pending lock boolean unset.\n",
+ pFile->h ));
}
/* Acquire an EXCLUSIVE lock
@@ -21053,7 +22845,7 @@ static int os2Lock( sqlite3_file *id, int locktype ){
if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){
assert( pFile->locktype>=SHARED_LOCK );
res = unlockReadLock(pFile);
- OSTRACE2( "unreadlock = %d\n", res );
+ OSTRACE(( "unreadlock = %d\n", res ));
LockArea.lOffset = SHARED_FIRST;
LockArea.lRange = SHARED_SIZE;
UnlockArea.lOffset = 0L;
@@ -21062,10 +22854,10 @@ static int os2Lock( sqlite3_file *id, int locktype ){
if( res == NO_ERROR ){
newLocktype = EXCLUSIVE_LOCK;
}else{
- OSTRACE2( "OS/2 error-code = %d\n", res );
+ OSTRACE(( "OS/2 error-code = %d\n", res ));
getReadLock(pFile);
}
- OSTRACE3( "LOCK %d acquire exclusive lock. res=%d\n", pFile->h, res );
+ OSTRACE(( "LOCK %d acquire exclusive lock. res=%d\n", pFile->h, res ));
}
/* If we are holding a PENDING lock that ought to be released, then
@@ -21078,7 +22870,7 @@ static int os2Lock( sqlite3_file *id, int locktype ){
UnlockArea.lOffset = PENDING_BYTE;
UnlockArea.lRange = 1L;
r = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
- OSTRACE3( "LOCK %d unlocking pending/is shared. r=%d\n", pFile->h, r );
+ OSTRACE(( "LOCK %d unlocking pending/is shared. r=%d\n", pFile->h, r ));
}
/* Update the state of the lock has held in the file descriptor then
@@ -21087,12 +22879,12 @@ static int os2Lock( sqlite3_file *id, int locktype ){
if( res == NO_ERROR ){
rc = SQLITE_OK;
}else{
- OSTRACE4( "LOCK FAILED %d trying for %d but got %d\n", pFile->h,
- locktype, newLocktype );
+ OSTRACE(( "LOCK FAILED %d trying for %d but got %d\n", pFile->h,
+ locktype, newLocktype ));
rc = SQLITE_BUSY;
}
pFile->locktype = newLocktype;
- OSTRACE3( "LOCK %d now %d\n", pFile->h, pFile->locktype );
+ OSTRACE(( "LOCK %d now %d\n", pFile->h, pFile->locktype ));
return rc;
}
@@ -21107,7 +22899,7 @@ static int os2CheckReservedLock( sqlite3_file *id, int *pOut ){
assert( pFile!=0 );
if( pFile->locktype>=RESERVED_LOCK ){
r = 1;
- OSTRACE3( "TEST WR-LOCK %d %d (local)\n", pFile->h, r );
+ OSTRACE(( "TEST WR-LOCK %d %d (local)\n", pFile->h, r ));
}else{
FILELOCK LockArea,
UnlockArea;
@@ -21119,7 +22911,7 @@ static int os2CheckReservedLock( sqlite3_file *id, int *pOut ){
UnlockArea.lOffset = 0L;
UnlockArea.lRange = 0L;
rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
- OSTRACE3( "TEST WR-LOCK %d lock reserved byte rc=%d\n", pFile->h, rc );
+ OSTRACE(( "TEST WR-LOCK %d lock reserved byte rc=%d\n", pFile->h, rc ));
if( rc == NO_ERROR ){
APIRET rcu = NO_ERROR; /* return code for unlocking */
LockArea.lOffset = 0L;
@@ -21127,10 +22919,10 @@ static int os2CheckReservedLock( sqlite3_file *id, int *pOut ){
UnlockArea.lOffset = RESERVED_BYTE;
UnlockArea.lRange = 1L;
rcu = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
- OSTRACE3( "TEST WR-LOCK %d unlock reserved byte r=%d\n", pFile->h, rcu );
+ OSTRACE(( "TEST WR-LOCK %d unlock reserved byte r=%d\n", pFile->h, rcu ));
}
r = !(rc == NO_ERROR);
- OSTRACE3( "TEST WR-LOCK %d %d (remote)\n", pFile->h, r );
+ OSTRACE(( "TEST WR-LOCK %d %d (remote)\n", pFile->h, r ));
}
*pOut = r;
return SQLITE_OK;
@@ -21158,7 +22950,7 @@ static int os2Unlock( sqlite3_file *id, int locktype ){
memset(&UnlockArea, 0, sizeof(UnlockArea));
assert( pFile!=0 );
assert( locktype<=SHARED_LOCK );
- OSTRACE4( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype );
+ OSTRACE(( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype ));
type = pFile->locktype;
if( type>=EXCLUSIVE_LOCK ){
LockArea.lOffset = 0L;
@@ -21166,11 +22958,11 @@ static int os2Unlock( sqlite3_file *id, int locktype ){
UnlockArea.lOffset = SHARED_FIRST;
UnlockArea.lRange = SHARED_SIZE;
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
- OSTRACE3( "UNLOCK %d exclusive lock res=%d\n", pFile->h, res );
+ OSTRACE(( "UNLOCK %d exclusive lock res=%d\n", pFile->h, res ));
if( locktype==SHARED_LOCK && getReadLock(pFile) != NO_ERROR ){
/* This should never happen. We should always be able to
** reacquire the read lock */
- OSTRACE3( "UNLOCK %d to %d getReadLock() failed\n", pFile->h, locktype );
+ OSTRACE(( "UNLOCK %d to %d getReadLock() failed\n", pFile->h, locktype ));
rc = SQLITE_IOERR_UNLOCK;
}
}
@@ -21180,11 +22972,12 @@ static int os2Unlock( sqlite3_file *id, int locktype ){
UnlockArea.lOffset = RESERVED_BYTE;
UnlockArea.lRange = 1L;
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
- OSTRACE3( "UNLOCK %d reserved res=%d\n", pFile->h, res );
+ OSTRACE(( "UNLOCK %d reserved res=%d\n", pFile->h, res ));
}
if( locktype==NO_LOCK && type>=SHARED_LOCK ){
res = unlockReadLock(pFile);
- OSTRACE5( "UNLOCK %d is %d want %d res=%d\n", pFile->h, type, locktype, res );
+ OSTRACE(( "UNLOCK %d is %d want %d res=%d\n",
+ pFile->h, type, locktype, res ));
}
if( type>=PENDING_LOCK ){
LockArea.lOffset = 0L;
@@ -21192,10 +22985,10 @@ static int os2Unlock( sqlite3_file *id, int locktype ){
UnlockArea.lOffset = PENDING_BYTE;
UnlockArea.lRange = 1L;
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
- OSTRACE3( "UNLOCK %d pending res=%d\n", pFile->h, res );
+ OSTRACE(( "UNLOCK %d pending res=%d\n", pFile->h, res ));
}
pFile->locktype = locktype;
- OSTRACE3( "UNLOCK %d now %d\n", pFile->h, pFile->locktype );
+ OSTRACE(( "UNLOCK %d now %d\n", pFile->h, pFile->locktype ));
return rc;
}
@@ -21206,11 +22999,26 @@ static int os2FileControl(sqlite3_file *id, int op, void *pArg){
switch( op ){
case SQLITE_FCNTL_LOCKSTATE: {
*(int*)pArg = ((os2File*)id)->locktype;
- OSTRACE3( "FCNTL_LOCKSTATE %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype );
+ OSTRACE(( "FCNTL_LOCKSTATE %d lock=%d\n",
+ ((os2File*)id)->h, ((os2File*)id)->locktype ));
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_CHUNK_SIZE: {
+ ((os2File*)id)->szChunk = *(int*)pArg;
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_SIZE_HINT: {
+ sqlite3_int64 sz = *(sqlite3_int64*)pArg;
+ SimulateIOErrorBenign(1);
+ os2Truncate(id, sz);
+ SimulateIOErrorBenign(0);
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_SYNC_OMITTED: {
return SQLITE_OK;
}
}
- return SQLITE_ERROR;
+ return SQLITE_NOTFOUND;
}
/*
@@ -21224,6 +23032,7 @@ static int os2FileControl(sqlite3_file *id, int op, void *pArg){
** same for both.
*/
static int os2SectorSize(sqlite3_file *id){
+ UNUSED_PARAMETER(id);
return SQLITE_DEFAULT_SECTOR_SIZE;
}
@@ -21231,7 +23040,8 @@ static int os2SectorSize(sqlite3_file *id){
** Return a vector of device characteristics.
*/
static int os2DeviceCharacteristics(sqlite3_file *id){
- return 0;
+ UNUSED_PARAMETER(id);
+ return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
}
@@ -21318,26 +23128,682 @@ char *convertCpPathToUtf8( const char *in ){
return out;
}
+
+#ifndef SQLITE_OMIT_WAL
+
+/*
+** Use main database file for interprocess locking. If un-defined
+** a separate file is created for this purpose. The file will be
+** used only to set file locks. There will be no data written to it.
+*/
+#define SQLITE_OS2_NO_WAL_LOCK_FILE
+
+#if 0
+static void _ERR_TRACE( const char *fmt, ... ) {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ fflush(stderr);
+}
+#define ERR_TRACE(rc, msg) \
+ if( (rc) != SQLITE_OK ) _ERR_TRACE msg;
+#else
+#define ERR_TRACE(rc, msg)
+#endif
+
+/*
+** Helper functions to obtain and relinquish the global mutex. The
+** global mutex is used to protect os2ShmNodeList.
+**
+** Function os2ShmMutexHeld() is used to assert() that the global mutex
+** is held when required. This function is only used as part of assert()
+** statements. e.g.
+**
+** os2ShmEnterMutex()
+** assert( os2ShmMutexHeld() );
+** os2ShmLeaveMutex()
+*/
+static void os2ShmEnterMutex(void){
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+}
+static void os2ShmLeaveMutex(void){
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+}
+#ifdef SQLITE_DEBUG
+static int os2ShmMutexHeld(void) {
+ return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+}
+int GetCurrentProcessId(void) {
+ PPIB pib;
+ DosGetInfoBlocks(NULL, &pib);
+ return (int)pib->pib_ulpid;
+}
+#endif
+
+/*
+** Object used to represent a the shared memory area for a single log file.
+** When multiple threads all reference the same log-summary, each thread has
+** its own os2File object, but they all point to a single instance of this
+** object. In other words, each log-summary is opened only once per process.
+**
+** os2ShmMutexHeld() 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:
+**
+** szRegion
+** hLockFile
+** shmBaseName
+**
+** Either os2ShmNode.mutex must be held or os2ShmNode.nRef==0 and
+** os2ShmMutexHeld() is true when reading or writing any other field
+** in this structure.
+**
+*/
+struct os2ShmNode {
+ sqlite3_mutex *mutex; /* Mutex to access this object */
+ os2ShmNode *pNext; /* Next in list of all os2ShmNode objects */
+
+ int szRegion; /* Size of shared-memory regions */
+
+ int nRegion; /* Size of array apRegion */
+ void **apRegion; /* Array of pointers to shared-memory regions */
+
+ int nRef; /* Number of os2ShmLink objects pointing to this */
+ os2ShmLink *pFirst; /* First os2ShmLink object pointing to this */
+
+ HFILE hLockFile; /* File used for inter-process memory locking */
+ char shmBaseName[1]; /* Name of the memory object !!! must last !!! */
+};
+
+
+/*
+** 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:
+**
+** os2Shm.pShmNode
+** os2Shm.id
+**
+** All other fields are read/write. The os2Shm.pShmNode->mutex must be held
+** while accessing any read/write fields.
+*/
+struct os2ShmLink {
+ os2ShmNode *pShmNode; /* The underlying os2ShmNode object */
+ os2ShmLink *pNext; /* Next os2Shm with the same os2ShmNode */
+ u32 sharedMask; /* Mask of shared locks held */
+ u32 exclMask; /* Mask of exclusive locks held */
+#ifdef SQLITE_DEBUG
+ u8 id; /* Id of this connection with its os2ShmNode */
+#endif
+};
+
+
+/*
+** A global list of all os2ShmNode objects.
+**
+** The os2ShmMutexHeld() must be true while reading or writing this list.
+*/
+static os2ShmNode *os2ShmNodeList = NULL;
+
+/*
+** Constants used for locking
+*/
+#ifdef SQLITE_OS2_NO_WAL_LOCK_FILE
+#define OS2_SHM_BASE (PENDING_BYTE + 0x10000) /* first lock byte */
+#else
+#define OS2_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
+#endif
+
+#define OS2_SHM_DMS (OS2_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
+
+/*
+** Apply advisory locks for all n bytes beginning at ofst.
+*/
+#define _SHM_UNLCK 1 /* no lock */
+#define _SHM_RDLCK 2 /* shared lock, no wait */
+#define _SHM_WRLCK 3 /* exlusive lock, no wait */
+#define _SHM_WRLCK_WAIT 4 /* exclusive lock, wait */
+static int os2ShmSystemLock(
+ os2ShmNode *pNode, /* Apply locks to this open shared-memory segment */
+ int lockType, /* _SHM_UNLCK, _SHM_RDLCK, _SHM_WRLCK or _SHM_WRLCK_WAIT */
+ int ofst, /* Offset to first byte to be locked/unlocked */
+ int nByte /* Number of bytes to lock or unlock */
+){
+ APIRET rc;
+ FILELOCK area;
+ ULONG mode, timeout;
+
+ /* Access to the os2ShmNode object is serialized by the caller */
+ assert( sqlite3_mutex_held(pNode->mutex) || pNode->nRef==0 );
+
+ mode = 1; /* shared lock */
+ timeout = 0; /* no wait */
+ area.lOffset = ofst;
+ area.lRange = nByte;
+
+ switch( lockType ) {
+ case _SHM_WRLCK_WAIT:
+ timeout = (ULONG)-1; /* wait forever */
+ case _SHM_WRLCK:
+ mode = 0; /* exclusive lock */
+ case _SHM_RDLCK:
+ rc = DosSetFileLocks(pNode->hLockFile,
+ NULL, &area, timeout, mode);
+ break;
+ /* case _SHM_UNLCK: */
+ default:
+ rc = DosSetFileLocks(pNode->hLockFile,
+ &area, NULL, 0, 0);
+ break;
+ }
+
+ OSTRACE(("SHM-LOCK %d %s %s 0x%08lx\n",
+ pNode->hLockFile,
+ rc==SQLITE_OK ? "ok" : "failed",
+ lockType==_SHM_UNLCK ? "Unlock" : "Lock",
+ rc));
+
+ ERR_TRACE(rc, ("os2ShmSystemLock: %d %s\n", rc, pNode->shmBaseName))
+
+ return ( rc == 0 ) ? SQLITE_OK : SQLITE_BUSY;
+}
+
+/*
+** Find an os2ShmNode in global list or allocate a new one, if not found.
+**
+** This is not a VFS shared-memory method; it is a utility function called
+** by VFS shared-memory methods.
+*/
+static int os2OpenSharedMemory( os2File *fd, int szRegion ) {
+ os2ShmLink *pLink;
+ os2ShmNode *pNode;
+ int cbShmName, rc = SQLITE_OK;
+ char shmName[CCHMAXPATH + 30];
+#ifndef SQLITE_OS2_NO_WAL_LOCK_FILE
+ ULONG action;
+#endif
+
+ /* We need some additional space at the end to append the region number */
+ cbShmName = sprintf(shmName, "\\SHAREMEM\\%s", fd->zFullPathCp );
+ if( cbShmName >= CCHMAXPATH-8 )
+ return SQLITE_IOERR_SHMOPEN;
+
+ /* Replace colon in file name to form a valid shared memory name */
+ shmName[10+1] = '!';
+
+ /* Allocate link object (we free it later in case of failure) */
+ pLink = sqlite3_malloc( sizeof(*pLink) );
+ if( !pLink )
+ return SQLITE_NOMEM;
+
+ /* Access node list */
+ os2ShmEnterMutex();
+
+ /* Find node by it's shared memory base name */
+ for( pNode = os2ShmNodeList;
+ pNode && stricmp(shmName, pNode->shmBaseName) != 0;
+ pNode = pNode->pNext ) ;
+
+ /* Not found: allocate a new node */
+ if( !pNode ) {
+ pNode = sqlite3_malloc( sizeof(*pNode) + cbShmName );
+ if( pNode ) {
+ memset(pNode, 0, sizeof(*pNode) );
+ pNode->szRegion = szRegion;
+ pNode->hLockFile = (HFILE)-1;
+ strcpy(pNode->shmBaseName, shmName);
+
+#ifdef SQLITE_OS2_NO_WAL_LOCK_FILE
+ if( DosDupHandle(fd->h, &pNode->hLockFile) != 0 ) {
+#else
+ sprintf(shmName, "%s-lck", fd->zFullPathCp);
+ if( DosOpen((PSZ)shmName, &pNode->hLockFile, &action, 0, FILE_NORMAL,
+ OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW,
+ OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE |
+ OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_FAIL_ON_ERROR,
+ NULL) != 0 ) {
+#endif
+ sqlite3_free(pNode);
+ rc = SQLITE_IOERR;
+ } else {
+ pNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ if( !pNode->mutex ) {
+ sqlite3_free(pNode);
+ rc = SQLITE_NOMEM;
+ }
+ }
+ } else {
+ rc = SQLITE_NOMEM;
+ }
+
+ if( rc == SQLITE_OK ) {
+ pNode->pNext = os2ShmNodeList;
+ os2ShmNodeList = pNode;
+ } else {
+ pNode = NULL;
+ }
+ } else if( pNode->szRegion != szRegion ) {
+ rc = SQLITE_IOERR_SHMSIZE;
+ pNode = NULL;
+ }
+
+ if( pNode ) {
+ sqlite3_mutex_enter(pNode->mutex);
+
+ memset(pLink, 0, sizeof(*pLink));
+
+ pLink->pShmNode = pNode;
+ pLink->pNext = pNode->pFirst;
+ pNode->pFirst = pLink;
+ pNode->nRef++;
+
+ fd->pShmLink = pLink;
+
+ sqlite3_mutex_leave(pNode->mutex);
+
+ } else {
+ /* Error occured. Free our link object. */
+ sqlite3_free(pLink);
+ }
+
+ os2ShmLeaveMutex();
+
+ ERR_TRACE(rc, ("os2OpenSharedMemory: %d %s\n", rc, fd->zFullPathCp))
+
+ return rc;
+}
+
+/*
+** Purge the os2ShmNodeList list of all entries with nRef==0.
+**
+** This is not a VFS shared-memory method; it is a utility function called
+** by VFS shared-memory methods.
+*/
+static void os2PurgeShmNodes( int deleteFlag ) {
+ os2ShmNode *pNode;
+ os2ShmNode **ppNode;
+
+ os2ShmEnterMutex();
+
+ ppNode = &os2ShmNodeList;
+
+ while( *ppNode ) {
+ pNode = *ppNode;
+
+ if( pNode->nRef == 0 ) {
+ *ppNode = pNode->pNext;
+
+ if( pNode->apRegion ) {
+ /* Prevent other processes from resizing the shared memory */
+ os2ShmSystemLock(pNode, _SHM_WRLCK_WAIT, OS2_SHM_DMS, 1);
+
+ while( pNode->nRegion-- ) {
+#ifdef SQLITE_DEBUG
+ int rc =
+#endif
+ DosFreeMem(pNode->apRegion[pNode->nRegion]);
+
+ OSTRACE(("SHM-PURGE pid-%d unmap region=%d %s\n",
+ (int)GetCurrentProcessId(), pNode->nRegion,
+ rc == 0 ? "ok" : "failed"));
+ }
+
+ /* Allow other processes to resize the shared memory */
+ os2ShmSystemLock(pNode, _SHM_UNLCK, OS2_SHM_DMS, 1);
+
+ sqlite3_free(pNode->apRegion);
+ }
+
+ DosClose(pNode->hLockFile);
+
+#ifndef SQLITE_OS2_NO_WAL_LOCK_FILE
+ if( deleteFlag ) {
+ char fileName[CCHMAXPATH];
+ /* Skip "\\SHAREMEM\\" */
+ sprintf(fileName, "%s-lck", pNode->shmBaseName + 10);
+ /* restore colon */
+ fileName[1] = ':';
+
+ DosForceDelete(fileName);
+ }
+#endif
+
+ sqlite3_mutex_free(pNode->mutex);
+
+ sqlite3_free(pNode);
+
+ } else {
+ ppNode = &pNode->pNext;
+ }
+ }
+
+ os2ShmLeaveMutex();
+}
+
+/*
+** This function is called to obtain a pointer to region iRegion of the
+** shared-memory associated with the database file id. 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 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 os2ShmMap(
+ sqlite3_file *id, /* Handle open on database file */
+ int iRegion, /* Region to retrieve */
+ int szRegion, /* Size of regions */
+ int bExtend, /* True to extend block if necessary */
+ void volatile **pp /* OUT: Mapped memory */
+){
+ PVOID pvTemp;
+ void **apRegion;
+ os2ShmNode *pNode;
+ int n, rc = SQLITE_OK;
+ char shmName[CCHMAXPATH];
+ os2File *pFile = (os2File*)id;
+
+ *pp = NULL;
+
+ if( !pFile->pShmLink )
+ rc = os2OpenSharedMemory( pFile, szRegion );
+
+ if( rc == SQLITE_OK ) {
+ pNode = pFile->pShmLink->pShmNode ;
+
+ sqlite3_mutex_enter(pNode->mutex);
+
+ assert( szRegion==pNode->szRegion );
+
+ /* Unmapped region ? */
+ if( iRegion >= pNode->nRegion ) {
+ /* Prevent other processes from resizing the shared memory */
+ os2ShmSystemLock(pNode, _SHM_WRLCK_WAIT, OS2_SHM_DMS, 1);
+
+ apRegion = sqlite3_realloc(
+ pNode->apRegion, (iRegion + 1) * sizeof(apRegion[0]));
+
+ if( apRegion ) {
+ pNode->apRegion = apRegion;
+
+ while( pNode->nRegion <= iRegion ) {
+ sprintf(shmName, "%s-%u",
+ pNode->shmBaseName, pNode->nRegion);
+
+ if( DosGetNamedSharedMem(&pvTemp, (PSZ)shmName,
+ PAG_READ | PAG_WRITE) != NO_ERROR ) {
+ if( !bExtend )
+ break;
+
+ if( DosAllocSharedMem(&pvTemp, (PSZ)shmName, szRegion,
+ PAG_READ | PAG_WRITE | PAG_COMMIT | OBJ_ANY) != NO_ERROR &&
+ DosAllocSharedMem(&pvTemp, (PSZ)shmName, szRegion,
+ PAG_READ | PAG_WRITE | PAG_COMMIT) != NO_ERROR ) {
+ rc = SQLITE_NOMEM;
+ break;
+ }
+ }
+
+ apRegion[pNode->nRegion++] = pvTemp;
+ }
+
+ /* zero out remaining entries */
+ for( n = pNode->nRegion; n <= iRegion; n++ )
+ pNode->apRegion[n] = NULL;
+
+ /* Return this region (maybe zero) */
+ *pp = pNode->apRegion[iRegion];
+ } else {
+ rc = SQLITE_NOMEM;
+ }
+
+ /* Allow other processes to resize the shared memory */
+ os2ShmSystemLock(pNode, _SHM_UNLCK, OS2_SHM_DMS, 1);
+
+ } else {
+ /* Region has been mapped previously */
+ *pp = pNode->apRegion[iRegion];
+ }
+
+ sqlite3_mutex_leave(pNode->mutex);
+ }
+
+ ERR_TRACE(rc, ("os2ShmMap: %s iRgn = %d, szRgn = %d, bExt = %d : %d\n",
+ pFile->zFullPathCp, iRegion, szRegion, bExtend, rc))
+
+ return rc;
+}
+
+/*
+** 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 os2ShmUnmap(
+ sqlite3_file *id, /* The underlying database file */
+ int deleteFlag /* Delete shared-memory if true */
+){
+ os2File *pFile = (os2File*)id;
+ os2ShmLink *pLink = pFile->pShmLink;
+
+ if( pLink ) {
+ int nRef = -1;
+ os2ShmLink **ppLink;
+ os2ShmNode *pNode = pLink->pShmNode;
+
+ sqlite3_mutex_enter(pNode->mutex);
+
+ for( ppLink = &pNode->pFirst;
+ *ppLink && *ppLink != pLink;
+ ppLink = &(*ppLink)->pNext ) ;
+
+ assert(*ppLink);
+
+ if( *ppLink ) {
+ *ppLink = pLink->pNext;
+ nRef = --pNode->nRef;
+ } else {
+ ERR_TRACE(1, ("os2ShmUnmap: link not found ! %s\n",
+ pNode->shmBaseName))
+ }
+
+ pFile->pShmLink = NULL;
+ sqlite3_free(pLink);
+
+ sqlite3_mutex_leave(pNode->mutex);
+
+ if( nRef == 0 )
+ os2PurgeShmNodes( deleteFlag );
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Change the lock state for a shared-memory segment.
+**
+** 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 os2ShmLock(
+ sqlite3_file *id, /* 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 */
+){
+ u32 mask; /* Mask of locks to take or release */
+ int rc = SQLITE_OK; /* Result code */
+ os2File *pFile = (os2File*)id;
+ os2ShmLink *p = pFile->pShmLink; /* The shared memory being locked */
+ os2ShmLink *pX; /* For looping over all siblings */
+ os2ShmNode *pShmNode = p->pShmNode; /* Our node */
+
+ assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
+ assert( n>=1 );
+ assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
+ || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
+ || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
+ || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
+ assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
+
+ mask = (u32)((1U<<(ofst+n)) - (1U<1 || mask==(1<mutex);
+
+ if( flags & SQLITE_SHM_UNLOCK ){
+ u32 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 = os2ShmSystemLock(pShmNode, _SHM_UNLCK, ofst+OS2_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 ){
+ u32 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 = os2ShmSystemLock(pShmNode, _SHM_RDLCK, ofst+OS2_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 = os2ShmSystemLock(pShmNode, _SHM_WRLCK, ofst+OS2_SHM_BASE, n);
+ if( rc==SQLITE_OK ){
+ assert( (p->sharedMask & mask)==0 );
+ p->exclMask |= mask;
+ }
+ }
+ }
+
+ sqlite3_mutex_leave(pShmNode->mutex);
+
+ OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x %s\n",
+ p->id, (int)GetCurrentProcessId(), p->sharedMask, p->exclMask,
+ rc ? "failed" : "ok"));
+
+ ERR_TRACE(rc, ("os2ShmLock: ofst = %d, n = %d, flags = 0x%x -> %d \n",
+ ofst, n, flags, rc))
+
+ return rc;
+}
+
+/*
+** 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 os2ShmBarrier(
+ sqlite3_file *id /* Database file holding the shared memory */
+){
+ UNUSED_PARAMETER(id);
+ os2ShmEnterMutex();
+ os2ShmLeaveMutex();
+}
+
+#else
+# define os2ShmMap 0
+# define os2ShmLock 0
+# define os2ShmBarrier 0
+# define os2ShmUnmap 0
+#endif /* #ifndef SQLITE_OMIT_WAL */
+
+
/*
** This vector defines all the methods that can operate on an
** sqlite3_file for os2.
*/
static const sqlite3_io_methods os2IoMethod = {
- 1, /* iVersion */
- os2Close,
- os2Read,
- os2Write,
- os2Truncate,
- os2Sync,
- os2FileSize,
- os2Lock,
- os2Unlock,
- os2CheckReservedLock,
- os2FileControl,
- os2SectorSize,
- os2DeviceCharacteristics
+ 2, /* iVersion */
+ os2Close, /* xClose */
+ os2Read, /* xRead */
+ os2Write, /* xWrite */
+ os2Truncate, /* xTruncate */
+ os2Sync, /* xSync */
+ os2FileSize, /* xFileSize */
+ os2Lock, /* xLock */
+ os2Unlock, /* xUnlock */
+ os2CheckReservedLock, /* xCheckReservedLock */
+ os2FileControl, /* xFileControl */
+ os2SectorSize, /* xSectorSize */
+ os2DeviceCharacteristics, /* xDeviceCharacteristics */
+ os2ShmMap, /* xShmMap */
+ os2ShmLock, /* xShmLock */
+ os2ShmBarrier, /* xShmBarrier */
+ os2ShmUnmap /* xShmUnmap */
};
+
/***************************************************************************
** Here ends the I/O methods that form the sqlite3_io_methods object.
**
@@ -21349,51 +23815,58 @@ static const sqlite3_io_methods os2IoMethod = {
** hold at pVfs->mxPathname characters.
*/
static int getTempname(int nBuf, char *zBuf ){
- static const unsigned char zChars[] =
+ static const char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
int i, j;
- char zTempPathBuf[3];
- PSZ zTempPath = (PSZ)&zTempPathBuf;
- if( sqlite3_temp_directory ){
- zTempPath = sqlite3_temp_directory;
- }else{
- if( DosScanEnv( (PSZ)"TEMP", &zTempPath ) ){
- if( DosScanEnv( (PSZ)"TMP", &zTempPath ) ){
- if( DosScanEnv( (PSZ)"TMPDIR", &zTempPath ) ){
- ULONG ulDriveNum = 0, ulDriveMap = 0;
- DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap );
- sprintf( (char*)zTempPath, "%c:", (char)( 'A' + ulDriveNum - 1 ) );
- }
- }
- }
+ PSZ zTempPathCp;
+ char zTempPath[CCHMAXPATH];
+ ULONG ulDriveNum, ulDriveMap;
+
+ /* 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 );
+
+ if( sqlite3_temp_directory ) {
+ sqlite3_snprintf(CCHMAXPATH-30, zTempPath, "%s", sqlite3_temp_directory);
+ } else if( DosScanEnv( (PSZ)"TEMP", &zTempPathCp ) == NO_ERROR ||
+ DosScanEnv( (PSZ)"TMP", &zTempPathCp ) == NO_ERROR ||
+ DosScanEnv( (PSZ)"TMPDIR", &zTempPathCp ) == NO_ERROR ) {
+ char *zTempPathUTF = convertCpPathToUtf8( (char *)zTempPathCp );
+ sqlite3_snprintf(CCHMAXPATH-30, zTempPath, "%s", zTempPathUTF);
+ free( zTempPathUTF );
+ } else if( DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ) == NO_ERROR ) {
+ zTempPath[0] = (char)('A' + ulDriveNum - 1);
+ zTempPath[1] = ':';
+ zTempPath[2] = '\0';
+ } else {
+ zTempPath[0] = '\0';
}
+
/* Strip off a trailing slashes or backslashes, otherwise we would get *
* multiple (back)slashes which causes DosOpen() to fail. *
* Trailing spaces are not allowed, either. */
j = sqlite3Strlen30(zTempPath);
- while( j > 0 && ( zTempPath[j-1] == '\\' || zTempPath[j-1] == '/'
- || zTempPath[j-1] == ' ' ) ){
+ while( j > 0 && ( zTempPath[j-1] == '\\' || zTempPath[j-1] == '/' ||
+ zTempPath[j-1] == ' ' ) ){
j--;
}
zTempPath[j] = '\0';
- if( !sqlite3_temp_directory ){
- char *zTempPathUTF = convertCpPathToUtf8( zTempPath );
- sqlite3_snprintf( nBuf-30, zBuf,
- "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPathUTF );
- free( zTempPathUTF );
- }else{
- sqlite3_snprintf( nBuf-30, zBuf,
- "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath );
- }
- j = sqlite3Strlen30( zBuf );
+
+ /* We use 20 bytes to randomize the name */
+ sqlite3_snprintf(nBuf-22, zBuf,
+ "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath);
+ j = sqlite3Strlen30(zBuf);
sqlite3_randomness( 20, &zBuf[j] );
for( i = 0; i < 20; i++, j++ ){
- zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
+ zBuf[j] = zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
- OSTRACE2( "TEMP FILENAME: %s\n", zBuf );
+
+ OSTRACE(( "TEMP FILENAME: %s\n", zBuf ));
return SQLITE_OK;
}
@@ -21412,8 +23885,8 @@ static int os2FullPathname(
char *zRelativeCp = convertUtf8PathToCp( zRelative );
char zFullCp[CCHMAXPATH] = "\0";
char *zFullUTF;
- APIRET rc = DosQueryPathInfo( zRelativeCp, FIL_QUERYFULLNAME, zFullCp,
- CCHMAXPATH );
+ APIRET rc = DosQueryPathInfo( (PSZ)zRelativeCp, FIL_QUERYFULLNAME,
+ zFullCp, CCHMAXPATH );
free( zRelativeCp );
zFullUTF = convertCpPathToUtf8( zFullCp );
sqlite3_snprintf( nFull, zFull, zFullUTF );
@@ -21427,99 +23900,127 @@ static int os2FullPathname(
*/
static int os2Open(
sqlite3_vfs *pVfs, /* Not used */
- const char *zName, /* Name of the file */
+ 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 */
){
HFILE h;
- ULONG ulFileAttribute = FILE_NORMAL;
ULONG ulOpenFlags = 0;
ULONG ulOpenMode = 0;
+ ULONG ulAction = 0;
+ ULONG rc;
os2File *pFile = (os2File*)id;
- APIRET rc = NO_ERROR;
- ULONG ulAction;
+ const char *zUtf8Name = zName;
char *zNameCp;
- char zTmpname[CCHMAXPATH+1]; /* Buffer to hold name of temp file */
+ char zTmpname[CCHMAXPATH];
- /* If the second argument to this function is NULL, generate a
- ** temporary file name to use
+ int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
+ int isCreate = (flags & SQLITE_OPEN_CREATE);
+ int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
+#ifndef NDEBUG
+ int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
+ int isReadonly = (flags & SQLITE_OPEN_READONLY);
+ int eType = (flags & 0xFFFFFF00);
+ int isOpenJournal = (isCreate && (
+ eType==SQLITE_OPEN_MASTER_JOURNAL
+ || eType==SQLITE_OPEN_MAIN_JOURNAL
+ || eType==SQLITE_OPEN_WAL
+ ));
+#endif
+
+ UNUSED_PARAMETER(pVfs);
+ assert( id!=0 );
+
+ /* 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( !zName ){
- int rc = getTempname(CCHMAXPATH+1, zTmpname);
+ 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( pFile, 0, sizeof(*pFile) );
+ pFile->h = (HFILE)-1;
+
+ /* If the second argument to this function is NULL, generate a
+ ** temporary file name to use
+ */
+ if( !zUtf8Name ){
+ assert(isDelete && !isOpenJournal);
+ rc = getTempname(CCHMAXPATH, zTmpname);
if( rc!=SQLITE_OK ){
return rc;
}
- zName = zTmpname;
+ zUtf8Name = zTmpname;
}
-
- memset( pFile, 0, sizeof(*pFile) );
-
- OSTRACE2( "OPEN want %d\n", flags );
-
- if( flags & SQLITE_OPEN_READWRITE ){
+ if( isReadWrite ){
ulOpenMode |= OPEN_ACCESS_READWRITE;
- OSTRACE1( "OPEN read/write\n" );
}else{
ulOpenMode |= OPEN_ACCESS_READONLY;
- OSTRACE1( "OPEN read only\n" );
}
- if( flags & SQLITE_OPEN_CREATE ){
- ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW;
- OSTRACE1( "OPEN open new/create\n" );
+ /* Open in random access mode for possibly better speed. Allow full
+ ** sharing because file locks will provide exclusive access when needed.
+ ** The handle should not be inherited by child processes and we don't
+ ** want popups from the critical error handler.
+ */
+ ulOpenMode |= OPEN_FLAGS_RANDOM | OPEN_SHARE_DENYNONE |
+ OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_FAIL_ON_ERROR;
+
+ /* 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. */
+ ulOpenFlags |= OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_FAIL_IF_EXISTS;
+ }else if( isCreate ){
+ /* Open existing file, or create if it doesn't exist */
+ ulOpenFlags |= OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
}else{
- ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW;
- OSTRACE1( "OPEN open existing\n" );
+ /* Opens a file, only if it exists. */
+ ulOpenFlags |= OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
}
- if( flags & SQLITE_OPEN_MAIN_DB ){
- ulOpenMode |= OPEN_SHARE_DENYNONE;
- OSTRACE1( "OPEN share read/write\n" );
- }else{
- ulOpenMode |= OPEN_SHARE_DENYWRITE;
- OSTRACE1( "OPEN share read only\n" );
- }
-
- if( flags & SQLITE_OPEN_DELETEONCLOSE ){
- char pathUtf8[CCHMAXPATH];
-#ifdef NDEBUG /* when debugging we want to make sure it is deleted */
- ulFileAttribute = FILE_HIDDEN;
-#endif
- os2FullPathname( pVfs, zName, CCHMAXPATH, pathUtf8 );
- pFile->pathToDel = convertUtf8PathToCp( pathUtf8 );
- OSTRACE1( "OPEN hidden/delete on close file attributes\n" );
- }else{
- pFile->pathToDel = NULL;
- OSTRACE1( "OPEN normal file attribute\n" );
- }
-
- /* always open in random access mode for possibly better speed */
- ulOpenMode |= OPEN_FLAGS_RANDOM;
- ulOpenMode |= OPEN_FLAGS_FAIL_ON_ERROR;
- ulOpenMode |= OPEN_FLAGS_NOINHERIT;
-
- zNameCp = convertUtf8PathToCp( zName );
+ zNameCp = convertUtf8PathToCp( zUtf8Name );
rc = DosOpen( (PSZ)zNameCp,
&h,
&ulAction,
0L,
- ulFileAttribute,
+ FILE_NORMAL,
ulOpenFlags,
ulOpenMode,
(PEAOP2)NULL );
free( zNameCp );
+
if( rc != NO_ERROR ){
- OSTRACE7( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulAttr=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
- rc, zName, ulAction, ulFileAttribute, ulOpenFlags, ulOpenMode );
- if( pFile->pathToDel )
- free( pFile->pathToDel );
- pFile->pathToDel = NULL;
- if( flags & SQLITE_OPEN_READWRITE ){
- OSTRACE2( "OPEN %d Invalid handle\n", ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE) );
+ OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
+ rc, zUtf8Name, ulAction, ulOpenFlags, ulOpenMode ));
+
+ if( isReadWrite ){
return os2Open( pVfs, zName, id,
- ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE),
+ ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
pOutFlags );
}else{
return SQLITE_CANTOPEN;
@@ -21527,13 +24028,17 @@ static int os2Open(
}
if( pOutFlags ){
- *pOutFlags = flags & SQLITE_OPEN_READWRITE ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
+ *pOutFlags = isReadWrite ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
}
+ os2FullPathname( pVfs, zUtf8Name, sizeof( zTmpname ), zTmpname );
+ pFile->zFullPathCp = convertUtf8PathToCp( zTmpname );
pFile->pMethod = &os2IoMethod;
+ pFile->flags = flags;
pFile->h = h;
+
OpenCounter(+1);
- OSTRACE3( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags );
+ OSTRACE(( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags ));
return SQLITE_OK;
}
@@ -21545,13 +24050,16 @@ static int os2Delete(
const char *zFilename, /* Name of file to delete */
int syncDir /* Not used on os2 */
){
- APIRET rc = NO_ERROR;
- char *zFilenameCp = convertUtf8PathToCp( zFilename );
+ APIRET rc;
+ char *zFilenameCp;
SimulateIOError( return SQLITE_IOERR_DELETE );
+ zFilenameCp = convertUtf8PathToCp( zFilename );
rc = DosDelete( (PSZ)zFilenameCp );
free( zFilenameCp );
- OSTRACE2( "DELETE \"%s\"\n", zFilename );
- return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_DELETE;
+ OSTRACE(( "DELETE \"%s\"\n", zFilename ));
+ return (rc == NO_ERROR ||
+ rc == ERROR_FILE_NOT_FOUND ||
+ rc == ERROR_PATH_NOT_FOUND ) ? SQLITE_OK : SQLITE_IOERR_DELETE;
}
/*
@@ -21563,30 +24071,42 @@ static int os2Access(
int flags, /* Type of test to make on this file */
int *pOut /* Write results here */
){
+ APIRET rc;
FILESTATUS3 fsts3ConfigInfo;
- APIRET rc = NO_ERROR;
- char *zFilenameCp = convertUtf8PathToCp( zFilename );
+ char *zFilenameCp;
- memset( &fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo) );
+ UNUSED_PARAMETER(pVfs);
+ SimulateIOError( return SQLITE_IOERR_ACCESS; );
+
+ zFilenameCp = convertUtf8PathToCp( zFilename );
rc = DosQueryPathInfo( (PSZ)zFilenameCp, FIL_STANDARD,
&fsts3ConfigInfo, sizeof(FILESTATUS3) );
free( zFilenameCp );
- OSTRACE4( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n",
- fsts3ConfigInfo.attrFile, flags, rc );
+ OSTRACE(( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n",
+ fsts3ConfigInfo.attrFile, flags, rc ));
+
switch( flags ){
- case SQLITE_ACCESS_READ:
case SQLITE_ACCESS_EXISTS:
- rc = (rc == NO_ERROR);
- OSTRACE3( "ACCESS %s access of read and exists rc=%d\n", zFilename, rc );
+ /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file
+ ** as if it does not exist.
+ */
+ if( fsts3ConfigInfo.cbFile == 0 )
+ rc = ERROR_FILE_NOT_FOUND;
+ break;
+ case SQLITE_ACCESS_READ:
break;
case SQLITE_ACCESS_READWRITE:
- rc = (rc == NO_ERROR) && ( (fsts3ConfigInfo.attrFile & FILE_READONLY) == 0 );
- OSTRACE3( "ACCESS %s access of read/write rc=%d\n", zFilename, rc );
+ if( fsts3ConfigInfo.attrFile & FILE_READONLY )
+ rc = ERROR_ACCESS_DENIED;
break;
default:
+ rc = ERROR_FILE_NOT_FOUND;
assert( !"Invalid flags argument" );
}
- *pOut = rc;
+
+ *pOut = (rc == NO_ERROR);
+ OSTRACE(( "ACCESS %s flags %d: rc=%d\n", zFilename, flags, *pOut ));
+
return SQLITE_OK;
}
@@ -21601,11 +24121,10 @@ static int os2Access(
** within the shared library, and closing the shared library.
*/
static void *os2DlOpen(sqlite3_vfs *pVfs, const char *zFilename){
- UCHAR loadErr[256];
HMODULE hmod;
APIRET rc;
char *zFilenameCp = convertUtf8PathToCp(zFilename);
- rc = DosLoadModule((PSZ)loadErr, sizeof(loadErr), zFilenameCp, &hmod);
+ rc = DosLoadModule(NULL, 0, (PSZ)zFilenameCp, &hmod);
free(zFilenameCp);
return rc != NO_ERROR ? 0 : (void*)hmod;
}
@@ -21616,19 +24135,19 @@ static void *os2DlOpen(sqlite3_vfs *pVfs, const char *zFilename){
static void os2DlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
/* no-op */
}
-static void *os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){
+static void (*os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
PFN pfn;
APIRET rc;
- rc = DosQueryProcAddr((HMODULE)pHandle, 0L, zSymbol, &pfn);
+ rc = DosQueryProcAddr((HMODULE)pHandle, 0L, (PSZ)zSymbol, &pfn);
if( rc != NO_ERROR ){
/* if the symbol itself was not found, search again for the same
* symbol with an extra underscore, that might be needed depending
* on the calling convention */
char _zSymbol[256] = "_";
- strncat(_zSymbol, zSymbol, 255);
- rc = DosQueryProcAddr((HMODULE)pHandle, 0L, _zSymbol, &pfn);
+ strncat(_zSymbol, zSymbol, 254);
+ rc = DosQueryProcAddr((HMODULE)pHandle, 0L, (PSZ)_zSymbol, &pfn);
}
- return rc != NO_ERROR ? 0 : (void*)pfn;
+ return rc != NO_ERROR ? 0 : (void(*)(void))pfn;
}
static void os2DlClose(sqlite3_vfs *pVfs, void *pHandle){
DosFreeModule((HMODULE)pHandle);
@@ -21650,54 +24169,39 @@ static int os2Randomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf ){
n = nBuf;
memset(zBuf, 0, nBuf);
#else
- int sizeofULong = sizeof(ULONG);
- if( (int)sizeof(DATETIME) <= nBuf - n ){
- DATETIME x;
- DosGetDateTime(&x);
- memcpy(&zBuf[n], &x, sizeof(x));
- n += sizeof(x);
+ int i;
+ PPIB ppib;
+ PTIB ptib;
+ DATETIME dt;
+ static unsigned c = 0;
+ /* Ordered by variation probability */
+ static ULONG svIdx[6] = { QSV_MS_COUNT, QSV_TIME_LOW,
+ QSV_MAXPRMEM, QSV_MAXSHMEM,
+ QSV_TOTAVAILMEM, QSV_TOTRESMEM };
+
+ /* 8 bytes; timezone and weekday don't increase the randomness much */
+ if( (int)sizeof(dt)-3 <= nBuf - n ){
+ c += 0x0100;
+ DosGetDateTime(&dt);
+ dt.year = (USHORT)((dt.year - 1900) | c);
+ memcpy(&zBuf[n], &dt, sizeof(dt)-3);
+ n += sizeof(dt)-3;
}
- if( sizeofULong <= nBuf - n ){
- PPIB ppib;
- DosGetInfoBlocks(NULL, &ppib);
- memcpy(&zBuf[n], &ppib->pib_ulpid, sizeofULong);
- n += sizeofULong;
+ /* 4 bytes; PIDs and TIDs are 16 bit internally, so combine them */
+ if( (int)sizeof(ULONG) <= nBuf - n ){
+ DosGetInfoBlocks(&ptib, &ppib);
+ *(PULONG)&zBuf[n] = MAKELONG(ppib->pib_ulpid,
+ ptib->tib_ptib2->tib2_ultid);
+ n += sizeof(ULONG);
}
- if( sizeofULong <= nBuf - n ){
- PTIB ptib;
- DosGetInfoBlocks(&ptib, NULL);
- memcpy(&zBuf[n], &ptib->tib_ptib2->tib2_ultid, sizeofULong);
- n += sizeofULong;
- }
-
- /* if we still haven't filled the buffer yet the following will */
- /* grab everything once instead of making several calls for a single item */
- if( sizeofULong <= nBuf - n ){
- ULONG ulSysInfo[QSV_MAX];
- DosQuerySysInfo(1L, QSV_MAX, ulSysInfo, sizeofULong * QSV_MAX);
-
- memcpy(&zBuf[n], &ulSysInfo[QSV_MS_COUNT - 1], sizeofULong);
- n += sizeofULong;
-
- if( sizeofULong <= nBuf - n ){
- memcpy(&zBuf[n], &ulSysInfo[QSV_TIMER_INTERVAL - 1], sizeofULong);
- n += sizeofULong;
- }
- if( sizeofULong <= nBuf - n ){
- memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_LOW - 1], sizeofULong);
- n += sizeofULong;
- }
- if( sizeofULong <= nBuf - n ){
- memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_HIGH - 1], sizeofULong);
- n += sizeofULong;
- }
- if( sizeofULong <= nBuf - n ){
- memcpy(&zBuf[n], &ulSysInfo[QSV_TOTAVAILMEM - 1], sizeofULong);
- n += sizeofULong;
- }
- }
+ /* Up to 6 * 4 bytes; variables depend on the system state */
+ for( i = 0; i < 6 && (int)sizeof(ULONG) <= nBuf - n; i++ ){
+ DosQuerySysInfo(svIdx[i], svIdx[i],
+ (PULONG)&zBuf[n], sizeof(ULONG));
+ n += sizeof(ULONG);
+ }
#endif
return n;
@@ -21725,46 +24229,98 @@ SQLITE_API int sqlite3_current_time = 0;
#endif
/*
-** 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.
+** 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 0. Return 1 if the time and date cannot be found.
*/
-int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){
- double now;
- SHORT minute; /* needs to be able to cope with negative timezone offset */
- USHORT second, hour,
- day, month, year;
+static int os2CurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
+#ifdef SQLITE_TEST
+ static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
+#endif
+ int year, month, datepart, timepart;
+
DATETIME dt;
DosGetDateTime( &dt );
- second = (USHORT)dt.seconds;
- minute = (SHORT)dt.minutes + dt.timezone;
- hour = (USHORT)dt.hours;
- day = (USHORT)dt.day;
- month = (USHORT)dt.month;
- year = (USHORT)dt.year;
+
+ year = dt.year;
+ month = dt.month;
/* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html
- http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c */
- /* Calculate the Julian days */
- now = day - 32076 +
+ ** http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c
+ ** Calculate the Julian days
+ */
+ datepart = (int)dt.day - 32076 +
1461*(year + 4800 + (month - 14)/12)/4 +
367*(month - 2 - (month - 14)/12*12)/12 -
3*((year + 4900 + (month - 14)/12)/100)/4;
- /* Add the fractional hours, mins and seconds */
- now += (hour + 12.0)/24.0;
- now += minute/1440.0;
- now += second/86400.0;
- *prNow = now;
+ /* Time in milliseconds, hours to noon added */
+ timepart = 12*3600*1000 + dt.hundredths*10 + dt.seconds*1000 +
+ ((int)dt.minutes + dt.timezone)*60*1000 + dt.hours*3600*1000;
+
+ *piNow = (sqlite3_int64)datepart*86400*1000 + timepart;
+
#ifdef SQLITE_TEST
if( sqlite3_current_time ){
- *prNow = sqlite3_current_time/86400.0 + 2440587.5;
+ *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
}
#endif
+
+ UNUSED_PARAMETER(pVfs);
return 0;
}
+/*
+** 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 os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){
+ int rc;
+ sqlite3_int64 i;
+ rc = os2CurrentTimeInt64(pVfs, &i);
+ if( !rc ){
+ *prNow = i/86400000.0;
+ }
+ return rc;
+}
+
+/*
+** The idea is that this function works like a combination of
+** GetLastError() and FormatMessage() on windows (or errno and
+** strerror_r() on unix). After an error is returned by an OS
+** function, SQLite calls this function with zBuf pointing to
+** a buffer of nBuf bytes. The OS layer should populate the
+** buffer with a nul-terminated UTF-8 encoded error message
+** describing the last IO error to have occurred within the calling
+** thread.
+**
+** If the error message is too large for the supplied buffer,
+** it should be truncated. The return value of xGetLastError
+** is zero if the error message fits in the buffer, or non-zero
+** otherwise (if the message was truncated). If non-zero is returned,
+** then it is not necessary to include the nul-terminator character
+** in the output buffer.
+**
+** Not supplying an error message will have no adverse effect
+** on SQLite. It is fine to have an implementation that never
+** returns an error message:
+**
+** int xGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
+** assert(zBuf[0]=='\0');
+** return 0;
+** }
+**
+** However if an error message is supplied, it will be incorporated
+** by sqlite into the error message available to the user using
+** sqlite3_errmsg(), possibly making IO errors easier to debug.
+*/
static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
+ assert(zBuf[0]=='\0');
return 0;
}
@@ -21773,7 +24329,7 @@ static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
*/
SQLITE_API int sqlite3_os_init(void){
static sqlite3_vfs os2Vfs = {
- 1, /* iVersion */
+ 3, /* iVersion */
sizeof(os2File), /* szOsFile */
CCHMAXPATH, /* mxPathname */
0, /* pNext */
@@ -21791,10 +24347,15 @@ SQLITE_API int sqlite3_os_init(void){
os2Randomness, /* xRandomness */
os2Sleep, /* xSleep */
os2CurrentTime, /* xCurrentTime */
- os2GetLastError /* xGetLastError */
+ os2GetLastError, /* xGetLastError */
+ os2CurrentTimeInt64, /* xCurrentTimeInt64 */
+ 0, /* xSetSystemCall */
+ 0, /* xGetSystemCall */
+ 0 /* xNextSystemCall */
};
sqlite3_vfs_register(&os2Vfs, 1);
initUconvObjects();
+/* sqlite3OSTrace = 1; */
return SQLITE_OK;
}
SQLITE_API int sqlite3_os_end(void){
@@ -21868,7 +24429,7 @@ SQLITE_API int sqlite3_os_end(void){
** 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.
+** where the database is located.
*/
#if !defined(SQLITE_ENABLE_LOCKING_STYLE)
# if defined(__APPLE__)
@@ -21879,7 +24440,7 @@ SQLITE_API int sqlite3_os_end(void){
#endif
/*
-** Define the OS_VXWORKS pre-processor macro to 1 if building on
+** Define the OS_VXWORKS pre-processor macro to 1 if building on
** vxworks, or 0 otherwise.
*/
#ifndef OS_VXWORKS
@@ -21923,8 +24484,12 @@ SQLITE_API int sqlite3_os_end(void){
#include
#include
#include
+/* #include */
#include
#include
+#ifndef SQLITE_OMIT_WAL
+#include
+#endif
#if SQLITE_ENABLE_LOCKING_STYLE
# include
@@ -21941,6 +24506,10 @@ SQLITE_API int sqlite3_os_end(void){
# include
#endif
+#ifdef HAVE_UTIME
+# include
+#endif
+
/*
** Allowed values of unixFile.fsFlags
*/
@@ -21951,6 +24520,7 @@ SQLITE_API int sqlite3_os_end(void){
** the SQLITE_UNIX_THREADS macro.
*/
#if SQLITE_THREADSAFE
+/* # include */
# define SQLITE_UNIX_THREADS 1
#endif
@@ -21974,11 +24544,16 @@ SQLITE_API int sqlite3_os_end(void){
#define MAX_PATHNAME 512
/*
-** Only set the lastErrno if the error code is a real error and not
+** 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
*/
#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 */
/*
** Sometimes, after a file handle is closed by SQLite, the file descriptor
@@ -21986,7 +24561,6 @@ SQLITE_API int sqlite3_os_end(void){
** structure are used to store the file descriptor while waiting for an
** opportunity to either close or reuse it.
*/
-typedef struct UnixUnusedFd UnixUnusedFd;
struct UnixUnusedFd {
int fd; /* File descriptor to close */
int flags; /* Flags this file descriptor was opened with */
@@ -22000,27 +24574,25 @@ struct UnixUnusedFd {
typedef struct unixFile unixFile;
struct unixFile {
sqlite3_io_methods const *pMethod; /* Always the first entry */
- struct unixOpenCnt *pOpen; /* Info about all open fd's on this inode */
- struct unixLockInfo *pLock; /* Info about locks on this inode */
- int h; /* The file descriptor */
- int dirfd; /* File descriptor for the directory */
- unsigned char locktype; /* The type of lock held on this fd */
- int lastErrno; /* The unix errno from the last I/O error */
- void *lockingContext; /* Locking style specific state */
- UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
- int fileFlags; /* Miscellanous flags */
+ 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 char 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 */
#if SQLITE_ENABLE_LOCKING_STYLE
- int openFlags; /* The flags specified at open() */
+ int openFlags; /* The flags specified at open() */
#endif
#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
- unsigned fsFlags; /* cached details from statfs() */
-#endif
-#if SQLITE_THREADSAFE && defined(__linux__)
- pthread_t tid; /* The thread that "owns" this unixFile */
+ unsigned fsFlags; /* cached details from statfs() */
#endif
#if OS_VXWORKS
- int isDelete; /* Delete on close if true */
- struct vxworksFileId *pId; /* Unique file ID */
+ int isDelete; /* Delete on close if true */
+ struct vxworksFileId *pId; /* Unique file ID */
#endif
#ifndef NDEBUG
/* The next group of variables are used to track whether or not the
@@ -22028,14 +24600,14 @@ struct unixFile {
** 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.
+ ** 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 */
#endif
#ifdef SQLITE_TEST
- /* In test mode, increase the size of this structure a bit so that
+ /* 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];
@@ -22043,9 +24615,16 @@ struct unixFile {
};
/*
-** The following macros define bits in unixFile.fileFlags
+** Allowed values for the unixFile.ctrlFlags bitmask:
*/
-#define SQLITE_WHOLE_FILE_LOCKING 0x0001 /* Use whole-file locking */
+#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
/*
** Include code that is common to all os_*.c files
@@ -22083,25 +24662,14 @@ struct unixFile {
# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
#endif
-#ifdef SQLITE_DEBUG
-SQLITE_PRIVATE int sqlite3OSTrace = 0;
-#define OSTRACE1(X) if( sqlite3OSTrace ) sqlite3DebugPrintf(X)
-#define OSTRACE2(X,Y) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y)
-#define OSTRACE3(X,Y,Z) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z)
-#define OSTRACE4(X,Y,Z,A) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A)
-#define OSTRACE5(X,Y,Z,A,B) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A,B)
-#define OSTRACE6(X,Y,Z,A,B,C) \
- if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
-#define OSTRACE7(X,Y,Z,A,B,C,D) \
- if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
+#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 OSTRACE1(X)
-#define OSTRACE2(X,Y)
-#define OSTRACE3(X,Y,Z)
-#define OSTRACE4(X,Y,Z,A)
-#define OSTRACE5(X,Y,Z,A,B)
-#define OSTRACE6(X,Y,Z,A,B,C)
-#define OSTRACE7(X,Y,Z,A,B,C,D)
+# define OSTRACE(X)
#endif
/*
@@ -22110,8 +24678,8 @@ SQLITE_PRIVATE int sqlite3OSTrace = 0;
*/
#ifdef SQLITE_PERFORMANCE_TRACE
-/*
-** hwtime.h contains inline assembler code for implementing
+/*
+** hwtime.h contains inline assembler code for implementing
** high-performance timing routines.
*/
/************** Include hwtime.h in the middle of os_common.h ****************/
@@ -22169,7 +24737,7 @@ SQLITE_PRIVATE int sqlite3OSTrace = 0;
__asm__ __volatile__ ("rdtsc" : "=A" (val));
return val;
}
-
+
#elif (defined(__GNUC__) && defined(__ppc__))
__inline__ sqlite_uint64 sqlite3Hwtime(void){
@@ -22288,16 +24856,6 @@ SQLITE_API int sqlite3_open_file_count = 0;
# define O_BINARY 0
#endif
-/*
-** 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?
-*/
-#ifdef __DJGPP__
-# define fcntl(A,B,C) 0
-#endif
-
/*
** The threadid macro resolves to the thread-id or to 0. Used for
** testing and debugging only.
@@ -22308,15 +24866,225 @@ SQLITE_API int sqlite3_open_file_count = 0;
#define threadid 0
#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.
+**
+** The safest way to deal with the problem is to always use this wrapper
+** which always has the same well-defined interface.
+*/
+static int posixOpen(const char *zFile, int flags, int mode){
+ return open(zFile, flags, mode);
+}
+
+/* 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.
+*/
+static struct unix_syscall {
+ const char *zName; /* Name of the sytem 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)
+
+ { "stat", (sqlite3_syscall_ptr)stat, 0 },
+#define osStat ((int(*)(const char*,struct stat*))aSyscall[4].pCurrent)
+
+/*
+** 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?
+*/
+#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)
+
+#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
+ { "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)
+
+}; /* End of the overrideable system calls */
+
+/*
+** 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;
+
+ 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; il_whence==SEEK_SET );
- s = fcntl(fd, op, p);
+ 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,
@@ -22394,7 +25162,7 @@ static int lockTrace(int fd, int op, struct flock *p){
if( s==(-1) && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){
struct flock l2;
l2 = *p;
- fcntl(fd, F_GETLK, &l2);
+ osFcntl(fd, F_GETLK, &l2);
if( l2.l_type==F_RDLCK ){
zType = "RDLCK";
}else if( l2.l_type==F_WRLCK ){
@@ -22410,58 +25178,86 @@ static int lockTrace(int fd, int op, struct flock *p){
errno = savedErrno;
return s;
}
-#define fcntl lockTrace
+#undef osFcntl
+#define osFcntl lockTrace
#endif /* SQLITE_LOCK_TRACE */
-
+/*
+** Retry ftruncate() calls that fail due to EINTR
+*/
+static int robust_ftruncate(int h, sqlite3_int64 sz){
+ int rc;
+ do{ rc = osFtruncate(h,sz); }while( rc<0 && errno==EINTR );
+ return rc;
+}
/*
** 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
+** 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) {
- case 0:
+#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
+ 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:
+
+ case EACCES:
/* EACCES is like EAGAIN during locking operations, but not any other time*/
- if( (sqliteIOErr == SQLITE_IOERR_LOCK) ||
- (sqliteIOErr == SQLITE_IOERR_UNLOCK) ||
+ if( (sqliteIOErr == SQLITE_IOERR_LOCK) ||
+ (sqliteIOErr == SQLITE_IOERR_UNLOCK) ||
(sqliteIOErr == SQLITE_IOERR_RDLOCK) ||
(sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) ){
return SQLITE_BUSY;
}
/* else fall through */
- case EPERM:
+ 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
+ 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
+ case ENOTSUP:
+ /* invalid fd, unless during file system support introspection, in which
* it actually means what it says */
#endif
case EIO:
@@ -22471,11 +25267,13 @@ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
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:
+
+ default:
return sqliteIOErr;
}
}
@@ -22491,7 +25289,7 @@ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
**
** 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.
+** 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.
**
@@ -22507,7 +25305,7 @@ struct vxworksFileId {
};
#if OS_VXWORKS
-/*
+/*
** All unique filenames are held on a linked list headed by this
** variable:
*/
@@ -22579,7 +25377,7 @@ static struct vxworksFileId *vxworksFindFileId(const char *zAbsoluteName){
*/
unixEnterMutex();
for(pCandidate=vxworksFileList; pCandidate; pCandidate=pCandidate->pNext){
- if( pCandidate->nName==n
+ if( pCandidate->nName==n
&& memcmp(pCandidate->zCanonicalName, pNew->zCanonicalName, n)==0
){
sqlite3_free(pNew);
@@ -22672,7 +25470,7 @@ static void vxworksReleaseFileId(struct vxworksFileId *pId){
** 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
+** 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.
**
@@ -22680,13 +25478,12 @@ static void vxworksReleaseFileId(struct vxworksFileId *pId){
**
** 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 unixFile structure contains
-** a pointer to an unixOpenCnt structure. There is one unixOpenCnt structure
-** per open inode, which means that multiple unixFile can point to a single
-** unixOpenCnt. When an attempt is made to close an unixFile, if there 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 unixOpenCnt structure keeps a list of file descriptors that need to
+** 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.
**
@@ -22701,46 +25498,19 @@ static void vxworksReleaseFileId(struct vxworksFileId *pId){
** 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.
-** We have to do a run-time check to discover the behavior of the
+** One has to do a run-time check to discover the behavior of the
** current process.
**
-** On systems where thread A is unable to modify locks created by
-** thread B, we have to keep track of which thread created each
-** lock. Hence there is an extra field in the key to the unixLockInfo
-** structure to record this information. And on those systems it
-** is illegal to begin a transaction in one thread and finish it
-** in another. For this latter restriction, there is no work-around.
-** It is a limitation of LinuxThreads.
+** 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.
*/
-/*
-** Set or check the unixFile.tid field. This field is set when an unixFile
-** is first opened. All subsequent uses of the unixFile verify that the
-** same thread is operating on the unixFile. Some operating systems do
-** not allow locks to be overridden by other threads and that restriction
-** means that sqlite3* database handles cannot be moved from one thread
-** to another while locks are held.
-**
-** Version 3.3.1 (2006-01-15): unixFile can be moved from one thread to
-** another as long as we are running on a system that supports threads
-** overriding each others locks (which is now the most common behavior)
-** or if no locks are held. But the unixFile.pLock field needs to be
-** recomputed because its key includes the thread-id. See the
-** transferOwnership() function below for additional information
-*/
-#if SQLITE_THREADSAFE && defined(__linux__)
-# define SET_THREADID(X) (X)->tid = pthread_self()
-# define CHECK_THREADID(X) (threadsOverrideEachOthersLocks==0 && \
- !pthread_equal((X)->tid, pthread_self()))
-#else
-# define SET_THREADID(X)
-# define CHECK_THREADID(X) 0
-#endif
-
/*
** An instance of the following structure serves as the key used
-** to locate a particular unixOpenCnt structure given its inode. This
-** is the same as the unixLockKey except that the thread ID is omitted.
+** to locate a particular unixInodeInfo object.
*/
struct unixFileId {
dev_t dev; /* Device number */
@@ -22751,23 +25521,6 @@ struct unixFileId {
#endif
};
-/*
-** An instance of the following structure serves as the key used
-** to locate a particular unixLockInfo structure given its inode.
-**
-** If threads cannot override each others locks (LinuxThreads), then we
-** set the unixLockKey.tid field to the thread ID. If threads can override
-** each others locks (Posix and NPTL) then tid is always set to zero.
-** tid is omitted if we compile without threading support or on an OS
-** other than linux.
-*/
-struct unixLockKey {
- struct unixFileId fid; /* Unique identifier for the file */
-#if SQLITE_THREADSAFE && defined(__linux__)
- pthread_t tid; /* Thread ID of lock owner. Zero if not using LinuxThreads */
-#endif
-};
-
/*
** An instance of the following structure is allocated for each open
** inode. Or, on LinuxThreads, there is one of these structures for
@@ -22777,230 +25530,185 @@ struct unixLockKey {
** structure contains a pointer to an instance of this object and this
** object keeps a count of the number of unixFile pointing to it.
*/
-struct unixLockInfo {
- struct unixLockKey lockKey; /* The lookup key */
- int cnt; /* Number of SHARED locks held */
- int locktype; /* One of SHARED_LOCK, RESERVED_LOCK etc. */
+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 */
-#if defined(SQLITE_ENABLE_LOCKING_STYLE)
+ 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
- struct unixLockInfo *pNext; /* List of all unixLockInfo objects */
- struct unixLockInfo *pPrev; /* .... doubly linked */
-};
-
-/*
-** An instance of the following structure is allocated for each open
-** inode. This structure keeps track of the number of locks on that
-** inode. If a close is attempted against an inode that is holding
-** locks, the close is deferred until all locks clear by adding the
-** file descriptor to be closed to the pending list.
-**
-** TODO: Consider changing this so that there is only a single file
-** descriptor for each open file, even when it is opened multiple times.
-** The close() system call would only occur when the last database
-** using the file closes.
-*/
-struct unixOpenCnt {
- struct unixFileId fileId; /* The lookup key */
- int nRef; /* Number of pointers to this structure */
- int nLock; /* Number of outstanding locks */
- UnixUnusedFd *pUnused; /* Unused file descriptors to close */
#if OS_VXWORKS
- sem_t *pSem; /* Named POSIX semaphore */
- char aSemName[MAX_PATHNAME+2]; /* Name of that semaphore */
+ sem_t *pSem; /* Named POSIX semaphore */
+ char aSemName[MAX_PATHNAME+2]; /* Name of that semaphore */
#endif
- struct unixOpenCnt *pNext, *pPrev; /* List of all unixOpenCnt objects */
};
/*
-** Lists of all unixLockInfo and unixOpenCnt objects. These used to be hash
-** tables. But the number of objects is rarely more than a dozen and
-** never exceeds a few thousand. And lookup is not on a critical
-** path so a simple linked list will suffice.
+** A lists of all unixInodeInfo objects.
*/
-static struct unixLockInfo *lockList = 0;
-static struct unixOpenCnt *openList = 0;
+static unixInodeInfo *inodeList = 0;
/*
-** This variable remembers whether or not threads can override each others
-** locks.
**
-** 0: No. Threads cannot override each others locks. (LinuxThreads)
-** 1: Yes. Threads can override each others locks. (Posix & NLPT)
-** -1: We don't know yet.
+** This function - unixLogError_x(), is only ever called via the macro
+** unixLogError().
**
-** On some systems, we know at compile-time if threads can override each
-** others locks. On those systems, the SQLITE_THREAD_OVERRIDE_LOCK macro
-** will be set appropriately. On other systems, we have to check at
-** runtime. On these latter systems, SQLTIE_THREAD_OVERRIDE_LOCK is
-** undefined.
+** 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().
**
-** This variable normally has file scope only. But during testing, we make
-** it a global so that the test code can change its value in order to verify
-** that the right stuff happens in either case.
+** 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 the associated file-system path,
+** if any.
*/
-#if SQLITE_THREADSAFE && defined(__linux__)
-# ifndef SQLITE_THREAD_OVERRIDE_LOCK
-# define SQLITE_THREAD_OVERRIDE_LOCK -1
-# endif
-# ifdef SQLITE_TEST
-int threadsOverrideEachOthersLocks = SQLITE_THREAD_OVERRIDE_LOCK;
-# else
-static int threadsOverrideEachOthersLocks = SQLITE_THREAD_OVERRIDE_LOCK;
-# endif
+#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 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
-/*
-** This structure holds information passed into individual test
-** threads by the testThreadLockingBehavior() routine.
-*/
-struct threadTestData {
- int fd; /* File to be locked */
- struct flock lock; /* The locking operation */
- int result; /* Result of the locking operation */
-};
+ assert( errcode!=SQLITE_OK );
+ if( zPath==0 ) zPath = "";
+ sqlite3_log(errcode,
+ "os_unix.c:%d: (%d) %s(%s) - %s",
+ iLine, iErrno, zFunc, zPath, zErr
+ );
-#if SQLITE_THREADSAFE && defined(__linux__)
-/*
-** This function is used as the main routine for a thread launched by
-** testThreadLockingBehavior(). It tests whether the shared-lock obtained
-** by the main thread in testThreadLockingBehavior() conflicts with a
-** hypothetical write-lock obtained by this thread on the same file.
-**
-** The write-lock is not actually acquired, as this is not possible if
-** the file is open in read-only mode (see ticket #3472).
-*/
-static void *threadLockingTest(void *pArg){
- struct threadTestData *pData = (struct threadTestData*)pArg;
- pData->result = fcntl(pData->fd, F_GETLK, &pData->lock);
- return pArg;
+ return errcode;
}
-#endif /* SQLITE_THREADSAFE && defined(__linux__) */
-
-#if SQLITE_THREADSAFE && defined(__linux__)
/*
-** This procedure attempts to determine whether or not threads
-** can override each others locks then sets the
-** threadsOverrideEachOthersLocks variable appropriately.
+** 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.
+**
+** 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 void testThreadLockingBehavior(int fd_orig){
- int fd;
- int rc;
- struct threadTestData d;
- struct flock l;
- pthread_t t;
-
- fd = dup(fd_orig);
- if( fd<0 ) return;
- memset(&l, 0, sizeof(l));
- l.l_type = F_RDLCK;
- l.l_len = 1;
- l.l_start = 0;
- l.l_whence = SEEK_SET;
- rc = fcntl(fd_orig, F_SETLK, &l);
- if( rc!=0 ) return;
- memset(&d, 0, sizeof(d));
- d.fd = fd;
- d.lock = l;
- d.lock.l_type = F_WRLCK;
- if( pthread_create(&t, 0, threadLockingTest, &d)==0 ){
- pthread_join(t, 0);
+static void robust_close(unixFile *pFile, int h, int lineno){
+ if( osClose(h) ){
+ unixLogErrorAtLine(SQLITE_IOERR_CLOSE, "close",
+ pFile ? pFile->zPath : 0, lineno);
}
- close(fd);
- if( d.result!=0 ) return;
- threadsOverrideEachOthersLocks = (d.lock.l_type==F_UNLCK);
}
-#endif /* SQLITE_THREADSAFE && defined(__linux__) */
/*
-** Release a unixLockInfo structure previously allocated by findLockInfo().
+** 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;
+}
+
+/*
+** Release a unixInodeInfo structure previously allocated by findInodeInfo().
**
** The mutex entered using the unixEnterMutex() function must be held
** when this function is called.
*/
-static void releaseLockInfo(struct unixLockInfo *pLock){
+static void releaseInodeInfo(unixFile *pFile){
+ unixInodeInfo *pInode = pFile->pInode;
assert( unixMutexHeld() );
- if( pLock ){
- pLock->nRef--;
- if( pLock->nRef==0 ){
- if( pLock->pPrev ){
- assert( pLock->pPrev->pNext==pLock );
- pLock->pPrev->pNext = pLock->pNext;
+ 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( lockList==pLock );
- lockList = pLock->pNext;
+ assert( inodeList==pInode );
+ inodeList = pInode->pNext;
}
- if( pLock->pNext ){
- assert( pLock->pNext->pPrev==pLock );
- pLock->pNext->pPrev = pLock->pPrev;
+ if( pInode->pNext ){
+ assert( pInode->pNext->pPrev==pInode );
+ pInode->pNext->pPrev = pInode->pPrev;
}
- sqlite3_free(pLock);
+ sqlite3_free(pInode);
}
}
}
/*
-** Release a unixOpenCnt structure previously allocated by findLockInfo().
-**
-** The mutex entered using the unixEnterMutex() function must be held
-** when this function is called.
-*/
-static void releaseOpenCnt(struct unixOpenCnt *pOpen){
- assert( unixMutexHeld() );
- if( pOpen ){
- pOpen->nRef--;
- if( pOpen->nRef==0 ){
- if( pOpen->pPrev ){
- assert( pOpen->pPrev->pNext==pOpen );
- pOpen->pPrev->pNext = pOpen->pNext;
- }else{
- assert( openList==pOpen );
- openList = pOpen->pNext;
- }
- if( pOpen->pNext ){
- assert( pOpen->pNext->pPrev==pOpen );
- pOpen->pNext->pPrev = pOpen->pPrev;
- }
-#if SQLITE_THREADSAFE && defined(__linux__)
- assert( !pOpen->pUnused || threadsOverrideEachOthersLocks==0 );
-#endif
-
- /* If pOpen->pUnused is not null, then memory and file-descriptors
- ** are leaked.
- **
- ** This will only happen if, under Linuxthreads, the user has opened
- ** a transaction in one thread, then attempts to close the database
- ** handle from another thread (without first unlocking the db file).
- ** This is a misuse. */
- sqlite3_free(pOpen);
- }
- }
-}
-
-/*
-** Given a file descriptor, locate unixLockInfo and unixOpenCnt structures that
-** describes that file descriptor. Create new ones if necessary. The
-** return values might be uninitialized if an error occurs.
+** 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 findLockInfo(
+static int findInodeInfo(
unixFile *pFile, /* Unix file with file desc used in the key */
- struct unixLockInfo **ppLock, /* Return the unixLockInfo structure here */
- struct unixOpenCnt **ppOpen /* Return the unixOpenCnt structure here */
+ unixInodeInfo **ppInode /* Return the unixInodeInfo object here */
){
int rc; /* System call return code */
int fd; /* The file descriptor for pFile */
- struct unixLockKey lockKey; /* Lookup key for the unixLockInfo structure */
- struct unixFileId fileId; /* Lookup key for the unixOpenCnt struct */
+ struct unixFileId fileId; /* Lookup key for the unixInodeInfo */
struct stat statbuf; /* Low-level file information */
- struct unixLockInfo *pLock = 0;/* Candidate unixLockInfo object */
- struct unixOpenCnt *pOpen; /* Candidate unixOpenCnt object */
+ unixInodeInfo *pInode = 0; /* Candidate unixInodeInfo object */
assert( unixMutexHeld() );
@@ -23008,7 +25716,7 @@ static int findLockInfo(
** create a unique name for the file.
*/
fd = pFile->h;
- rc = fstat(fd, &statbuf);
+ rc = osFstat(fd, &statbuf);
if( rc!=0 ){
pFile->lastErrno = errno;
#ifdef EOVERFLOW
@@ -23029,12 +25737,12 @@ static int findLockInfo(
** the first page of the database, no damage is done.
*/
if( statbuf.st_size==0 && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS)!=0 ){
- rc = write(fd, "S", 1);
+ do{ rc = osWrite(fd, "S", 1); }while( rc<0 && errno==EINTR );
if( rc!=1 ){
pFile->lastErrno = errno;
return SQLITE_IOERR;
}
- rc = fstat(fd, &statbuf);
+ rc = osFstat(fd, &statbuf);
if( rc!=0 ){
pFile->lastErrno = errno;
return SQLITE_IOERR;
@@ -23042,123 +25750,36 @@ static int findLockInfo(
}
#endif
- memset(&lockKey, 0, sizeof(lockKey));
- lockKey.fid.dev = statbuf.st_dev;
+ memset(&fileId, 0, sizeof(fileId));
+ fileId.dev = statbuf.st_dev;
#if OS_VXWORKS
- lockKey.fid.pId = pFile->pId;
+ fileId.pId = pFile->pId;
#else
- lockKey.fid.ino = statbuf.st_ino;
+ fileId.ino = statbuf.st_ino;
#endif
-#if SQLITE_THREADSAFE && defined(__linux__)
- if( threadsOverrideEachOthersLocks<0 ){
- testThreadLockingBehavior(fd);
+ pInode = inodeList;
+ while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){
+ pInode = pInode->pNext;
}
- lockKey.tid = threadsOverrideEachOthersLocks ? 0 : pthread_self();
-#endif
- fileId = lockKey.fid;
- if( ppLock!=0 ){
- pLock = lockList;
- while( pLock && memcmp(&lockKey, &pLock->lockKey, sizeof(lockKey)) ){
- pLock = pLock->pNext;
+ if( pInode==0 ){
+ pInode = sqlite3_malloc( sizeof(*pInode) );
+ if( pInode==0 ){
+ return SQLITE_NOMEM;
}
- if( pLock==0 ){
- pLock = sqlite3_malloc( sizeof(*pLock) );
- if( pLock==0 ){
- rc = SQLITE_NOMEM;
- goto exit_findlockinfo;
- }
- memcpy(&pLock->lockKey,&lockKey,sizeof(lockKey));
- pLock->nRef = 1;
- pLock->cnt = 0;
- pLock->locktype = 0;
-#if defined(SQLITE_ENABLE_LOCKING_STYLE)
- pLock->sharedByte = 0;
-#endif
- pLock->pNext = lockList;
- pLock->pPrev = 0;
- if( lockList ) lockList->pPrev = pLock;
- lockList = pLock;
- }else{
- pLock->nRef++;
- }
- *ppLock = pLock;
+ 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++;
}
- if( ppOpen!=0 ){
- pOpen = openList;
- while( pOpen && memcmp(&fileId, &pOpen->fileId, sizeof(fileId)) ){
- pOpen = pOpen->pNext;
- }
- if( pOpen==0 ){
- pOpen = sqlite3_malloc( sizeof(*pOpen) );
- if( pOpen==0 ){
- releaseLockInfo(pLock);
- rc = SQLITE_NOMEM;
- goto exit_findlockinfo;
- }
- memset(pOpen, 0, sizeof(*pOpen));
- pOpen->fileId = fileId;
- pOpen->nRef = 1;
- pOpen->pNext = openList;
- if( openList ) openList->pPrev = pOpen;
- openList = pOpen;
- }else{
- pOpen->nRef++;
- }
- *ppOpen = pOpen;
- }
-
-exit_findlockinfo:
- return rc;
+ *ppInode = pInode;
+ return SQLITE_OK;
}
-/*
-** If we are currently in a different thread than the thread that the
-** unixFile argument belongs to, then transfer ownership of the unixFile
-** over to the current thread.
-**
-** A unixFile is only owned by a thread on systems that use LinuxThreads.
-**
-** Ownership transfer is only allowed if the unixFile is currently unlocked.
-** If the unixFile is locked and an ownership is wrong, then return
-** SQLITE_MISUSE. SQLITE_OK is returned if everything works.
-*/
-#if SQLITE_THREADSAFE && defined(__linux__)
-static int transferOwnership(unixFile *pFile){
- int rc;
- pthread_t hSelf;
- if( threadsOverrideEachOthersLocks ){
- /* Ownership transfers not needed on this system */
- return SQLITE_OK;
- }
- hSelf = pthread_self();
- if( pthread_equal(pFile->tid, hSelf) ){
- /* We are still in the same thread */
- OSTRACE1("No-transfer, same thread\n");
- return SQLITE_OK;
- }
- if( pFile->locktype!=NO_LOCK ){
- /* We cannot change ownership while we are holding a lock! */
- return SQLITE_MISUSE_BKPT;
- }
- OSTRACE4("Transfer ownership of %d from %d to %d\n",
- pFile->h, pFile->tid, hSelf);
- pFile->tid = hSelf;
- if (pFile->pLock != NULL) {
- releaseLockInfo(pFile->pLock);
- rc = findLockInfo(pFile, &pFile->pLock, 0);
- OSTRACE5("LOCK %d is now %s(%s,%d)\n", pFile->h,
- locktypeName(pFile->locktype),
- locktypeName(pFile->pLock->locktype), pFile->pLock->cnt);
- return rc;
- } else {
- return SQLITE_OK;
- }
-}
-#else /* if not SQLITE_THREADSAFE */
- /* On single-threaded builds, ownership transfer is a no-op */
-# define transferOwnership(X) SQLITE_OK
-#endif /* SQLITE_THREADSAFE */
-
/*
** This routine checks if there is a RESERVED lock held on the specified
@@ -23174,41 +25795,87 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
assert( pFile );
- unixEnterMutex(); /* Because pFile->pLock is shared across threads */
+ unixEnterMutex(); /* Because pFile->pInode is shared across threads */
/* Check if a thread in this process holds such a lock */
- if( pFile->pLock->locktype>SHARED_LOCK ){
+ if( pFile->pInode->eFileLock>SHARED_LOCK ){
reserved = 1;
}
/* Otherwise see if some other process holds it.
*/
#ifndef __DJGPP__
- if( !reserved ){
+ 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 (-1 == fcntl(pFile->h, F_GETLK, &lock)) {
- int tErrno = errno;
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK);
- pFile->lastErrno = tErrno;
+ if( osFcntl(pFile->h, F_GETLK, &lock) ){
+ rc = SQLITE_IOERR_CHECKRESERVEDLOCK;
+ pFile->lastErrno = errno;
} else if( lock.l_type!=F_UNLCK ){
reserved = 1;
}
}
#endif
-
+
unixLeaveMutex();
- OSTRACE4("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved);
+ OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved));
*pResOut = reserved;
return rc;
}
/*
-** Lock the file with the lock specified by parameter locktype - one
+** 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()).
+*/
+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);
+ }
+ return rc;
+}
+
+/*
+** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
@@ -23231,7 +25898,7 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-static int unixLock(sqlite3_file *id, int locktype){
+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
@@ -23249,7 +25916,7 @@ static int unixLock(sqlite3_file *id, int locktype){
**
** 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'.
+ ** '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
@@ -23263,7 +25930,7 @@ static int unixLock(sqlite3_file *id, int locktype){
** 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.
+ ** 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
@@ -23272,23 +25939,22 @@ static int unixLock(sqlite3_file *id, int locktype){
*/
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
- struct unixLockInfo *pLock = pFile->pLock;
+ unixInodeInfo *pInode = pFile->pInode;
struct flock lock;
- int s = 0;
int tErrno = 0;
assert( pFile );
- OSTRACE7("LOCK %d %s was %s(%s,%d) pid=%d (unix)\n", pFile->h,
- locktypeName(locktype), locktypeName(pFile->locktype),
- locktypeName(pLock->locktype), pLock->cnt , getpid());
+ OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (unix)\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 end_lock: exit path, as
** unixEnterMutex() hasn't been called yet.
*/
- if( pFile->locktype>=locktype ){
- OSTRACE3("LOCK %d %s ok (already held) (unix)\n", pFile->h,
- locktypeName(locktype));
+ if( pFile->eFileLock>=eFileLock ){
+ OSTRACE(("LOCK %d %s ok (already held) (unix)\n", pFile->h,
+ azFileLock(eFileLock)));
return SQLITE_OK;
}
@@ -23297,28 +25963,20 @@ static int unixLock(sqlite3_file *id, int locktype){
** (2) SQLite never explicitly requests a pendig lock.
** (3) A shared lock is always held when a reserve lock is requested.
*/
- assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
- assert( locktype!=PENDING_LOCK );
- assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
+ 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->pLock is shared across threads
+ /* This mutex is needed because pFile->pInode is shared across threads
*/
unixEnterMutex();
-
- /* Make sure the current thread owns the pFile.
- */
- rc = transferOwnership(pFile);
- if( rc!=SQLITE_OK ){
- unixLeaveMutex();
- return rc;
- }
- pLock = pFile->pLock;
+ 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->locktype!=pLock->locktype &&
- (pLock->locktype>=PENDING_LOCK || locktype>SHARED_LOCK))
+ if( (pFile->eFileLock!=pInode->eFileLock &&
+ (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK))
){
rc = SQLITE_BUSY;
goto end_lock;
@@ -23328,14 +25986,14 @@ static int unixLock(sqlite3_file *id, int locktype){
** has a SHARED or RESERVED lock, then increment reference counts and
** return SQLITE_OK.
*/
- if( locktype==SHARED_LOCK &&
- (pLock->locktype==SHARED_LOCK || pLock->locktype==RESERVED_LOCK) ){
- assert( locktype==SHARED_LOCK );
- assert( pFile->locktype==0 );
- assert( pLock->cnt>0 );
- pFile->locktype = SHARED_LOCK;
- pLock->cnt++;
- pFile->pOpen->nLock++;
+ 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;
}
@@ -23346,16 +26004,15 @@ static int unixLock(sqlite3_file *id, int locktype){
*/
lock.l_len = 1L;
lock.l_whence = SEEK_SET;
- if( locktype==SHARED_LOCK
- || (locktype==EXCLUSIVE_LOCK && pFile->locktypeeFileLockh, F_SETLK, &lock);
- if( s==(-1) ){
+ if( unixFileLock(pFile, &lock) ){
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
- if( IS_LOCK_ERROR(rc) ){
+ if( rc!=SQLITE_BUSY ){
pFile->lastErrno = tErrno;
}
goto end_lock;
@@ -23366,42 +26023,40 @@ static int unixLock(sqlite3_file *id, int locktype){
/* If control gets to this point, then actually go ahead and make
** operating system calls for the specified lock.
*/
- if( locktype==SHARED_LOCK ){
- assert( pLock->cnt==0 );
- assert( pLock->locktype==0 );
+ 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( (s = fcntl(pFile->h, F_SETLK, &lock))==(-1) ){
+ if( unixFileLock(pFile, &lock) ){
tErrno = errno;
+ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
}
+
/* Drop the temporary PENDING lock */
lock.l_start = PENDING_BYTE;
lock.l_len = 1L;
lock.l_type = F_UNLCK;
- if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){
- if( s != -1 ){
- /* This could happen with a network mount */
- tErrno = errno;
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
- if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
- }
- goto end_lock;
- }
+ if( unixFileLock(pFile, &lock) && rc==SQLITE_OK ){
+ /* This could happen with a network mount */
+ tErrno = errno;
+ rc = SQLITE_IOERR_UNLOCK;
}
- if( s==(-1) ){
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
- if( IS_LOCK_ERROR(rc) ){
+
+ if( rc ){
+ if( rc!=SQLITE_BUSY ){
pFile->lastErrno = tErrno;
}
+ goto end_lock;
}else{
- pFile->locktype = SHARED_LOCK;
- pFile->pOpen->nLock++;
- pLock->cnt = 1;
+ pFile->eFileLock = SHARED_LOCK;
+ pInode->nLock++;
+ pInode->nShared = 1;
}
- }else if( locktype==EXCLUSIVE_LOCK && pLock->cnt>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;
@@ -23410,29 +26065,27 @@ static int unixLock(sqlite3_file *id, int locktype){
** assumed that there is a SHARED or greater lock on the file
** already.
*/
- assert( 0!=pFile->locktype );
+ assert( 0!=pFile->eFileLock );
lock.l_type = F_WRLCK;
- switch( locktype ){
- case RESERVED_LOCK:
- lock.l_start = RESERVED_BYTE;
- break;
- case EXCLUSIVE_LOCK:
- lock.l_start = SHARED_FIRST;
- lock.l_len = SHARED_SIZE;
- break;
- default:
- assert(0);
+
+ 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;
}
- s = fcntl(pFile->h, F_SETLK, &lock);
- if( s==(-1) ){
+
+ if( unixFileLock(pFile, &lock) ){
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
- if( IS_LOCK_ERROR(rc) ){
+ if( rc!=SQLITE_BUSY ){
pFile->lastErrno = tErrno;
}
}
}
-
+
#ifndef NDEBUG
/* Set up the transaction-counter change checking flags when
@@ -23441,8 +26094,8 @@ static int unixLock(sqlite3_file *id, int locktype){
** write operation (not a hot journal rollback).
*/
if( rc==SQLITE_OK
- && pFile->locktype<=SHARED_LOCK
- && locktype==RESERVED_LOCK
+ && pFile->eFileLock<=SHARED_LOCK
+ && eFileLock==RESERVED_LOCK
){
pFile->transCntrChng = 0;
pFile->dbUpdate = 0;
@@ -23452,47 +26105,17 @@ static int unixLock(sqlite3_file *id, int locktype){
if( rc==SQLITE_OK ){
- pFile->locktype = locktype;
- pLock->locktype = locktype;
- }else if( locktype==EXCLUSIVE_LOCK ){
- pFile->locktype = PENDING_LOCK;
- pLock->locktype = PENDING_LOCK;
+ pFile->eFileLock = eFileLock;
+ pInode->eFileLock = eFileLock;
+ }else if( eFileLock==EXCLUSIVE_LOCK ){
+ pFile->eFileLock = PENDING_LOCK;
+ pInode->eFileLock = PENDING_LOCK;
}
end_lock:
unixLeaveMutex();
- OSTRACE4("LOCK %d %s %s (unix)\n", pFile->h, locktypeName(locktype),
- rc==SQLITE_OK ? "ok" : "failed");
- return rc;
-}
-
-/*
-** Close all file descriptors accumuated in the unixOpenCnt->pUnused list.
-** If all such file descriptors are closed without error, the list is
-** cleared and SQLITE_OK returned.
-**
-** Otherwise, if an error occurs, then successfully closed file descriptor
-** entries are removed from the list, and SQLITE_IOERR_CLOSE returned.
-** not deleted and SQLITE_IOERR_CLOSE returned.
-*/
-static int closePendingFds(unixFile *pFile){
- int rc = SQLITE_OK;
- struct unixOpenCnt *pOpen = pFile->pOpen;
- UnixUnusedFd *pError = 0;
- UnixUnusedFd *p;
- UnixUnusedFd *pNext;
- for(p=pOpen->pUnused; p; p=pNext){
- pNext = p->pNext;
- if( close(p->fd) ){
- pFile->lastErrno = errno;
- rc = SQLITE_IOERR_CLOSE;
- p->pNext = pError;
- pError = p;
- }else{
- sqlite3_free(p);
- }
- }
- pOpen->pUnused = pError;
+ OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock),
+ rc==SQLITE_OK ? "ok" : "failed"));
return rc;
}
@@ -23501,52 +26124,49 @@ static int closePendingFds(unixFile *pFile){
** pUnused list.
*/
static void setPendingFd(unixFile *pFile){
- struct unixOpenCnt *pOpen = pFile->pOpen;
+ unixInodeInfo *pInode = pFile->pInode;
UnixUnusedFd *p = pFile->pUnused;
- p->pNext = pOpen->pUnused;
- pOpen->pUnused = p;
+ p->pNext = pInode->pUnused;
+ pInode->pUnused = p;
pFile->h = -1;
pFile->pUnused = 0;
}
/*
-** Lower the locking level on file descriptor pFile to locktype. locktype
+** 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
+** 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 _posixUnlock(sqlite3_file *id, int locktype, int handleNFSUnlock){
+static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
unixFile *pFile = (unixFile*)id;
- struct unixLockInfo *pLock;
+ unixInodeInfo *pInode;
struct flock lock;
int rc = SQLITE_OK;
int h;
- int tErrno; /* Error code from system call errors */
assert( pFile );
- OSTRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d (unix)\n", pFile->h, locktype,
- pFile->locktype, pFile->pLock->locktype, pFile->pLock->cnt, getpid());
+ 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( locktype<=SHARED_LOCK );
- if( pFile->locktype<=locktype ){
+ assert( eFileLock<=SHARED_LOCK );
+ if( pFile->eFileLock<=eFileLock ){
return SQLITE_OK;
}
- if( CHECK_THREADID(pFile) ){
- return SQLITE_MISUSE_BKPT;
- }
unixEnterMutex();
h = pFile->h;
- pLock = pFile->pLock;
- assert( pLock->cnt!=0 );
- if( pFile->locktype>SHARED_LOCK ){
- assert( pLock->locktype==pFile->locktype );
+ pInode = pFile->pInode;
+ assert( pInode->nShared!=0 );
+ if( pFile->eFileLock>SHARED_LOCK ){
+ assert( pInode->eFileLock==pFile->eFileLock );
SimulateIOErrorBenign(1);
SimulateIOError( h=(-1) )
SimulateIOErrorBenign(0);
@@ -23560,32 +26180,41 @@ static int _posixUnlock(sqlite3_file *id, int locktype, int handleNFSUnlock){
** the file has changed and hence might not know to flush their
** cache. The use of a stale cache can lead to database corruption.
*/
+#if 0
assert( pFile->inNormalWrite==0
|| pFile->dbUpdate==0
|| pFile->transCntrChng==1 );
+#endif
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
+ ** 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( locktype==SHARED_LOCK ){
- if( handleNFSUnlock ){
- off_t divSize = SHARED_SIZE - 1;
+ 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( fcntl(h, F_SETLK, &lock)==(-1) ){
+ if( unixFileLock(pFile, &lock)==(-1) ){
tErrno = errno;
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
+ rc = SQLITE_IOERR_UNLOCK;
if( IS_LOCK_ERROR(rc) ){
pFile->lastErrno = tErrno;
}
@@ -23595,7 +26224,7 @@ static int _posixUnlock(sqlite3_file *id, int locktype, int handleNFSUnlock){
lock.l_whence = SEEK_SET;
lock.l_start = SHARED_FIRST;
lock.l_len = divSize;
- if( fcntl(h, F_SETLK, &lock)==(-1) ){
+ if( unixFileLock(pFile, &lock)==(-1) ){
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
if( IS_LOCK_ERROR(rc) ){
@@ -23607,25 +26236,30 @@ static int _posixUnlock(sqlite3_file *id, int locktype, int handleNFSUnlock){
lock.l_whence = SEEK_SET;
lock.l_start = SHARED_FIRST+divSize;
lock.l_len = SHARED_SIZE-divSize;
- if( fcntl(h, F_SETLK, &lock)==(-1) ){
+ if( unixFileLock(pFile, &lock)==(-1) ){
tErrno = errno;
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
+ rc = SQLITE_IOERR_UNLOCK;
if( IS_LOCK_ERROR(rc) ){
pFile->lastErrno = tErrno;
}
goto end_unlock;
}
- }else{
+ }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( fcntl(h, F_SETLK, &lock)==(-1) ){
- tErrno = errno;
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
- if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
- }
+ 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;
}
}
@@ -23634,42 +26268,34 @@ static int _posixUnlock(sqlite3_file *id, int locktype, int handleNFSUnlock){
lock.l_whence = SEEK_SET;
lock.l_start = PENDING_BYTE;
lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE );
- if( fcntl(h, F_SETLK, &lock)!=(-1) ){
- pLock->locktype = SHARED_LOCK;
+ if( unixFileLock(pFile, &lock)==0 ){
+ pInode->eFileLock = SHARED_LOCK;
}else{
- tErrno = errno;
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
- if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
- }
+ rc = SQLITE_IOERR_UNLOCK;
+ pFile->lastErrno = errno;
goto end_unlock;
}
}
- if( locktype==NO_LOCK ){
- struct unixOpenCnt *pOpen;
-
+ 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.
*/
- pLock->cnt--;
- if( pLock->cnt==0 ){
+ pInode->nShared--;
+ if( pInode->nShared==0 ){
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = lock.l_len = 0L;
SimulateIOErrorBenign(1);
SimulateIOError( h=(-1) )
SimulateIOErrorBenign(0);
- if( fcntl(h, F_SETLK, &lock)!=(-1) ){
- pLock->locktype = NO_LOCK;
+ if( unixFileLock(pFile, &lock)==0 ){
+ pInode->eFileLock = NO_LOCK;
}else{
- tErrno = errno;
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
- if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
- }
- pLock->locktype = NO_LOCK;
- pFile->locktype = NO_LOCK;
+ rc = SQLITE_IOERR_UNLOCK;
+ pFile->lastErrno = errno;
+ pInode->eFileLock = NO_LOCK;
+ pFile->eFileLock = NO_LOCK;
}
}
@@ -23677,36 +26303,32 @@ static int _posixUnlock(sqlite3_file *id, int locktype, int handleNFSUnlock){
** count reaches zero, close any other file descriptors whose close
** was deferred because of outstanding locks.
*/
- pOpen = pFile->pOpen;
- pOpen->nLock--;
- assert( pOpen->nLock>=0 );
- if( pOpen->nLock==0 ){
- int rc2 = closePendingFds(pFile);
- if( rc==SQLITE_OK ){
- rc = rc2;
- }
+ pInode->nLock--;
+ assert( pInode->nLock>=0 );
+ if( pInode->nLock==0 ){
+ closePendingFds(pFile);
}
}
-
+
end_unlock:
unixLeaveMutex();
- if( rc==SQLITE_OK ) pFile->locktype = locktype;
+ if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
return rc;
}
/*
-** Lower the locking level on file descriptor pFile to locktype. locktype
+** 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 unixUnlock(sqlite3_file *id, int locktype){
- return _posixUnlock(id, locktype, 0);
+static int unixUnlock(sqlite3_file *id, int eFileLock){
+ return posixUnlock(id, eFileLock, 0);
}
/*
-** This function performs the parts of the "close file" operation
+** 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.
@@ -23717,37 +26339,23 @@ static int unixUnlock(sqlite3_file *id, int locktype){
*/
static int closeUnixFile(sqlite3_file *id){
unixFile *pFile = (unixFile*)id;
- if( pFile ){
- if( pFile->dirfd>=0 ){
- int err = close(pFile->dirfd);
- if( err ){
- pFile->lastErrno = errno;
- return SQLITE_IOERR_DIR_CLOSE;
- }else{
- pFile->dirfd=-1;
- }
- }
- if( pFile->h>=0 ){
- int err = close(pFile->h);
- if( err ){
- pFile->lastErrno = errno;
- return SQLITE_IOERR_CLOSE;
- }
- }
-#if OS_VXWORKS
- if( pFile->pId ){
- if( pFile->isDelete ){
- unlink(pFile->pId->zCanonicalName);
- }
- vxworksReleaseFileId(pFile->pId);
- pFile->pId = 0;
- }
-#endif
- OSTRACE2("CLOSE %-3d\n", pFile->h);
- OpenCounter(-1);
- sqlite3_free(pFile->pUnused);
- memset(pFile, 0, sizeof(unixFile));
+ if( pFile->h>=0 ){
+ robust_close(pFile, pFile->h, __LINE__);
+ pFile->h = -1;
}
+#if OS_VXWORKS
+ if( pFile->pId ){
+ if( pFile->isDelete ){
+ 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;
}
@@ -23756,23 +26364,25 @@ static int closeUnixFile(sqlite3_file *id){
*/
static int unixClose(sqlite3_file *id){
int rc = SQLITE_OK;
- if( id ){
- unixFile *pFile = (unixFile *)id;
- unixUnlock(id, NO_LOCK);
- unixEnterMutex();
- if( pFile->pOpen && pFile->pOpen->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 pOpen->pUnused list. It will be automatically closed
- ** when the last lock is cleared.
- */
- setPendingFd(pFile);
- }
- releaseLockInfo(pFile->pLock);
- releaseOpenCnt(pFile->pOpen);
- rc = closeUnixFile(id);
- unixLeaveMutex();
+ unixFile *pFile = (unixFile *)id;
+ 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;
}
@@ -23864,26 +26474,26 @@ static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) {
unixFile *pFile = (unixFile*)id;
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
-
+
assert( pFile );
/* Check if a thread in this process holds such a lock */
- if( pFile->locktype>SHARED_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 = access(zLockFile, 0)==0;
+ reserved = osAccess(zLockFile, 0)==0;
}
- OSTRACE4("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved);
+ OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved));
*pResOut = reserved;
return rc;
}
/*
-** Lock the file with the lock specified by parameter locktype - one
+** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
@@ -23909,7 +26519,7 @@ static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) {
** With dotfile locking, we really only support state (4): EXCLUSIVE.
** But we track the other locking levels internally.
*/
-static int dotlockLock(sqlite3_file *id, int locktype) {
+static int dotlockLock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
int fd;
char *zLockFile = (char *)pFile->lockingContext;
@@ -23919,17 +26529,19 @@ static int dotlockLock(sqlite3_file *id, int locktype) {
/* 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->locktype > NO_LOCK ){
- pFile->locktype = locktype;
-#if !OS_VXWORKS
+ 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;
}
-
+
/* grab an exclusive lock */
- fd = open(zLockFile,O_RDONLY|O_CREAT|O_EXCL,0600);
+ fd = robust_open(zLockFile,O_RDONLY|O_CREAT|O_EXCL,0600);
if( fd<0 ){
/* failed to open/create the file, someone else may have stolen the lock */
int tErrno = errno;
@@ -23942,19 +26554,16 @@ static int dotlockLock(sqlite3_file *id, int locktype) {
}
}
return rc;
- }
- if( close(fd) ){
- pFile->lastErrno = errno;
- rc = SQLITE_IOERR_CLOSE;
- }
-
+ }
+ robust_close(pFile, fd, __LINE__);
+
/* got it, set the type and return ok */
- pFile->locktype = locktype;
+ pFile->eFileLock = eFileLock;
return rc;
}
/*
-** Lower the locking level on file descriptor pFile to locktype. locktype
+** 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
@@ -23962,42 +26571,42 @@ static int dotlockLock(sqlite3_file *id, int locktype) {
**
** When the locking level reaches NO_LOCK, delete the lock file.
*/
-static int dotlockUnlock(sqlite3_file *id, int locktype) {
+static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
char *zLockFile = (char *)pFile->lockingContext;
assert( pFile );
- OSTRACE5("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, locktype,
- pFile->locktype, getpid());
- assert( locktype<=SHARED_LOCK );
-
+ 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->locktype==locktype ){
+ if( pFile->eFileLock==eFileLock ){
return SQLITE_OK;
}
/* To downgrade to shared, simply update our internal notion of the
** lock state. No need to mess with the file on disk.
*/
- if( locktype==SHARED_LOCK ){
- pFile->locktype = SHARED_LOCK;
+ if( eFileLock==SHARED_LOCK ){
+ pFile->eFileLock = SHARED_LOCK;
return SQLITE_OK;
}
-
+
/* To fully unlock the database, delete the lock file */
- assert( locktype==NO_LOCK );
- if( unlink(zLockFile) ){
+ assert( eFileLock==NO_LOCK );
+ if( osUnlink(zLockFile) ){
int rc = 0;
int tErrno = errno;
if( ENOENT != tErrno ){
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
+ rc = SQLITE_IOERR_UNLOCK;
}
if( IS_LOCK_ERROR(rc) ){
pFile->lastErrno = tErrno;
}
- return rc;
+ return rc;
}
- pFile->locktype = NO_LOCK;
+ pFile->eFileLock = NO_LOCK;
return SQLITE_OK;
}
@@ -24034,6 +26643,20 @@ static int dotlockClose(sqlite3_file *id) {
*/
#if SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS
+/*
+** 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
+
+
/*
** 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
@@ -24044,27 +26667,27 @@ 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->locktype>SHARED_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 = flock(pFile->h, LOCK_EX | LOCK_NB);
+ int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB);
if( !lrc ){
/* got the lock, unlock it */
- lrc = flock(pFile->h, LOCK_UN);
+ lrc = robust_flock(pFile->h, LOCK_UN);
if ( lrc ) {
int tErrno = errno;
/* unlock failed with an error */
- lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
+ lrc = SQLITE_IOERR_UNLOCK;
if( IS_LOCK_ERROR(lrc) ){
pFile->lastErrno = tErrno;
rc = lrc;
@@ -24074,14 +26697,14 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
int tErrno = errno;
reserved = 1;
/* someone else might have it reserved */
- lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
+ lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( IS_LOCK_ERROR(lrc) ){
pFile->lastErrno = tErrno;
rc = lrc;
}
}
}
- OSTRACE4("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved);
+ 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 ){
@@ -24094,7 +26717,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
}
/*
-** Lock the file with the lock specified by parameter locktype - one
+** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
@@ -24122,22 +26745,22 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-static int flockLock(sqlite3_file *id, int locktype) {
+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.
+ /* if we already have a lock, it is exclusive.
** Just adjust level and punt on outta here. */
- if (pFile->locktype > NO_LOCK) {
- pFile->locktype = locktype;
+ if (pFile->eFileLock > NO_LOCK) {
+ pFile->eFileLock = eFileLock;
return SQLITE_OK;
}
-
+
/* grab an exclusive lock */
-
- if (flock(pFile->h, LOCK_EX | LOCK_NB)) {
+
+ if (robust_flock(pFile->h, LOCK_EX | LOCK_NB)) {
int tErrno = errno;
/* didn't get, must be busy */
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
@@ -24146,10 +26769,10 @@ static int flockLock(sqlite3_file *id, int locktype) {
}
} else {
/* got it, set the type and return ok */
- pFile->locktype = locktype;
+ pFile->eFileLock = eFileLock;
}
- OSTRACE4("LOCK %d %s %s (flock)\n", pFile->h, locktypeName(locktype),
- rc==SQLITE_OK ? "ok" : "failed");
+ 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;
@@ -24160,48 +26783,39 @@ static int flockLock(sqlite3_file *id, int locktype) {
/*
-** Lower the locking level on file descriptor pFile to locktype. locktype
+** 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 flockUnlock(sqlite3_file *id, int locktype) {
+static int flockUnlock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
-
+
assert( pFile );
- OSTRACE5("UNLOCK %d %d was %d pid=%d (flock)\n", pFile->h, locktype,
- pFile->locktype, getpid());
- assert( locktype<=SHARED_LOCK );
-
+ 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->locktype==locktype ){
+ if( pFile->eFileLock==eFileLock ){
return SQLITE_OK;
}
-
+
/* shared can just be set because we always have an exclusive */
- if (locktype==SHARED_LOCK) {
- pFile->locktype = locktype;
+ if (eFileLock==SHARED_LOCK) {
+ pFile->eFileLock = eFileLock;
return SQLITE_OK;
}
-
+
/* no, really, unlock. */
- int rc = flock(pFile->h, LOCK_UN);
- if (rc) {
- int r, tErrno = errno;
- r = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
- if( IS_LOCK_ERROR(r) ){
- pFile->lastErrno = tErrno;
- }
+ if( robust_flock(pFile->h, LOCK_UN) ){
#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
- if( (r & SQLITE_IOERR) == SQLITE_IOERR ){
- r = SQLITE_BUSY;
- }
+ return SQLITE_OK;
#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
-
- return r;
- } else {
- pFile->locktype = NO_LOCK;
+ return SQLITE_IOERR_UNLOCK;
+ }else{
+ pFile->eFileLock = NO_LOCK;
return SQLITE_OK;
}
}
@@ -24245,17 +26859,17 @@ static int semCheckReservedLock(sqlite3_file *id, int *pResOut) {
unixFile *pFile = (unixFile*)id;
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
-
+
assert( pFile );
/* Check if a thread in this process holds such a lock */
- if( pFile->locktype>SHARED_LOCK ){
+ if( pFile->eFileLock>SHARED_LOCK ){
reserved = 1;
}
-
+
/* Otherwise see if some other process holds it. */
if( !reserved ){
- sem_t *pSem = pFile->pOpen->pSem;
+ sem_t *pSem = pFile->pInode->pSem;
struct stat statBuf;
if( sem_trywait(pSem)==-1 ){
@@ -24265,21 +26879,21 @@ static int semCheckReservedLock(sqlite3_file *id, int *pResOut) {
pFile->lastErrno = tErrno;
} else {
/* someone else has the lock when we are in NO_LOCK */
- reserved = (pFile->locktype < SHARED_LOCK);
+ reserved = (pFile->eFileLock < SHARED_LOCK);
}
}else{
/* we could have it if we want it */
sem_post(pSem);
}
}
- OSTRACE4("TEST WR-LOCK %d %d %d (sem)\n", pFile->h, rc, reserved);
+ OSTRACE(("TEST WR-LOCK %d %d %d (sem)\n", pFile->h, rc, reserved));
*pResOut = reserved;
return rc;
}
/*
-** Lock the file with the lock specified by parameter locktype - one
+** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
@@ -24307,20 +26921,20 @@ static int semCheckReservedLock(sqlite3_file *id, int *pResOut) {
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-static int semLock(sqlite3_file *id, int locktype) {
+static int semLock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
int fd;
- sem_t *pSem = pFile->pOpen->pSem;
+ sem_t *pSem = pFile->pInode->pSem;
int rc = SQLITE_OK;
- /* if we already have a lock, it is exclusive.
+ /* if we already have a lock, it is exclusive.
** Just adjust level and punt on outta here. */
- if (pFile->locktype > NO_LOCK) {
- pFile->locktype = locktype;
+ if (pFile->eFileLock > NO_LOCK) {
+ pFile->eFileLock = eFileLock;
rc = SQLITE_OK;
goto sem_end_lock;
}
-
+
/* lock semaphore now but bail out when already locked. */
if( sem_trywait(pSem)==-1 ){
rc = SQLITE_BUSY;
@@ -24328,40 +26942,40 @@ static int semLock(sqlite3_file *id, int locktype) {
}
/* got it, set the type and return ok */
- pFile->locktype = locktype;
+ pFile->eFileLock = eFileLock;
sem_end_lock:
return rc;
}
/*
-** Lower the locking level on file descriptor pFile to locktype. locktype
+** 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 semUnlock(sqlite3_file *id, int locktype) {
+static int semUnlock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
- sem_t *pSem = pFile->pOpen->pSem;
+ sem_t *pSem = pFile->pInode->pSem;
assert( pFile );
assert( pSem );
- OSTRACE5("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, locktype,
- pFile->locktype, getpid());
- assert( locktype<=SHARED_LOCK );
-
+ 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->locktype==locktype ){
+ if( pFile->eFileLock==eFileLock ){
return SQLITE_OK;
}
-
+
/* shared can just be set because we always have an exclusive */
- if (locktype==SHARED_LOCK) {
- pFile->locktype = locktype;
+ if (eFileLock==SHARED_LOCK) {
+ pFile->eFileLock = eFileLock;
return SQLITE_OK;
}
-
+
/* no, really unlock. */
if ( sem_post(pSem)==-1 ) {
int rc, tErrno = errno;
@@ -24369,9 +26983,9 @@ static int semUnlock(sqlite3_file *id, int locktype) {
if( IS_LOCK_ERROR(rc) ){
pFile->lastErrno = tErrno;
}
- return rc;
+ return rc;
}
- pFile->locktype = NO_LOCK;
+ pFile->eFileLock = NO_LOCK;
return SQLITE_OK;
}
@@ -24384,8 +26998,7 @@ static int semClose(sqlite3_file *id) {
semUnlock(id, NO_LOCK);
assert( pFile );
unixEnterMutex();
- releaseLockInfo(pFile->pLock);
- releaseOpenCnt(pFile->pOpen);
+ releaseInodeInfo(pFile);
unixLeaveMutex();
closeUnixFile(id);
}
@@ -24435,7 +27048,7 @@ struct ByteRangeLockPB2
/*
** 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(
@@ -24447,22 +27060,22 @@ static int afpSetLock(
){
struct ByteRangeLockPB2 pb;
int err;
-
+
pb.unLockFlag = setLockFlag ? 0 : 1;
pb.startEndFlag = 0;
pb.offset = offset;
- pb.length = length;
+ pb.length = length;
pb.fd = pFile->h;
-
- OSTRACE6("AFPSETLOCK [%s] for %d%s in range %llx:%llx\n",
+
+ OSTRACE(("AFPSETLOCK [%s] for %d%s in range %llx:%llx\n",
(setLockFlag?"ON":"OFF"), pFile->h, (pb.fd==-1?"[testval-1]":""),
- offset, length);
+ offset, length));
err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0);
if ( err==-1 ) {
int rc;
int tErrno = errno;
- OSTRACE4("AFPSETLOCK failed to fsctl() '%s' %d %s\n",
- path, tErrno, strerror(tErrno));
+ OSTRACE(("AFPSETLOCK failed to fsctl() '%s' %d %s\n",
+ path, tErrno, strerror(tErrno)));
#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
rc = SQLITE_BUSY;
#else
@@ -24488,27 +27101,28 @@ 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 );
- afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
+ context = (afpLockingContext *) pFile->lockingContext;
if( context->reserved ){
*pResOut = 1;
return SQLITE_OK;
}
- unixEnterMutex(); /* Because pFile->pLock is shared across threads */
-
+ unixEnterMutex(); /* Because pFile->pInode is shared across threads */
+
/* Check if a thread in this process holds such a lock */
- if( pFile->pLock->locktype>SHARED_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);
+ 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 */
@@ -24521,16 +27135,16 @@ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){
rc=lrc;
}
}
-
+
unixLeaveMutex();
- OSTRACE4("TEST WR-LOCK %d %d %d (afp)\n", pFile->h, rc, reserved);
-
+ OSTRACE(("TEST WR-LOCK %d %d %d (afp)\n", pFile->h, rc, reserved));
+
*pResOut = reserved;
return rc;
}
/*
-** Lock the file with the lock specified by parameter locktype - one
+** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
@@ -24553,24 +27167,24 @@ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-static int afpLock(sqlite3_file *id, int locktype){
+static int afpLock(sqlite3_file *id, int eFileLock){
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
- struct unixLockInfo *pLock = pFile->pLock;
+ unixInodeInfo *pInode = pFile->pInode;
afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
-
+
assert( pFile );
- OSTRACE7("LOCK %d %s was %s(%s,%d) pid=%d (afp)\n", pFile->h,
- locktypeName(locktype), locktypeName(pFile->locktype),
- locktypeName(pLock->locktype), pLock->cnt , getpid());
+ 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->locktype>=locktype ){
- OSTRACE3("LOCK %d %s ok (already held) (afp)\n", pFile->h,
- locktypeName(locktype));
+ if( pFile->eFileLock>=eFileLock ){
+ OSTRACE(("LOCK %d %s ok (already held) (afp)\n", pFile->h,
+ azFileLock(eFileLock)));
return SQLITE_OK;
}
@@ -24579,54 +27193,46 @@ static int afpLock(sqlite3_file *id, int locktype){
** (2) SQLite never explicitly requests a pendig lock.
** (3) A shared lock is always held when a reserve lock is requested.
*/
- assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
- assert( locktype!=PENDING_LOCK );
- assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
-
- /* This mutex is needed because pFile->pLock is shared across threads
+ 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();
-
- /* Make sure the current thread owns the pFile.
- */
- rc = transferOwnership(pFile);
- if( rc!=SQLITE_OK ){
- unixLeaveMutex();
- return rc;
- }
- pLock = pFile->pLock;
+ 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->locktype!=pLock->locktype &&
- (pLock->locktype>=PENDING_LOCK || locktype>SHARED_LOCK))
+ 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( locktype==SHARED_LOCK &&
- (pLock->locktype==SHARED_LOCK || pLock->locktype==RESERVED_LOCK) ){
- assert( locktype==SHARED_LOCK );
- assert( pFile->locktype==0 );
- assert( pLock->cnt>0 );
- pFile->locktype = SHARED_LOCK;
- pLock->cnt++;
- pFile->pOpen->nLock++;
+ 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( locktype==SHARED_LOCK
- || (locktype==EXCLUSIVE_LOCK && pFile->locktypeeFileLockdbPath, pFile, PENDING_BYTE, 1, 1);
@@ -24635,30 +27241,30 @@ static int afpLock(sqlite3_file *id, int locktype){
goto afp_end_lock;
}
}
-
+
/* If control gets to this point, then actually go ahead and make
** operating system calls for the specified lock.
*/
- if( locktype==SHARED_LOCK ){
- int lrc1, lrc2, lrc1Errno;
+ if( eFileLock==SHARED_LOCK ){
+ int lrc1, lrc2, lrc1Errno = 0;
long lk, mask;
-
- assert( pLock->cnt==0 );
- assert( pLock->locktype==0 );
-
+
+ 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();
- pLock->sharedByte = (lk & mask)%(SHARED_SIZE - 1);
- lrc1 = afpSetLock(context->dbPath, pFile,
- SHARED_FIRST+pLock->sharedByte, 1, 1);
+ 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;
@@ -24669,11 +27275,11 @@ static int afpLock(sqlite3_file *id, int locktype){
} else if( lrc1 != SQLITE_OK ) {
rc = lrc1;
} else {
- pFile->locktype = SHARED_LOCK;
- pFile->pOpen->nLock++;
- pLock->cnt = 1;
+ pFile->eFileLock = SHARED_LOCK;
+ pInode->nLock++;
+ pInode->nShared = 1;
}
- }else if( locktype==EXCLUSIVE_LOCK && pLock->cnt>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;
@@ -24683,70 +27289,70 @@ static int afpLock(sqlite3_file *id, int locktype){
** already.
*/
int failed = 0;
- assert( 0!=pFile->locktype );
- if (locktype >= RESERVED_LOCK && pFile->locktype < RESERVED_LOCK) {
+ 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 && locktype == EXCLUSIVE_LOCK) {
+ if (!failed && eFileLock == EXCLUSIVE_LOCK) {
/* Acquire an EXCLUSIVE lock */
-
- /* Remove the shared lock before trying the range. we'll need to
+
+ /* 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 +
- pLock->sharedByte, 1, 0)) ){
+ pInode->sharedByte, 1, 0)) ){
int failed2 = SQLITE_OK;
/* now attemmpt to get the exclusive lock range */
- failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST,
+ failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST,
SHARED_SIZE, 1);
- if( failed && (failed2 = afpSetLock(context->dbPath, pFile,
- SHARED_FIRST + pLock->sharedByte, 1, 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 :
+ rc = ((failed & SQLITE_IOERR) == SQLITE_IOERR) ? failed2 :
SQLITE_IOERR_LOCK;
goto afp_end_lock;
- }
+ }
}else{
- rc = failed;
+ rc = failed;
}
}
if( failed ){
rc = failed;
}
}
-
+
if( rc==SQLITE_OK ){
- pFile->locktype = locktype;
- pLock->locktype = locktype;
- }else if( locktype==EXCLUSIVE_LOCK ){
- pFile->locktype = PENDING_LOCK;
- pLock->locktype = PENDING_LOCK;
+ pFile->eFileLock = eFileLock;
+ pInode->eFileLock = eFileLock;
+ }else if( eFileLock==EXCLUSIVE_LOCK ){
+ pFile->eFileLock = PENDING_LOCK;
+ pInode->eFileLock = PENDING_LOCK;
}
-
+
afp_end_lock:
unixLeaveMutex();
- OSTRACE4("LOCK %d %s %s (afp)\n", pFile->h, locktypeName(locktype),
- rc==SQLITE_OK ? "ok" : "failed");
+ OSTRACE(("LOCK %d %s %s (afp)\n", pFile->h, azFileLock(eFileLock),
+ rc==SQLITE_OK ? "ok" : "failed"));
return rc;
}
/*
-** Lower the locking level on file descriptor pFile to locktype. locktype
+** 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 afpUnlock(sqlite3_file *id, int locktype) {
+static int afpUnlock(sqlite3_file *id, int eFileLock) {
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
- struct unixLockInfo *pLock;
+ unixInodeInfo *pInode;
afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
int skipShared = 0;
#ifdef SQLITE_TEST
@@ -24754,25 +27360,23 @@ static int afpUnlock(sqlite3_file *id, int locktype) {
#endif
assert( pFile );
- OSTRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d (afp)\n", pFile->h, locktype,
- pFile->locktype, pFile->pLock->locktype, pFile->pLock->cnt, getpid());
+ 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( locktype<=SHARED_LOCK );
- if( pFile->locktype<=locktype ){
+ assert( eFileLock<=SHARED_LOCK );
+ if( pFile->eFileLock<=eFileLock ){
return SQLITE_OK;
}
- if( CHECK_THREADID(pFile) ){
- return SQLITE_MISUSE_BKPT;
- }
unixEnterMutex();
- pLock = pFile->pLock;
- assert( pLock->cnt!=0 );
- if( pFile->locktype>SHARED_LOCK ){
- assert( pLock->locktype==pFile->locktype );
+ pInode = pFile->pInode;
+ assert( pInode->nShared!=0 );
+ if( pFile->eFileLock>SHARED_LOCK ){
+ assert( pInode->eFileLock==pFile->eFileLock );
SimulateIOErrorBenign(1);
SimulateIOError( h=(-1) )
SimulateIOErrorBenign(0);
-
+
#ifndef NDEBUG
/* When reducing a lock such that other processes can start
** reading the database file again, make sure that the
@@ -24787,39 +27391,39 @@ static int afpUnlock(sqlite3_file *id, int locktype) {
|| pFile->transCntrChng==1 );
pFile->inNormalWrite = 0;
#endif
-
- if( pFile->locktype==EXCLUSIVE_LOCK ){
+
+ if( pFile->eFileLock==EXCLUSIVE_LOCK ){
rc = afpSetLock(context->dbPath, pFile, SHARED_FIRST, SHARED_SIZE, 0);
- if( rc==SQLITE_OK && (locktype==SHARED_LOCK || pLock->cnt>1) ){
+ if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1) ){
/* only re-establish the shared lock if necessary */
- int sharedLockByte = SHARED_FIRST+pLock->sharedByte;
+ int sharedLockByte = SHARED_FIRST+pInode->sharedByte;
rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 1);
} else {
skipShared = 1;
}
}
- if( rc==SQLITE_OK && pFile->locktype>=PENDING_LOCK ){
+ if( rc==SQLITE_OK && pFile->eFileLock>=PENDING_LOCK ){
rc = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0);
- }
- if( rc==SQLITE_OK && pFile->locktype>=RESERVED_LOCK && context->reserved ){
+ }
+ 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 ){
+ context->reserved = 0;
}
}
- if( rc==SQLITE_OK && (locktype==SHARED_LOCK || pLock->cnt>1)){
- pLock->locktype = SHARED_LOCK;
+ if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1)){
+ pInode->eFileLock = SHARED_LOCK;
}
}
- if( rc==SQLITE_OK && locktype==NO_LOCK ){
+ 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+pLock->sharedByte;
- pLock->cnt--;
- if( pLock->cnt==0 ){
+ unsigned long long sharedLockByte = SHARED_FIRST+pInode->sharedByte;
+ pInode->nShared--;
+ if( pInode->nShared==0 ){
SimulateIOErrorBenign(1);
SimulateIOError( h=(-1) )
SimulateIOErrorBenign(0);
@@ -24827,28 +27431,26 @@ static int afpUnlock(sqlite3_file *id, int locktype) {
rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 0);
}
if( !rc ){
- pLock->locktype = NO_LOCK;
- pFile->locktype = NO_LOCK;
+ pInode->eFileLock = NO_LOCK;
+ pFile->eFileLock = NO_LOCK;
}
}
if( rc==SQLITE_OK ){
- struct unixOpenCnt *pOpen = pFile->pOpen;
-
- pOpen->nLock--;
- assert( pOpen->nLock>=0 );
- if( pOpen->nLock==0 ){
- rc = closePendingFds(pFile);
+ pInode->nLock--;
+ assert( pInode->nLock>=0 );
+ if( pInode->nLock==0 ){
+ closePendingFds(pFile);
}
}
}
-
+
unixLeaveMutex();
- if( rc==SQLITE_OK ) pFile->locktype = locktype;
+ if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
return rc;
}
/*
-** Close a file & cleanup AFP specific locking context
+** Close a file & cleanup AFP specific locking context
*/
static int afpClose(sqlite3_file *id) {
int rc = SQLITE_OK;
@@ -24856,16 +27458,15 @@ static int afpClose(sqlite3_file *id) {
unixFile *pFile = (unixFile*)id;
afpUnlock(id, NO_LOCK);
unixEnterMutex();
- if( pFile->pOpen && pFile->pOpen->nLock ){
+ 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 pOpen->aPending. It will be automatically closed when
+ ** descriptor to pInode->aPending. It will be automatically closed when
** the last lock is cleared.
*/
setPendingFd(pFile);
}
- releaseLockInfo(pFile->pLock);
- releaseOpenCnt(pFile->pOpen);
+ releaseInodeInfo(pFile);
sqlite3_free(pFile->lockingContext);
rc = closeUnixFile(id);
unixLeaveMutex();
@@ -24888,21 +27489,21 @@ static int afpClose(sqlite3_file *id) {
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
/*
- ** Lower the locking level on file descriptor pFile to locktype. locktype
+ ** 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 locktype){
- return _posixUnlock(id, locktype, 1);
+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.
+** is available.
**
********************* End of the NFS lock implementation **********************
******************************************************************************/
@@ -24910,7 +27511,7 @@ static int nfsUnlock(sqlite3_file *id, int locktype){
/******************************************************************************
**************** Non-locking sqlite3_file methods *****************************
**
-** The next division contains implementations for all methods of the
+** 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
@@ -24918,7 +27519,7 @@ static int nfsUnlock(sqlite3_file *id, int locktype){
*/
/*
-** Seek to the offset passed as the second argument, then read cnt
+** 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
@@ -24937,10 +27538,10 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
#endif
TIMER_START;
#if defined(USE_PREAD)
- got = pread(id->h, pBuf, cnt, offset);
+ do{ got = osPread(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
SimulateIOError( got = -1 );
#elif defined(USE_PREAD64)
- got = pread64(id->h, pBuf, cnt, offset);
+ do{ got = osPread64(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR);
SimulateIOError( got = -1 );
#else
newOffset = lseek(id->h, offset, SEEK_SET);
@@ -24949,17 +27550,17 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
if( newOffset == -1 ){
((unixFile*)id)->lastErrno = errno;
}else{
- ((unixFile*)id)->lastErrno = 0;
+ ((unixFile*)id)->lastErrno = 0;
}
return -1;
}
- got = read(id->h, pBuf, cnt);
+ do{ got = osRead(id->h, pBuf, cnt); }while( got<0 && errno==EINTR );
#endif
TIMER_END;
if( got<0 ){
((unixFile*)id)->lastErrno = errno;
}
- OSTRACE5("READ %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED);
+ OSTRACE(("READ %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED));
return got;
}
@@ -24969,8 +27570,8 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
** wrong.
*/
static int unixRead(
- sqlite3_file *id,
- void *pBuf,
+ sqlite3_file *id,
+ void *pBuf,
int amt,
sqlite3_int64 offset
){
@@ -24980,10 +27581,12 @@ static int unixRead(
/* 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
+ || offset+amt<=PENDING_BYTE
);
+#endif
got = seekAndRead(pFile, offset, pBuf, amt);
if( got==amt ){
@@ -25013,27 +27616,30 @@ static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
#endif
TIMER_START;
#if defined(USE_PREAD)
- got = pwrite(id->h, pBuf, cnt, offset);
+ do{ got = osPwrite(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
#elif defined(USE_PREAD64)
- got = pwrite64(id->h, pBuf, cnt, offset);
+ do{ got = osPwrite64(id->h, pBuf, cnt, offset);}while( got<0 && errno==EINTR);
#else
- newOffset = lseek(id->h, offset, SEEK_SET);
- if( newOffset!=offset ){
- if( newOffset == -1 ){
- ((unixFile*)id)->lastErrno = errno;
- }else{
- ((unixFile*)id)->lastErrno = 0;
+ 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;
+ }
+ return -1;
}
- return -1;
- }
- got = write(id->h, pBuf, cnt);
+ got = osWrite(id->h, pBuf, cnt);
+ }while( got<0 && errno==EINTR );
#endif
TIMER_END;
if( got<0 ){
((unixFile*)id)->lastErrno = errno;
}
- OSTRACE5("WRITE %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED);
+ OSTRACE(("WRITE %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED));
return got;
}
@@ -25043,10 +27649,10 @@ static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
** or some other error code on failure.
*/
static int unixWrite(
- sqlite3_file *id,
- const void *pBuf,
+ sqlite3_file *id,
+ const void *pBuf,
int amt,
- sqlite3_int64 offset
+ sqlite3_int64 offset
){
unixFile *pFile = (unixFile*)id;
int wrote = 0;
@@ -25055,10 +27661,12 @@ static int unixWrite(
/* 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
+ || offset+amt<=PENDING_BYTE
);
+#endif
#ifndef NDEBUG
/* If we are doing a normal write to a database file (as opposed to
@@ -25089,8 +27697,9 @@ static int unixWrite(
}
SimulateIOError(( wrote=(-1), amt=1 ));
SimulateDiskfullError(( wrote=0, amt=1 ));
+
if( amt>0 ){
- if( wrote<0 ){
+ if( wrote<0 && pFile->lastErrno!=ENOSPC ){
/* lastErrno set by seekAndWrite */
return SQLITE_IOERR_WRITE;
}else{
@@ -25098,6 +27707,7 @@ static int unixWrite(
return SQLITE_FULL;
}
}
+
return SQLITE_OK;
}
@@ -25112,11 +27722,11 @@ SQLITE_API int sqlite3_fullsync_count = 0;
/*
** We do not trust systems to provide a working fdatasync(). Some do.
-** Others do no. To be safe, we will stick with the (slower) fsync().
-** If you know that your system does support fdatasync() correctly,
+** 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) && !defined(__linux__)
+#if !defined(fdatasync)
# define fdatasync fsync
#endif
@@ -25145,8 +27755,8 @@ SQLITE_API int sqlite3_fullsync_count = 0;
**
** 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,
+** 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
@@ -25160,7 +27770,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
int rc;
/* The following "ifdef/elif/else/" block has the same structure as
- ** the one below. It is replicated here solely to avoid cluttering
+ ** the one below. It is replicated here solely to avoid cluttering
** up the real code with the UNUSED_PARAMETER() macros.
*/
#ifdef SQLITE_NO_SYNC
@@ -25174,7 +27784,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
UNUSED_PARAMETER(dataOnly);
#endif
- /* Record the number of times that we do a normal fsync() and
+ /* 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.
*/
@@ -25190,16 +27800,16 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
rc = SQLITE_OK;
#elif HAVE_FULLFSYNC
if( fullSync ){
- rc = fcntl(fd, F_FULLFSYNC, 0);
+ 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
+ ** 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
+ ** 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);
@@ -25209,7 +27819,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
** so currently we default to the macro that redefines fdatasync to fsync
*/
rc = fsync(fd);
-#else
+#else
rc = fdatasync(fd);
#if OS_VXWORKS
if( rc==-1 && errno==ENOTSUP ){
@@ -25224,6 +27834,50 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
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.
+**
+** 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 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 ){
+#ifdef FD_CLOEXEC
+ osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
+#endif
+ OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
+ }
+ }
+ *pFd = fd;
+ return (fd>=0?SQLITE_OK:unixLogError(SQLITE_CANTOPEN_BKPT, "open", zDirname));
+}
+
/*
** Make sure all writes to a particular file are committed to disk.
**
@@ -25257,40 +27911,30 @@ static int unixSync(sqlite3_file *id, int flags){
SimulateDiskfullError( return SQLITE_FULL );
assert( pFile );
- OSTRACE2("SYNC %-3d\n", pFile->h);
+ OSTRACE(("SYNC %-3d\n", pFile->h));
rc = full_fsync(pFile->h, isFullsync, isDataOnly);
SimulateIOError( rc=1 );
if( rc ){
pFile->lastErrno = errno;
- return SQLITE_IOERR_FSYNC;
+ return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath);
}
- if( pFile->dirfd>=0 ){
- int err;
- OSTRACE4("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd,
- HAVE_FULLFSYNC, isFullsync);
-#ifndef SQLITE_DISABLE_DIRSYNC
- /* The directory sync is only attempted if full_fsync is
- ** turned off or unavailable. If a full_fsync occurred above,
- ** then the directory sync is superfluous.
- */
- if( (!HAVE_FULLFSYNC || !isFullsync) && full_fsync(pFile->dirfd,0,0) ){
- /*
- ** We have received multiple reports of fsync() returning
- ** errors when applied to directories on certain file systems.
- ** A failed directory sync is not a big deal. So it seems
- ** better to ignore the error. Ticket #1657
- */
- /* pFile->lastErrno = errno; */
- /* return SQLITE_IOERR; */
- }
-#endif
- err = close(pFile->dirfd); /* Only need to sync once, so close the */
- if( err==0 ){ /* directory when we are done */
- pFile->dirfd = -1;
- }else{
- pFile->lastErrno = errno;
- rc = SQLITE_IOERR_DIR_CLOSE;
+
+ /* Also fsync the directory containing the file if the DIRSYNC flag
+ ** is set. This is a one-time occurrance. 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;
}
+ pFile->ctrlFlags &= ~UNIXFILE_DIRSYNC;
}
return rc;
}
@@ -25299,13 +27943,24 @@ static int unixSync(sqlite3_file *id, int flags){
** Truncate an open file to a specified size
*/
static int unixTruncate(sqlite3_file *id, i64 nByte){
+ unixFile *pFile = (unixFile *)id;
int rc;
- assert( id );
+ assert( pFile );
SimulateIOError( return SQLITE_IOERR_TRUNCATE );
- rc = ftruncate(((unixFile*)id)->h, (off_t)nByte);
+
+ /* 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 ){
+ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
+ }
+
+ rc = robust_ftruncate(pFile->h, (off_t)nByte);
if( rc ){
- ((unixFile*)id)->lastErrno = errno;
- return SQLITE_IOERR_TRUNCATE;
+ pFile->lastErrno = errno;
+ return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
}else{
#ifndef NDEBUG
/* If we are doing a normal write to a database file (as opposed to
@@ -25315,8 +27970,8 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
** when restoring a database using the backup API from a zero-length
** source.
*/
- if( ((unixFile*)id)->inNormalWrite && nByte==0 ){
- ((unixFile*)id)->transCntrChng = 1;
+ if( pFile->inNormalWrite && nByte==0 ){
+ pFile->transCntrChng = 1;
}
#endif
@@ -25331,7 +27986,7 @@ static int unixFileSize(sqlite3_file *id, i64 *pSize){
int rc;
struct stat buf;
assert( id );
- rc = fstat(((unixFile*)id)->h, &buf);
+ rc = osFstat(((unixFile*)id)->h, &buf);
SimulateIOError( rc=1 );
if( rc!=0 ){
((unixFile*)id)->lastErrno = errno;
@@ -25339,7 +27994,7 @@ static int unixFileSize(sqlite3_file *id, i64 *pSize){
}
*pSize = buf.st_size;
- /* When opening a zero-size database, the findLockInfo() procedure
+ /* 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
@@ -25359,18 +28014,92 @@ static int unixFileSize(sqlite3_file *id, i64 *pSize){
static int proxyFileControl(sqlite3_file*,int,void*);
#endif
+/*
+** 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;
+
+ nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
+ if( nSize>(i64)buf.st_size ){
+
+#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( iWritelocktype;
+ *(int*)pArg = pFile->eFileLock;
return SQLITE_OK;
}
case SQLITE_LAST_ERRNO: {
- *(int*)pArg = ((unixFile*)id)->lastErrno;
+ *(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: {
+ int bPersist = *(int*)pArg;
+ if( bPersist<0 ){
+ *(int*)pArg = (pFile->ctrlFlags & UNIXFILE_PERSIST_WAL)!=0;
+ }else if( bPersist==0 ){
+ pFile->ctrlFlags &= ~UNIXFILE_PERSIST_WAL;
+ }else{
+ pFile->ctrlFlags |= UNIXFILE_PERSIST_WAL;
+ }
return SQLITE_OK;
}
#ifndef NDEBUG
@@ -25390,8 +28119,11 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
return proxyFileControl(id,op,pArg);
}
#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
+ case SQLITE_FCNTL_SYNC_OMITTED: {
+ return SQLITE_OK; /* A no-op */
+ }
}
- return SQLITE_ERROR;
+ return SQLITE_NOTFOUND;
}
/*
@@ -25417,6 +28149,656 @@ static int unixDeviceCharacteristics(sqlite3_file *NotUsed){
return 0;
}
+#ifndef SQLITE_OMIT_WAL
+
+
+/*
+** 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
+**
+** 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.
+*/
+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.
+**
+** 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 */
+
+/*
+** Apply posix advisory locks for all bytes from ofst through ofst+n-1.
+**
+** Locks block if the mask is exactly UNIX_SHM_C and are non-blocking
+** otherwise.
+*/
+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 && nh>=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<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;
+}
+
+
+/*
+** 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; inRegion; i++){
+ if( p->h>=0 ){
+ munmap(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);
+ }
+}
+
+/*
+** 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 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 */
+
+ /* 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 */
+
+ /* 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. The actual permissions the file is created
+ ** with are subject to the current umask setting.
+ */
+ 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) + 30;
+#else
+ nShmFilename = 5 + (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));
+ 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 ){
+ pShmNode->h = robust_open(zShmFilename, O_RDWR|O_CREAT,
+ (sStat.st_mode & 0777));
+ if( pShmNode->h<0 ){
+ const char *zRO;
+ zRO = sqlite3_uri_parameter(pDbFd->zPath, "readonly_shm");
+ if( zRO && sqlite3GetBoolean(zRO) ){
+ pShmNode->h = robust_open(zShmFilename, O_RDONLY,
+ (sStat.st_mode & 0777));
+ pShmNode->isReadonly = 1;
+ }
+ if( pShmNode->h<0 ){
+ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
+ goto shm_open_err;
+ }
+ }
+
+ /* 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;
+ }
+ }
+
+ /* 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;
+}
+
+/*
+** 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 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 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 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;
+ }
+
+ 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_sizeh, nByte) ){
+ rc = unixLogError(SQLITE_IOERR_SHMSIZE, "ftruncate",
+ pShmNode->zFilename);
+ 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 = mmap(0, szRegion,
+ pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
+ MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion
+ );
+ 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++;
+ }
+ }
+
+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;
+}
+
+/*
+** Change the lock state for a shared-memory segment.
+**
+** 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 */
+
+ 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<1 || mask==(1<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;
+ }
+
+ /* 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;
+ }
+ }
+
+ /* 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 = unixShmSystemLock(pShmNode, F_WRLCK, ofst+UNIX_SHM_BASE, n);
+ if( rc==SQLITE_OK ){
+ assert( (p->sharedMask & mask)==0 );
+ p->exclMask |= mask;
+ }
+ }
+ }
+ 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;
+}
+
+/*
+** 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();
+}
+
+/*
+** 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 */
+
+ 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;
+
+ /* 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
+# define unixShmMap 0
+# define unixShmLock 0
+# define unixShmBarrier 0
+# define unixShmUnmap 0
+#endif /* #ifndef SQLITE_OMIT_WAL */
+
/*
** Here ends the implementation of all sqlite3_file methods.
**
@@ -25457,9 +28839,9 @@ static int unixDeviceCharacteristics(sqlite3_file *NotUsed){
** * An I/O method finder function called FINDER that returns a pointer
** to the METHOD object in the previous bullet.
*/
-#define IOMETHODS(FINDER, METHOD, CLOSE, LOCK, UNLOCK, CKLOCK) \
+#define IOMETHODS(FINDER, METHOD, VERSION, CLOSE, LOCK, UNLOCK, CKLOCK) \
static const sqlite3_io_methods METHOD = { \
- 1, /* iVersion */ \
+ VERSION, /* iVersion */ \
CLOSE, /* xClose */ \
unixRead, /* xRead */ \
unixWrite, /* xWrite */ \
@@ -25471,7 +28853,11 @@ static const sqlite3_io_methods METHOD = { \
CKLOCK, /* xCheckReservedLock */ \
unixFileControl, /* xFileControl */ \
unixSectorSize, /* xSectorSize */ \
- unixDeviceCharacteristics /* xDeviceCapabilities */ \
+ unixDeviceCharacteristics, /* xDeviceCapabilities */ \
+ unixShmMap, /* xShmMap */ \
+ unixShmLock, /* xShmLock */ \
+ unixShmBarrier, /* xShmBarrier */ \
+ unixShmUnmap /* xShmUnmap */ \
}; \
static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \
UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \
@@ -25488,6 +28874,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 */
unixClose, /* xClose method */
unixLock, /* xLock method */
unixUnlock, /* xUnlock method */
@@ -25496,6 +28883,7 @@ IOMETHODS(
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 */
@@ -25504,6 +28892,7 @@ IOMETHODS(
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 */
@@ -25514,6 +28903,7 @@ IOMETHODS(
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 */
@@ -25525,6 +28915,7 @@ IOMETHODS(
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 */
@@ -25536,6 +28927,7 @@ IOMETHODS(
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 */
@@ -25560,6 +28952,7 @@ 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 */
@@ -25572,6 +28965,7 @@ IOMETHODS(
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 */
@@ -25580,8 +28974,8 @@ IOMETHODS(
#endif
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
-/*
-** This "finder" function attempts to determine the best locking strategy
+/*
+** 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.
**
@@ -25623,14 +29017,14 @@ static const sqlite3_io_methods *autolockIoFinderImpl(
}
/* 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.
+ ** 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( fcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
+ if( osFcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
if( strcmp(fsInfo.f_fstypename, "nfs")==0 ){
return &nfsIoMethods;
} else {
@@ -25640,14 +29034,14 @@ static const sqlite3_io_methods *autolockIoFinderImpl(
return &dotlockIoMethods;
}
}
-static const sqlite3_io_methods
+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
+/*
+** 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.
**
@@ -25672,13 +29066,13 @@ static const sqlite3_io_methods *autolockIoFinderImpl(
lockInfo.l_start = 0;
lockInfo.l_whence = SEEK_SET;
lockInfo.l_type = F_RDLCK;
- if( fcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
+ if( osFcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
return &posixIoMethods;
}else{
return &semIoMethods;
}
}
-static const sqlite3_io_methods
+static const sqlite3_io_methods
*(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl;
#endif /* OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE */
@@ -25702,29 +29096,49 @@ typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*);
static int fillInUnixFile(
sqlite3_vfs *pVfs, /* Pointer to vfs object */
int h, /* Open file descriptor of file being opened */
- int dirfd, /* Directory file descriptor */
+ int syncDir, /* True to sync directory on first sync */
sqlite3_file *pId, /* Write to the unixFile structure here */
const char *zFilename, /* Name of the file being opened */
int noLock, /* Omit locking if true */
- int isDelete /* Delete on close if true */
+ int isDelete, /* Delete on close if true */
+ int isReadOnly /* True if the file is opened read-only */
){
const sqlite3_io_methods *pLockingStyle;
unixFile *pNew = (unixFile *)pId;
int rc = SQLITE_OK;
- assert( pNew->pLock==NULL );
- assert( pNew->pOpen==NULL );
+ assert( pNew->pInode==NULL );
- /* Parameter isDelete is only used on vxworks. Express this explicitly
+ /* Parameter isDelete is only used on vxworks. Express this explicitly
** here to prevent compiler warnings about unused parameters.
*/
UNUSED_PARAMETER(isDelete);
- OSTRACE3("OPEN %-3d %s\n", h, zFilename);
+ /* 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
+
+ OSTRACE(("OPEN %-3d %s\n", h, zFilename));
pNew->h = h;
- pNew->dirfd = dirfd;
- SET_THREADID(pNew);
- pNew->fileFlags = 0;
+ pNew->zPath = zFilename;
+ if( memcmp(pVfs->zName,"unix-excl",10)==0 ){
+ pNew->ctrlFlags = UNIXFILE_EXCL;
+ }else{
+ pNew->ctrlFlags = 0;
+ }
+ if( isReadOnly ){
+ pNew->ctrlFlags |= UNIXFILE_RDONLY;
+ }
+ if( syncDir ){
+ pNew->ctrlFlags |= UNIXFILE_DIRSYNC;
+ }
#if OS_VXWORKS
pNew->pId = vxworksFindFileId(zFilename);
@@ -25752,10 +29166,10 @@ static int fillInUnixFile(
#endif
){
unixEnterMutex();
- rc = findLockInfo(pNew, &pNew->pLock, &pNew->pOpen);
+ rc = findInodeInfo(pNew, &pNew->pInode);
if( rc!=SQLITE_OK ){
- /* If an error occured in findLockInfo(), close the file descriptor
- ** immediately, before releasing the mutex. findLockInfo() may fail
+ /* If an error occured in findInodeInfo(), close the file descriptor
+ ** immediately, before releasing the mutex. findInodeInfo() may fail
** in two scenarios:
**
** (a) A call to fstat() failed.
@@ -25764,7 +29178,7 @@ static int fillInUnixFile(
** 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
- ** findLockInfo(). If this is the case, it is quite safe to close
+ ** 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.
**
@@ -25772,7 +29186,7 @@ static int fillInUnixFile(
** implicit assumption here is that if fstat() fails, things are in
** such bad shape that dropping a lock or two doesn't matter much.
*/
- close(h);
+ robust_close(pNew, h, __LINE__);
h = -1;
}
unixLeaveMutex();
@@ -25795,20 +29209,20 @@ static int fillInUnixFile(
pCtx->reserved = 0;
srandomdev();
unixEnterMutex();
- rc = findLockInfo(pNew, &pNew->pLock, &pNew->pOpen);
+ rc = findInodeInfo(pNew, &pNew->pInode);
if( rc!=SQLITE_OK ){
sqlite3_free(pNew->lockingContext);
- close(h);
+ robust_close(pNew, h, __LINE__);
h = -1;
}
- unixLeaveMutex();
+ unixLeaveMutex();
}
}
#endif
else if( pLockingStyle == &dotlockIoMethods ){
/* Dotfile locking uses the file path so it needs to be included in
- ** the dotlockLockingContext
+ ** the dotlockLockingContext
*/
char *zLockFile;
int nFilename;
@@ -25828,37 +29242,36 @@ static int fillInUnixFile(
** included in the semLockingContext
*/
unixEnterMutex();
- rc = findLockInfo(pNew, &pNew->pLock, &pNew->pOpen);
- if( (rc==SQLITE_OK) && (pNew->pOpen->pSem==NULL) ){
- char *zSemName = pNew->pOpen->aSemName;
+ 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->pOpen->pSem = sem_open(zSemName, O_CREAT, 0666, 1);
- if( pNew->pOpen->pSem == SEM_FAILED ){
+ pNew->pInode->pSem = sem_open(zSemName, O_CREAT, 0666, 1);
+ if( pNew->pInode->pSem == SEM_FAILED ){
rc = SQLITE_NOMEM;
- pNew->pOpen->aSemName[0] = '\0';
+ pNew->pInode->aSemName[0] = '\0';
}
}
unixLeaveMutex();
}
#endif
-
+
pNew->lastErrno = 0;
#if OS_VXWORKS
if( rc!=SQLITE_OK ){
- if( h>=0 ) close(h);
+ if( h>=0 ) robust_close(pNew, h, __LINE__);
h = -1;
- unlink(zFilename);
+ osUnlink(zFilename);
isDelete = 0;
}
pNew->isDelete = isDelete;
#endif
if( rc!=SQLITE_OK ){
- if( dirfd>=0 ) close(dirfd); /* silent leak if fail, already in error */
- if( h>=0 ) close(h);
+ if( h>=0 ) robust_close(pNew, h, __LINE__);
}else{
pNew->pMethod = pLockingStyle;
OpenCounter(+1);
@@ -25867,34 +29280,32 @@ static int fillInUnixFile(
}
/*
-** 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.
-**
-** If SQLITE_OK is returned, the caller is responsible for closing
-** the file descriptor *pFd using close().
+** Return the name of a directory in which to put temporary files.
+** If no suitable temporary file directory can be found, return NULL.
*/
-static int openDirectory(const char *zFilename, int *pFd){
- int ii;
- int fd = -1;
- char zDirname[MAX_PATHNAME+1];
+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;
- sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename);
- for(ii=(int)strlen(zDirname); ii>1 && zDirname[ii]!='/'; ii--);
- if( ii>0 ){
- zDirname[ii] = '\0';
- fd = open(zDirname, O_RDONLY|O_BINARY, 0);
- if( fd>=0 ){
-#ifdef FD_CLOEXEC
- fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
-#endif
- OSTRACE3("OPENDIR %-3d %s\n", fd, zDirname);
- }
+ azDirs[0] = sqlite3_temp_directory;
+ if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
+ for(i=0; i=0?SQLITE_OK:SQLITE_CANTOPEN_BKPT);
+ return zDir;
}
/*
@@ -25902,44 +29313,24 @@ static int openDirectory(const char *zFilename, int *pFd){
** by the calling process and must be big enough to hold at least
** pVfs->mxPathname bytes.
*/
-static int getTempname(int nBuf, char *zBuf){
- static const char *azDirs[] = {
- 0,
- 0,
- "/var/tmp",
- "/usr/tmp",
- "/tmp",
- ".",
- };
+static int unixGetTempname(int nBuf, char *zBuf){
static const unsigned char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
unsigned int i, j;
- struct stat buf;
- const char *zDir = ".";
+ 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.
+ ** function failing.
*/
SimulateIOError( return SQLITE_IOERR );
- azDirs[0] = sqlite3_temp_directory;
- if (NULL == azDirs[1]) {
- azDirs[1] = getenv("TMPDIR");
- }
+ zDir = unixTempFileDir();
+ if( zDir==0 ) zDir = ".";
- for(i=0; i= (size_t)nBuf ){
@@ -25954,7 +29345,7 @@ static int getTempname(int nBuf, char *zBuf){
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
- }while( access(zBuf,0)==0 );
+ }while( osAccess(zBuf,0)==0 );
return SQLITE_OK;
}
@@ -25968,7 +29359,7 @@ static int proxyTransformUnixFile(unixFile*, const char*);
#endif
/*
-** Search for an unused file descriptor that was opened on the database
+** 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.
@@ -25977,7 +29368,7 @@ static int proxyTransformUnixFile(unixFile*, const char*);
** 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
+** 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
@@ -25988,8 +29379,8 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
/* 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
+ ** 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 */
@@ -26002,18 +29393,18 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
**
** Even if a subsequent open() call does succeed, the consequences of
** not searching for a resusable file descriptor are not dire. */
- if( 0==stat(zPath, &sStat) ){
- struct unixOpenCnt *pOpen;
+ if( 0==osStat(zPath, &sStat) ){
+ unixInodeInfo *pInode;
unixEnterMutex();
- pOpen = openList;
- while( pOpen && (pOpen->fileId.dev!=sStat.st_dev
- || pOpen->fileId.ino!=sStat.st_ino) ){
- pOpen = pOpen->pNext;
+ pInode = inodeList;
+ while( pInode && (pInode->fileId.dev!=sStat.st_dev
+ || pInode->fileId.ino!=sStat.st_ino) ){
+ pInode = pInode->pNext;
}
- if( pOpen ){
+ if( pInode ){
UnixUnusedFd **pp;
- for(pp=&pOpen->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
+ for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
pUnused = *pp;
if( pUnused ){
*pp = pUnused->pNext;
@@ -26026,8 +29417,72 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
}
/*
-** Open the file zPath.
+** 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.
**
+** If the file being opened is a temporary file, it is always created with
+** the octal permissions 0600 (read/writable by owner only). If the file
+** is a database or master journal file, it is created with the permissions
+** mask SQLITE_DEFAULT_FILE_PERMISSIONS.
+**
+** Finally, 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 */
+){
+ int rc = SQLITE_OK; /* Return Code */
+ *pMode = SQLITE_DEFAULT_FILE_PERMISSIONS;
+ 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 */
+
+ /* 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:
+ **
+ ** "-journal"
+ ** "-wal"
+ ** "-journalNN"
+ ** "-walNN"
+ **
+ ** where NN is a 4 digit decimal number. The NN naming schemes are
+ ** used by the test_multiplex.c module.
+ */
+ nDb = sqlite3Strlen30(zPath) - 1;
+ while( nDb>0 && zPath[nDb]!='-' ) nDb--;
+ if( nDb==0 ) return SQLITE_OK;
+ memcpy(zDb, zPath, nDb);
+ zDb[nDb] = '\0';
+
+ if( 0==osStat(zDb, &sStat) ){
+ *pMode = sStat.st_mode & 0777;
+ }else{
+ rc = SQLITE_IOERR_FSTAT;
+ }
+ }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
+ *pMode = 0600;
+ }
+ return rc;
+}
+
+/*
+** Open the file zPath.
+**
** Previously, the SQLite OS layer used three functions in place of this
** one:
**
@@ -26038,13 +29493,13 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
** These calls correspond to the following combinations of flags:
**
** ReadWrite() -> (READWRITE | CREATE)
-** ReadOnly() -> (READONLY)
+** 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
+** file handle closed. To achieve the same effect using this new
+** interface, add the DELETEONCLOSE flag to those specified above for
** OpenExclusive().
*/
static int unixOpen(
@@ -26056,7 +29511,6 @@ static int unixOpen(
){
unixFile *p = (unixFile *)pFile;
int fd = -1; /* File descriptor returned by open() */
- int dirfd = -1; /* Directory file descriptor */
int openFlags = 0; /* Flags to pass to open() */
int eType = flags&0xFFFFFF00; /* Type of file to open */
int noLock; /* True to omit locking primitives */
@@ -26070,14 +29524,19 @@ static int unixOpen(
#if SQLITE_ENABLE_LOCKING_STYLE
int isAutoProxy = (flags & SQLITE_OPEN_AUTOPROXY);
#endif
+#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
+ struct statfs fsInfo;
+#endif
/* 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 isOpenDirectory = (isCreate &&
- (eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL)
- );
+ 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.
@@ -26085,9 +29544,9 @@ static int unixOpen(
char zTmpname[MAX_PATHNAME+1];
const char *zName = zPath;
- /* Check the following statements are true:
+ /* Check the following statements are true:
**
- ** (a) Exactly one of the READWRITE and READONLY flags must be set, and
+ ** (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.
@@ -26097,17 +29556,18 @@ static int unixOpen(
assert(isExclusive==0 || isCreate);
assert(isDelete==0 || isCreate);
- /* The main DB, main journal, and master journal are never automatically
- ** deleted. Nor are they ever temporary files. */
+ /* 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
+ 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));
@@ -26126,8 +29586,8 @@ static int unixOpen(
p->pUnused = pUnused;
}else if( !zName ){
/* If zName is NULL, the upper layer is requesting a temp file. */
- assert(isDelete && !isOpenDirectory);
- rc = getTempname(MAX_PATHNAME+1, zTmpname);
+ assert(isDelete && !syncDir);
+ rc = unixGetTempname(MAX_PATHNAME+1, zTmpname);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -26136,7 +29596,7 @@ static int unixOpen(
/* 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
+ ** 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;
@@ -26145,19 +29605,26 @@ static int unixOpen(
openFlags |= (O_LARGEFILE|O_BINARY);
if( fd<0 ){
- mode_t openMode = (isDelete?0600:SQLITE_DEFAULT_FILE_PERMISSIONS);
- fd = open(zName, openFlags, openMode);
- OSTRACE4("OPENX %-3d %s 0%o\n", fd, zName, openFlags);
+ mode_t openMode; /* Permissions to create file with */
+ rc = findCreateFileMode(zName, flags, &openMode);
+ 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;
- fd = open(zName, openFlags, openMode);
+ isReadonly = 1;
+ fd = robust_open(zName, openFlags, openMode);
}
if( fd<0 ){
- rc = SQLITE_CANTOPEN_BKPT;
+ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
goto open_finished;
}
}
@@ -26175,7 +29642,7 @@ static int unixOpen(
#if OS_VXWORKS
zPath = zName;
#else
- unlink(zName);
+ osUnlink(zName);
#endif
}
#if SQLITE_ENABLE_LOCKING_STYLE
@@ -26184,39 +29651,24 @@ static int unixOpen(
}
#endif
- if( isOpenDirectory ){
- rc = openDirectory(zPath, &dirfd);
- if( rc!=SQLITE_OK ){
- /* It is safe to close fd at this point, because it is guaranteed not
- ** to be open on a database file. If it were open on a database file,
- ** it would not be safe to close as this would release any locks held
- ** on the file by this process. */
- assert( eType!=SQLITE_OPEN_MAIN_DB );
- close(fd); /* silently leak if fail, already in error */
- goto open_finished;
- }
- }
-
#ifdef FD_CLOEXEC
- fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
+ osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
#endif
noLock = eType!=SQLITE_OPEN_MAIN_DB;
-
+
#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
- struct statfs fsInfo;
if( fstatfs(fd, &fsInfo) == -1 ){
((unixFile*)pFile)->lastErrno = errno;
- if( dirfd>=0 ) close(dirfd); /* silently leak if fail, in error */
- close(fd); /* silently leak if fail, in error */
+ 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
-
+
#if SQLITE_ENABLE_LOCKING_STYLE
#if SQLITE_PREFER_PROXY_LOCKING
isAutoProxy = 1;
@@ -26225,12 +29677,11 @@ static int unixOpen(
char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING");
int useProxy = 0;
- /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means
+ /* 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{
- struct statfs fsInfo;
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
@@ -26240,23 +29691,21 @@ static int unixOpen(
** not while other file descriptors opened by the same process on
** the same file are working. */
p->lastErrno = errno;
- if( dirfd>=0 ){
- close(dirfd); /* silently leak if fail, in error */
- }
- close(fd); /* silently leak if fail, in error */
+ robust_close(p, fd, __LINE__);
rc = SQLITE_IOERR_ACCESS;
goto open_finished;
}
useProxy = !(fsInfo.f_flags&MNT_LOCAL);
}
if( useProxy ){
- rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete);
+ rc = fillInUnixFile(pVfs, fd, syncDir, pFile, zPath, noLock,
+ isDelete, isReadonly);
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
+ /* 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;
@@ -26266,8 +29715,9 @@ static int unixOpen(
}
}
#endif
-
- rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete);
+
+ rc = fillInUnixFile(pVfs, fd, syncDir, pFile, zPath, noLock,
+ isDelete, isReadonly);
open_finished:
if( rc!=SQLITE_OK ){
sqlite3_free(p->pUnused);
@@ -26288,11 +29738,13 @@ static int unixDelete(
int rc = SQLITE_OK;
UNUSED_PARAMETER(NotUsed);
SimulateIOError(return SQLITE_IOERR_DELETE);
- unlink(zPath);
+ if( osUnlink(zPath)==(-1) && errno!=ENOENT ){
+ return unixLogError(SQLITE_IOERR_DELETE, "unlink", zPath);
+ }
#ifndef SQLITE_DISABLE_DIRSYNC
if( dirSync ){
int fd;
- rc = openDirectory(zPath, &fd);
+ rc = osOpenDirectory(zPath, &fd);
if( rc==SQLITE_OK ){
#if OS_VXWORKS
if( fsync(fd)==-1 )
@@ -26300,11 +29752,11 @@ static int unixDelete(
if( fsync(fd) )
#endif
{
- rc = SQLITE_IOERR_DIR_FSYNC;
- }
- if( close(fd)&&!rc ){
- rc = SQLITE_IOERR_DIR_CLOSE;
+ rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath);
}
+ robust_close(0, fd, __LINE__);
+ }else if( rc==SQLITE_CANTOPEN ){
+ rc = SQLITE_OK;
}
}
#endif
@@ -26344,7 +29796,13 @@ static int unixAccess(
default:
assert(!"Invalid flags argument");
}
- *pResOut = (access(zPath, amode)==0);
+ *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;
}
@@ -26352,9 +29810,9 @@ static int unixAccess(
/*
** 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.
+** zPath.
**
-** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes
+** 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.
*/
@@ -26380,8 +29838,8 @@ static int unixFullPathname(
sqlite3_snprintf(nOut, zOut, "%s", zPath);
}else{
int nCwd;
- if( getcwd(zOut, nOut-1)==0 ){
- return SQLITE_CANTOPEN_BKPT;
+ 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);
@@ -26409,7 +29867,7 @@ static void *unixDlOpen(sqlite3_vfs *NotUsed, const char *zFilename){
** error message.
*/
static void unixDlError(sqlite3_vfs *NotUsed, int nBuf, char *zBufOut){
- char *zErr;
+ const char *zErr;
UNUSED_PARAMETER(NotUsed);
unixEnterMutex();
zErr = dlerror();
@@ -26419,7 +29877,7 @@ static void unixDlError(sqlite3_vfs *NotUsed, int nBuf, char *zBufOut){
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
@@ -26429,7 +29887,7 @@ static void (*unixDlSym(sqlite3_vfs *NotUsed, void *p, const char*zSym))(void){
** 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.
+ ** 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
@@ -26475,7 +29933,7 @@ static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
#if !defined(SQLITE_TEST)
{
int pid, fd;
- fd = open("/dev/urandom", O_RDONLY);
+ fd = robust_open("/dev/urandom", O_RDONLY, 0);
if( fd<0 ){
time_t t;
time(&t);
@@ -26485,8 +29943,8 @@ static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf );
nBuf = sizeof(t) + sizeof(pid);
}else{
- nBuf = read(fd, zBuf, nBuf);
- close(fd);
+ do{ nBuf = osRead(fd, zBuf, nBuf); }while( nBuf<0 && errno==EINTR );
+ robust_close(0, fd, __LINE__);
}
}
#endif
@@ -26532,36 +29990,50 @@ static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){
SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */
#endif
+/*
+** 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 0. Return 1 if the time and date cannot be found.
+*/
+static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
+ static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
+#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;
+ gettimeofday(&sNow, 0);
+ *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
+#endif
+
+#ifdef SQLITE_TEST
+ if( sqlite3_current_time ){
+ *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
+ }
+#endif
+ UNUSED_PARAMETER(NotUsed);
+ return 0;
+}
+
/*
** 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){
-#if defined(SQLITE_OMIT_FLOATING_POINT)
- time_t t;
- time(&t);
- *prNow = (((sqlite3_int64)t)/8640 + 24405875)/10;
-#elif defined(NO_GETTOD)
- time_t t;
- time(&t);
- *prNow = t/86400.0 + 2440587.5;
-#elif OS_VXWORKS
- struct timespec sNow;
- clock_gettime(CLOCK_REALTIME, &sNow);
- *prNow = 2440587.5 + sNow.tv_sec/86400.0 + sNow.tv_nsec/86400000000000.0;
-#else
- struct timeval sNow;
- gettimeofday(&sNow, 0);
- *prNow = 2440587.5 + sNow.tv_sec/86400.0 + sNow.tv_usec/86400000000.0;
-#endif
-
-#ifdef SQLITE_TEST
- if( sqlite3_current_time ){
- *prNow = sqlite3_current_time/86400.0 + 2440587.5;
- }
-#endif
+ sqlite3_int64 i;
UNUSED_PARAMETER(NotUsed);
+ unixCurrentTimeInt64(0, &i);
+ *prNow = i/86400000.0;
return 0;
}
@@ -26579,6 +30051,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
return 0;
}
+
/*
************************ End of sqlite3_vfs methods ***************************
******************************************************************************/
@@ -26607,7 +30080,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
** address in the shared range is taken for a SHARED lock, the entire
** shared range is taken for an EXCLUSIVE lock):
**
-** PENDING_BYTE 0x40000000
+** PENDING_BYTE 0x40000000
** RESERVED_BYTE 0x40000001
** SHARED_RANGE 0x40000002 -> 0x40000200
**
@@ -26625,7 +30098,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
** 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.
+** and onto a proxy file on the local file system.
**
**
** Using proxy locks
@@ -26650,19 +30123,19 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
** actual proxy file name is generated from the name and path of the
** database file. For example:
**
-** For database path "/Users/me/foo.db"
+** For database path "/Users/me/foo.db"
** The lock path will be "/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).
+** connection or process).
**
**
** How proxy locking works
** -----------------------
**
-** Proxy file locking relies primarily on two new supporting files:
+** 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
@@ -26689,11 +30162,11 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
** 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.
+** 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 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.
@@ -26707,7 +30180,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
** 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
@@ -26722,8 +30195,8 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
**
** 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
@@ -26733,12 +30206,12 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
*/
/*
-** Proxy locking is only available on MacOSX
+** Proxy locking is only available on MacOSX
*/
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
/*
-** The proxyLockingContext has the path and file structures for the remote
+** The proxyLockingContext has the path and file structures for the remote
** and local proxy files in it
*/
typedef struct proxyLockingContext proxyLockingContext;
@@ -26753,10 +30226,10 @@ struct proxyLockingContext {
sqlite3_io_methods const *pOldMethod; /* Original I/O methods for close */
};
-/*
-** The proxy lock file path for the database at dbPath is written into lPath,
+/*
+** 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.
+** file path.
*/
static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
int len;
@@ -26769,11 +30242,11 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
# ifdef _CS_DARWIN_USER_TEMP_DIR
{
if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){
- OSTRACE4("GETLOCKPATH failed %s errno=%d pid=%d\n",
- lPath, errno, getpid());
+ OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n",
+ lPath, errno, getpid()));
return SQLITE_IOERR_LOCK;
}
- len = strlcat(lPath, "sqliteplocks", maxLen);
+ len = strlcat(lPath, "sqliteplocks", maxLen);
}
# else
len = strlcpy(lPath, "/tmp/", maxLen);
@@ -26783,27 +30256,27 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
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 0) ){
/* only mkdir if leaf dir != "." or "/" or ".." */
- if( i-start>2 || (i-start==1 && buf[start] != '.' && buf[start] != '/')
+ if( i-start>2 || (i-start==1 && buf[start] != '.' && buf[start] != '/')
|| (i-start==2 && buf[start] != '.' && buf[start+1] != '.') ){
buf[i]='\0';
if( mkdir(buf, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){
int err=errno;
if( err!=EEXIST ) {
- OSTRACE5("CREATELOCKPATH FAILED creating %s, "
+ OSTRACE(("CREATELOCKPATH FAILED creating %s, "
"'%s' proxy lock path=%s pid=%d\n",
- buf, strerror(err), lockPath, getpid());
+ buf, strerror(err), lockPath, getpid()));
return err;
}
}
@@ -26828,7 +30301,7 @@ static int proxyCreateLockPath(const char *lockPath){
}
buf[i] = lockPath[i];
}
- OSTRACE3("CREATELOCKPATH proxy lock path=%s pid=%d\n", lockPath, getpid());
+ OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n", lockPath, getpid()));
return 0;
}
@@ -26845,7 +30318,6 @@ static int proxyCreateUnixFile(
int islockfile /* if non zero missing dirs will be created */
) {
int fd = -1;
- int dirfd = -1;
unixFile *pNew;
int rc = SQLITE_OK;
int openFlags = O_RDWR | O_CREAT;
@@ -26869,17 +30341,17 @@ static int proxyCreateUnixFile(
}
}
if( fd<0 ){
- fd = open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
+ fd = robust_open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
terrno = errno;
if( fd<0 && errno==ENOENT && islockfile ){
if( proxyCreateLockPath(path) == SQLITE_OK ){
- fd = open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
+ fd = robust_open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
}
}
}
if( fd<0 ){
openFlags = O_RDONLY;
- fd = open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
+ fd = robust_open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
terrno = errno;
}
if( fd<0 ){
@@ -26889,13 +30361,13 @@ static int proxyCreateUnixFile(
switch (terrno) {
case EACCES:
return SQLITE_PERM;
- case EIO:
+ 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;
@@ -26903,18 +30375,20 @@ static int proxyCreateUnixFile(
}
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, dirfd, (sqlite3_file*)pNew, path, 0, 0);
+
+ rc = fillInUnixFile(&dummyVfs, fd, 0, (sqlite3_file*)pNew, path, 0, 0, 0);
if( rc==SQLITE_OK ){
*ppFile = pNew;
return SQLITE_OK;
}
-end_create_proxy:
- close(fd); /* silently leak fd if error, we're already in error */
+end_create_proxy:
+ robust_close(pNew, fd, __LINE__);
sqlite3_free(pNew);
sqlite3_free(pUnused);
return rc;
@@ -26927,28 +30401,37 @@ SQLITE_API int sqlite3_hostid_num = 0;
#define PROXY_HOSTIDLEN 16 /* conch file host id length */
-/* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN
+/* 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){
- struct timespec timeout = {1, 0}; /* 1 sec timeout */
-
assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
memset(pHostID, 0, PROXY_HOSTIDLEN);
- if( gethostuuid(pHostID, &timeout) ){
- int err = errno;
- if( pError ){
- *pError = err;
+#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;
}
- return SQLITE_IOERR;
}
+#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));
}
#endif
-
+
return SQLITE_OK;
}
@@ -26959,14 +30442,14 @@ static int proxyGetHostID(unsigned char *pHostID, int *pError){
#define PROXY_PATHINDEX (PROXY_HEADERLEN+PROXY_HOSTIDLEN)
#define PROXY_MAXCONCHLEN (PROXY_HEADERLEN+PROXY_HOSTIDLEN+MAXPATHLEN)
-/*
-** Takes an open conch file, copies the contents to a new path and then moves
+/*
+** 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
+** conch file structure and finally the original conch file descriptor is
** closed. Returns zero if successful.
*/
static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){
- proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
+ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
unixFile *conchFile = pCtx->conchFile;
char tPath[MAXPATHLEN];
char buf[PROXY_MAXCONCHLEN];
@@ -26976,92 +30459,95 @@ static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){
char errmsg[64] = "";
int fd = -1;
int rc = -1;
+ UNUSED_PARAMETER(myHostID);
/* create a new path by replace the trailing '-conch' with '-break' */
pathLen = strlcpy(tPath, cPath, MAXPATHLEN);
- if( pathLen>MAXPATHLEN || pathLen<6 ||
+ if( pathLen>MAXPATHLEN || pathLen<6 ||
(strlcpy(&tPath[pathLen-5], "break", 6) != 5) ){
- sprintf(errmsg, "path error (len %d)", (int)pathLen);
+ sqlite3_snprintf(sizeof(errmsg),errmsg,"path error (len %d)",(int)pathLen);
goto end_breaklock;
}
/* read the conch content */
- readLen = pread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
+ readLen = osPread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
if( readLenh);
+ robust_close(pFile, conchFile->h, __LINE__);
conchFile->h = fd;
conchFile->openFlags = O_RDWR | O_CREAT;
end_breaklock:
if( rc ){
if( fd>=0 ){
- unlink(tPath);
- close(fd);
+ osUnlink(tPath);
+ robust_close(pFile, fd, __LINE__);
}
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
+/* 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;
+ 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
+ * 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( fstat(conchFile->h, &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;
+ continue;
}
assert( nTries>1 );
- if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec ||
+ if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec ||
conchModTime.tv_nsec != buf.st_mtimespec.tv_nsec ){
return SQLITE_BUSY;
}
-
- if( nTries==2 ){
+
+ if( nTries==2 ){
char tBuf[PROXY_MAXCONCHLEN];
- int len = pread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0);
+ int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0);
if( len<0 ){
pFile->lastErrno = errno;
return SQLITE_IOERR_LOCK;
@@ -27076,14 +30562,14 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
return SQLITE_BUSY;
}
usleep(10000000); /* wait 10 sec and try the lock again */
- continue;
+ 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);
+ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK);
}
if( !rc ){
rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
@@ -27091,19 +30577,19 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
}
}
} while( rc==SQLITE_BUSY && nTries<3 );
-
+
return rc;
}
-/* 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
+/* 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;
-
+ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
+
if( pCtx->conchHeld!=0 ){
return SQLITE_OK;
}else{
@@ -27119,9 +30605,9 @@ static int proxyTakeConch(unixFile *pFile){
int readLen = 0;
int tryOldLockPath = 0;
int forceNewLockPath = 0;
-
- OSTRACE4("TAKECONCH %d for %s pid=%d\n", conchFile->h,
- (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), getpid());
+
+ 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 ){
@@ -27139,21 +30625,21 @@ static int proxyTakeConch(unixFile *pFile){
pFile->lastErrno = conchFile->lastErrno;
rc = SQLITE_IOERR_READ;
goto end_takeconch;
- }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) ||
+ }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.
+ /* 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
+ ** 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 */
if( !createConch && !forceNewLockPath ){
- hostIdMatch = !memcmp(&readBuf[PROXY_HEADERLEN], myHostID,
+ hostIdMatch = !memcmp(&readBuf[PROXY_HEADERLEN], myHostID,
PROXY_HOSTIDLEN);
/* if the conch has data compare the contents */
if( !pCtx->lockProxyPath ){
@@ -27162,7 +30648,7 @@ static int proxyTakeConch(unixFile *pFile){
*/
if( hostIdMatch ){
size_t pathLen = (readLen - PROXY_PATHINDEX);
-
+
if( pathLen>=MAXPATHLEN ){
pathLen=MAXPATHLEN-1;
}
@@ -27178,34 +30664,34 @@ static int proxyTakeConch(unixFile *pFile){
readLen-PROXY_PATHINDEX)
){
/* conch host and lock path match */
- goto end_takeconch;
+ 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->pLock && conchFile->pLock->cnt>1 ){
+ 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 {
+ } else {
rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK);
}
}else{
@@ -27214,7 +30700,7 @@ static int proxyTakeConch(unixFile *pFile){
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 ){
@@ -27223,23 +30709,26 @@ static int proxyTakeConch(unixFile *pFile){
strlcpy(&writeBuffer[PROXY_PATHINDEX], tempLockPath, MAXPATHLEN);
}
writeSize = PROXY_PATHINDEX + strlen(&writeBuffer[PROXY_PATHINDEX]);
- ftruncate(conchFile->h, writeSize);
+ 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 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 = fstat(pFile->h, &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
- fchmod(conchFile->h, cmode);
+ osFchmod(conchFile->h, cmode);
#else
- if( fchmod(conchFile->h, cmode)!=0 ){
+ 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));
@@ -27248,31 +30737,25 @@ static int proxyTakeConch(unixFile *pFile){
}
}else{
int code = errno;
- fprintf(stderr, "STAT FAILED[%d] with %d %s\n",
+ fprintf(stderr, "STAT FAILED[%d] with %d %s\n",
err, code, strerror(code));
#endif
}
}
}
conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK);
-
+
end_takeconch:
- OSTRACE2("TRANSPROXY: CLOSE %d\n", pFile->h);
+ OSTRACE(("TRANSPROXY: CLOSE %d\n", pFile->h));
if( rc==SQLITE_OK && pFile->openFlags ){
+ int fd;
if( pFile->h>=0 ){
-#ifdef STRICT_CLOSE_ERROR
- if( close(pFile->h) ){
- pFile->lastErrno = errno;
- return SQLITE_IOERR_CLOSE;
- }
-#else
- close(pFile->h); /* silently leak fd if fail */
-#endif
+ robust_close(pFile, pFile->h, __LINE__);
}
pFile->h = -1;
- int fd = open(pCtx->dbPath, pFile->openFlags,
+ fd = robust_open(pCtx->dbPath, pFile->openFlags,
SQLITE_DEFAULT_FILE_PERMISSIONS);
- OSTRACE2("TRANSPROXY: OPEN %d\n", fd);
+ OSTRACE(("TRANSPROXY: OPEN %d\n", fd));
if( fd>=0 ){
pFile->h = fd;
}else{
@@ -27285,7 +30768,7 @@ static int proxyTakeConch(unixFile *pFile){
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
+ ** so try again via auto-naming
*/
forceNewLockPath = 1;
tryOldLockPath = 0;
@@ -27305,7 +30788,7 @@ static int proxyTakeConch(unixFile *pFile){
}
if( rc==SQLITE_OK ){
pCtx->conchHeld = 1;
-
+
if( pCtx->lockProxy->pMethod == &afpIoMethods ){
afpLockingContext *afpCtx;
afpCtx = (afpLockingContext *)pCtx->lockProxy->lockingContext;
@@ -27314,9 +30797,11 @@ static int proxyTakeConch(unixFile *pFile){
} else {
conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK);
}
- OSTRACE3("TAKECONCH %d %s\n", conchFile->h, rc==SQLITE_OK?"ok":"failed");
+ 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. */
+ } while (1); /* in case we need to retry the :auto: lock file -
+ ** we should never get here except via the 'continue' call. */
}
}
@@ -27324,21 +30809,21 @@ static int proxyTakeConch(unixFile *pFile){
** If pFile holds a lock on a conch file, then release that lock.
*/
static int proxyReleaseConch(unixFile *pFile){
- int rc; /* Subroutine return code */
+ int rc = SQLITE_OK; /* Subroutine return code */
proxyLockingContext *pCtx; /* The locking context for the proxy lock */
unixFile *conchFile; /* Name of the conch file */
pCtx = (proxyLockingContext *)pFile->lockingContext;
conchFile = pCtx->conchFile;
- OSTRACE4("RELEASECONCH %d for %s pid=%d\n", conchFile->h,
- (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"),
- getpid());
+ 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;
- OSTRACE3("RELEASECONCH %d %s\n", conchFile->h,
- (rc==SQLITE_OK ? "ok" : "failed"));
+ OSTRACE(("RELEASECONCH %d %s\n", conchFile->h,
+ (rc==SQLITE_OK ? "ok" : "failed")));
return rc;
}
@@ -27359,13 +30844,13 @@ static int proxyCreateConchPathname(char *dbPath, char **pConchPath){
char *conchPath; /* buffer in which to construct conch name */
/* Allocate space for the conch filename and initialize the name to
- ** the name of the original database file. */
+ ** 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]=='/' ){
@@ -27388,16 +30873,16 @@ static int proxyCreateConchPathname(char *dbPath, char **pConchPath){
/* Takes a fully configured proxy locking-style unix file and switches
-** the local lock file path
+** 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( pFile->locktype!=NO_LOCK ){
+ if( pFile->eFileLock!=NO_LOCK ){
return SQLITE_BUSY;
- }
+ }
/* nothing to do if the path is NULL, :auto: or matches the existing path */
if( !path || path[0]=='\0' || !strcmp(path, ":auto:") ||
@@ -27415,7 +30900,7 @@ static int switchLockProxyPath(unixFile *pFile, const char *path) {
sqlite3_free(oldPath);
pCtx->lockProxyPath = sqlite3DbStrDup(0, path);
}
-
+
return rc;
}
@@ -27429,7 +30914,7 @@ static int switchLockProxyPath(unixFile *pFile, const char *path) {
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
+ /* 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);
@@ -27449,9 +30934,9 @@ static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath){
}
/*
-** Takes an already filled in unix file and alters it so all file locking
+** 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
+** are preserved in the locking context so that they can be restored and
** the unix structure properly cleaned up at close time:
** ->lockingContext
** ->pMethod
@@ -27461,8 +30946,8 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
char dbPath[MAXPATHLEN+1]; /* Name of the database file */
char *lockPath=NULL;
int rc = SQLITE_OK;
-
- if( pFile->locktype!=NO_LOCK ){
+
+ if( pFile->eFileLock!=NO_LOCK ){
return SQLITE_BUSY;
}
proxyGetDbPathForUnixFile(pFile, dbPath);
@@ -27471,9 +30956,9 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
}else{
lockPath=(char *)path;
}
-
- OSTRACE4("TRANSPROXY %d for %s pid=%d\n", pFile->h,
- (lockPath ? lockPath : ":auto:"), getpid());
+
+ OSTRACE(("TRANSPROXY %d for %s pid=%d\n", pFile->h,
+ (lockPath ? lockPath : ":auto:"), getpid()));
pCtx = sqlite3_malloc( sizeof(*pCtx) );
if( pCtx==0 ){
@@ -27494,7 +30979,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
struct stat conchInfo;
int goLockless = 0;
- if( stat(pCtx->conchFilePath, &conchInfo) == -1 ) {
+ if( osStat(pCtx->conchFilePath, &conchInfo) == -1 ) {
int err = errno;
if( (err==ENOENT) && (statfs(dbPath, &fsInfo) != -1) ){
goLockless = (fsInfo.f_flags&MNT_RDONLY) == MNT_RDONLY;
@@ -27505,7 +30990,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
rc = SQLITE_OK;
}
}
- }
+ }
if( rc==SQLITE_OK && lockPath ){
pCtx->lockProxyPath = sqlite3DbStrDup(0, lockPath);
}
@@ -27517,7 +31002,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
}
}
if( rc==SQLITE_OK ){
- /* all memory is allocated, proxys are created and assigned,
+ /* all memory is allocated, proxys are created and assigned,
** switch the locking context and pMethod then return.
*/
pCtx->oldLockingContext = pFile->lockingContext;
@@ -27525,16 +31010,16 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
pCtx->pOldMethod = pFile->pMethod;
pFile->pMethod = &proxyIoMethods;
}else{
- if( pCtx->conchFile ){
+ if( pCtx->conchFile ){
pCtx->conchFile->pMethod->xClose((sqlite3_file *)pCtx->conchFile);
sqlite3_free(pCtx->conchFile);
}
- sqlite3_free(pCtx->lockProxyPath);
- sqlite3_free(pCtx->conchFilePath);
+ sqlite3DbFree(0, pCtx->lockProxyPath);
+ sqlite3_free(pCtx->conchFilePath);
sqlite3_free(pCtx);
}
- OSTRACE3("TRANSPROXY %d %s\n", pFile->h,
- (rc==SQLITE_OK ? "ok" : "failed"));
+ OSTRACE(("TRANSPROXY %d %s\n", pFile->h,
+ (rc==SQLITE_OK ? "ok" : "failed")));
return rc;
}
@@ -27575,9 +31060,9 @@ static int proxyFileControl(sqlite3_file *id, int op, void *pArg){
}else{
const char *proxyPath = (const char *)pArg;
if( isProxyStyle ){
- proxyLockingContext *pCtx =
+ proxyLockingContext *pCtx =
(proxyLockingContext*)pFile->lockingContext;
- if( !strcmp(pArg, ":auto:")
+ if( !strcmp(pArg, ":auto:")
|| (pCtx->lockProxyPath &&
!strncmp(pCtx->lockProxyPath, proxyPath, MAXPATHLEN))
){
@@ -27629,7 +31114,7 @@ static int proxyCheckReservedLock(sqlite3_file *id, int *pResOut) {
}
/*
-** Lock the file with the lock specified by parameter locktype - one
+** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
@@ -27652,15 +31137,15 @@ static int proxyCheckReservedLock(sqlite3_file *id, int *pResOut) {
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-static int proxyLock(sqlite3_file *id, int locktype) {
+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, locktype);
- pFile->locktype = proxy->locktype;
+ rc = proxy->pMethod->xLock((sqlite3_file*)proxy, eFileLock);
+ pFile->eFileLock = proxy->eFileLock;
}else{
/* conchHeld < 0 is lockless */
}
@@ -27670,21 +31155,21 @@ static int proxyLock(sqlite3_file *id, int locktype) {
/*
-** Lower the locking level on file descriptor pFile to locktype. locktype
+** 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 locktype) {
+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, locktype);
- pFile->locktype = proxy->locktype;
+ rc = proxy->pMethod->xUnlock((sqlite3_file*)proxy, eFileLock);
+ pFile->eFileLock = proxy->eFileLock;
}else{
/* conchHeld < 0 is lockless */
}
@@ -27702,7 +31187,7 @@ static int proxyClose(sqlite3_file *id) {
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;
@@ -27720,9 +31205,9 @@ static int proxyClose(sqlite3_file *id) {
if( rc ) return rc;
sqlite3_free(conchFile);
}
- sqlite3_free(pCtx->lockProxyPath);
+ sqlite3DbFree(0, pCtx->lockProxyPath);
sqlite3_free(pCtx->conchFilePath);
- sqlite3_free(pCtx->dbPath);
+ sqlite3DbFree(0, pCtx->dbPath);
/* restore the original locking context and pMethod then close it */
pFile->lockingContext = pCtx->oldLockingContext;
pFile->pMethod = pCtx->pOldMethod;
@@ -27739,7 +31224,7 @@ static int proxyClose(sqlite3_file *id) {
** 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 **********************
******************************************************************************/
@@ -27757,8 +31242,8 @@ static int proxyClose(sqlite3_file *id) {
** necessarily been initialized when this routine is called, and so they
** should not be used.
*/
-SQLITE_API int sqlite3_os_init(void){
- /*
+SQLITE_API int 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
@@ -27774,12 +31259,12 @@ SQLITE_API int sqlite3_os_init(void){
**
** 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
+ ** 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) { \
- 1, /* iVersion */ \
+ 3, /* iVersion */ \
sizeof(unixFile), /* szOsFile */ \
MAX_PATHNAME, /* mxPathname */ \
0, /* pNext */ \
@@ -27796,7 +31281,11 @@ SQLITE_API int sqlite3_os_init(void){
unixRandomness, /* xRandomness */ \
unixSleep, /* xSleep */ \
unixCurrentTime, /* xCurrentTime */ \
- unixGetLastError /* xGetLastError */ \
+ unixGetLastError, /* xGetLastError */ \
+ unixCurrentTimeInt64, /* xCurrentTimeInt64 */ \
+ unixSetSystemCall, /* xSetSystemCall */ \
+ unixGetSystemCall, /* xGetSystemCall */ \
+ unixNextSystemCall, /* xNextSystemCall */ \
}
/*
@@ -27814,6 +31303,7 @@ SQLITE_API int sqlite3_os_init(void){
#endif
UNIXVFS("unix-none", nolockIoFinder ),
UNIXVFS("unix-dotfile", dotlockIoFinder ),
+ UNIXVFS("unix-excl", posixIoFinder ),
#if OS_VXWORKS
UNIXVFS("unix-namedsem", semIoFinder ),
#endif
@@ -27831,11 +31321,15 @@ SQLITE_API int sqlite3_os_init(void){
};
unsigned int i; /* Loop counter */
+ /* Double-check that the aSyscall[] array has been constructed
+ ** correctly. See ticket [bb3a86e890c8e96ab] */
+ assert( ArraySize(aSyscall)==18 );
+
/* 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;
+ return SQLITE_OK;
}
/*
@@ -27845,10 +31339,10 @@ SQLITE_API int sqlite3_os_init(void){
** to release dynamically allocated objects. But not on unix.
** This routine is a no-op for unix.
*/
-SQLITE_API int sqlite3_os_end(void){
- return SQLITE_OK;
+SQLITE_API int sqlite3_os_end(void){
+ return SQLITE_OK;
}
-
+
#endif /* SQLITE_OS_UNIX */
/************** End of os_unix.c *********************************************/
@@ -27945,25 +31439,14 @@ SQLITE_API int sqlite3_os_end(void){
# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
#endif
-#ifdef SQLITE_DEBUG
-SQLITE_PRIVATE int sqlite3OSTrace = 0;
-#define OSTRACE1(X) if( sqlite3OSTrace ) sqlite3DebugPrintf(X)
-#define OSTRACE2(X,Y) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y)
-#define OSTRACE3(X,Y,Z) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z)
-#define OSTRACE4(X,Y,Z,A) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A)
-#define OSTRACE5(X,Y,Z,A,B) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A,B)
-#define OSTRACE6(X,Y,Z,A,B,C) \
- if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
-#define OSTRACE7(X,Y,Z,A,B,C,D) \
- if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
+#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 OSTRACE1(X)
-#define OSTRACE2(X,Y)
-#define OSTRACE3(X,Y,Z)
-#define OSTRACE4(X,Y,Z,A)
-#define OSTRACE5(X,Y,Z,A,B)
-#define OSTRACE6(X,Y,Z,A,B,C)
-#define OSTRACE7(X,Y,Z,A,B,C,D)
+# define OSTRACE(X)
#endif
/*
@@ -27972,8 +31455,8 @@ SQLITE_PRIVATE int sqlite3OSTrace = 0;
*/
#ifdef SQLITE_PERFORMANCE_TRACE
-/*
-** hwtime.h contains inline assembler code for implementing
+/*
+** hwtime.h contains inline assembler code for implementing
** high-performance timing routines.
*/
/************** Include hwtime.h in the middle of os_common.h ****************/
@@ -28031,7 +31514,7 @@ SQLITE_PRIVATE int sqlite3OSTrace = 0;
__asm__ __volatile__ ("rdtsc" : "=A" (val));
return val;
}
-
+
#elif (defined(__GNUC__) && defined(__ppc__))
__inline__ sqlite_uint64 sqlite3Hwtime(void){
@@ -28137,7 +31620,7 @@ SQLITE_API int sqlite3_open_file_count = 0;
** Some microsoft compilers lack this definition.
*/
#ifndef INVALID_FILE_ATTRIBUTES
-# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif
/*
@@ -28149,6 +31632,10 @@ SQLITE_API int sqlite3_open_file_count = 0;
# define FormatMessageW(a,b,c,d,e,f,g) 0
#endif
+/* Forward references */
+typedef struct winShm winShm; /* A connection to shared-memory */
+typedef struct winShmNode winShmNode; /* A region of shared-memory */
+
/*
** WinCE lacks native support for file locking so we have to fake it
** with some code of our own.
@@ -28168,21 +31655,97 @@ typedef struct winceLock {
*/
typedef struct winFile winFile;
struct winFile {
- const sqlite3_io_methods *pMethod;/* Must be first */
+ 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 */
- unsigned char locktype; /* Type of lock currently held on this file */
+ u8 locktype; /* Type of lock currently held on this file */
short sharedLockByte; /* Randomly chosen byte used as a shared lock */
+ u8 bPersistWal; /* True to persist WAL files */
DWORD lastErrno; /* The Windows errno from the last I/O error */
DWORD sectorSize; /* Sector size of the device file is on */
+ winShm *pShm; /* Instance of shared memory on this file */
+ const char *zPath; /* Full pathname of this file */
+ int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */
#if SQLITE_OS_WINCE
WCHAR *zDeleteOnClose; /* Name of file to delete when closing */
- HANDLE hMutex; /* Mutex used to control access to shared lock */
+ 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 compiled with SQLITE_WIN32_MALLOC on Windows, we will use the
+ * various Win32 API heap functions instead of our own.
+ */
+#ifdef SQLITE_WIN32_MALLOC
+/*
+ * 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
+
+/*
+ * 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
+
+/*
+ * 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
+
+/*
+** 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)? */
+};
+
+#ifndef NDEBUG
+#define WINMEM_MAGIC 0x42b2830b
+#endif
+
+static struct winMemData win_mem_data = {
+#ifndef NDEBUG
+ WINMEM_MAGIC,
+#endif
+ NULL, FALSE
+};
+
+#ifndef NDEBUG
+#define winMemAssertMagic() assert( win_mem_data.magic==WINMEM_MAGIC )
+#else
+#define winMemAssertMagic()
+#endif
+
+#define winMemGetHeap() win_mem_data.hHeap
+
+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);
+
+SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetWin32(void);
+#endif /* SQLITE_WIN32_MALLOC */
+
/*
** Forward prototypes.
*/
@@ -28234,8 +31797,190 @@ static int sqlite3_os_type = 0;
}
#endif /* SQLITE_OS_WINCE */
+#ifdef SQLITE_WIN32_MALLOC
/*
-** Convert a UTF-8 string to microsoft unicode (UTF-16?).
+** Allocate nBytes of memory.
+*/
+static void *winMemMalloc(int nBytes){
+ HANDLE hHeap;
+ void *p;
+
+ winMemAssertMagic();
+ hHeap = winMemGetHeap();
+ assert( hHeap!=0 );
+ assert( hHeap!=INVALID_HANDLE_VALUE );
+#ifdef SQLITE_WIN32_MALLOC_VALIDATE
+ assert ( HeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
+#endif
+ assert( nBytes>=0 );
+ p = HeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
+ if( !p ){
+ sqlite3_log(SQLITE_NOMEM, "failed to HeapAlloc %u bytes (%d), heap=%p",
+ nBytes, GetLastError(), (void*)hHeap);
+ }
+ return p;
+}
+
+/*
+** Free memory.
+*/
+static void winMemFree(void *pPrior){
+ HANDLE hHeap;
+
+ winMemAssertMagic();
+ hHeap = winMemGetHeap();
+ assert( hHeap!=0 );
+ assert( hHeap!=INVALID_HANDLE_VALUE );
+#ifdef SQLITE_WIN32_MALLOC_VALIDATE
+ assert ( HeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) );
+#endif
+ if( !pPrior ) return; /* Passing NULL to HeapFree is undefined. */
+ if( !HeapFree(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ){
+ sqlite3_log(SQLITE_NOMEM, "failed to HeapFree block %p (%d), heap=%p",
+ pPrior, GetLastError(), (void*)hHeap);
+ }
+}
+
+/*
+** Change the size of an existing memory allocation
+*/
+static void *winMemRealloc(void *pPrior, int nBytes){
+ HANDLE hHeap;
+ void *p;
+
+ winMemAssertMagic();
+ hHeap = winMemGetHeap();
+ assert( hHeap!=0 );
+ assert( hHeap!=INVALID_HANDLE_VALUE );
+#ifdef SQLITE_WIN32_MALLOC_VALIDATE
+ assert ( HeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) );
+#endif
+ assert( nBytes>=0 );
+ if( !pPrior ){
+ p = HeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
+ }else{
+ p = HeapReAlloc(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, GetLastError(),
+ (void*)hHeap);
+ }
+ return p;
+}
+
+/*
+** Return the size of an outstanding allocation, in bytes.
+*/
+static int winMemSize(void *p){
+ HANDLE hHeap;
+ SIZE_T n;
+
+ winMemAssertMagic();
+ hHeap = winMemGetHeap();
+ assert( hHeap!=0 );
+ assert( hHeap!=INVALID_HANDLE_VALUE );
+#ifdef SQLITE_WIN32_MALLOC_VALIDATE
+ assert ( HeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
+#endif
+ if( !p ) return 0;
+ n = HeapSize(hHeap, SQLITE_WIN32_HEAP_FLAGS, p);
+ if( n==(SIZE_T)-1 ){
+ sqlite3_log(SQLITE_NOMEM, "failed to HeapSize block %p (%d), heap=%p",
+ p, GetLastError(), (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;
+}
+
+/*
+** Initialize this module.
+*/
+static int winMemInit(void *pAppData){
+ winMemData *pWinMemData = (winMemData *)pAppData;
+
+ if( !pWinMemData ) return SQLITE_ERROR;
+ assert( pWinMemData->magic==WINMEM_MAGIC );
+ if( !pWinMemData->hHeap ){
+ pWinMemData->hHeap = HeapCreate(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",
+ GetLastError(), SQLITE_WIN32_HEAP_FLAGS, SQLITE_WIN32_HEAP_INIT_SIZE,
+ SQLITE_WIN32_HEAP_MAX_SIZE);
+ return SQLITE_NOMEM;
+ }
+ pWinMemData->bOwned = TRUE;
+ }
+ assert( pWinMemData->hHeap!=0 );
+ assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE );
+#ifdef SQLITE_WIN32_MALLOC_VALIDATE
+ assert( HeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
+#endif
+ return SQLITE_OK;
+}
+
+/*
+** Deinitialize this module.
+*/
+static void winMemShutdown(void *pAppData){
+ winMemData *pWinMemData = (winMemData *)pAppData;
+
+ if( !pWinMemData ) return;
+ if( pWinMemData->hHeap ){
+ assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE );
+#ifdef SQLITE_WIN32_MALLOC_VALIDATE
+ assert( HeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
+#endif
+ if( pWinMemData->bOwned ){
+ if( !HeapDestroy(pWinMemData->hHeap) ){
+ sqlite3_log(SQLITE_NOMEM, "failed to HeapDestroy (%d), heap=%p",
+ GetLastError(), (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;
+}
+
+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.
*/
@@ -28281,7 +32026,7 @@ static char *unicodeToUtf8(const WCHAR *zWideFilename){
/*
** 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 malloc.
*/
@@ -28347,10 +32092,10 @@ SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zFilename){
}
/*
-** Convert UTF-8 to multibyte character string. Space to hold the
+** Convert UTF-8 to multibyte character string. Space to hold the
** returned string is obtained from malloc().
*/
-static char *utf8ToMbcs(const char *zFilename){
+SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){
char *zFilenameMbcs;
WCHAR *zTmpWide;
@@ -28363,6 +32108,157 @@ static char *utf8ToMbcs(const char *zFilename){
return zFilenameMbcs;
}
+
+/*
+** 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(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 error = GetLastError();
+ DWORD dwLen = 0;
+ char *zOut = 0;
+
+ if( isNT() ){
+ WCHAR *zTempWide = NULL;
+ dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ error,
+ 0,
+ (LPWSTR) &zTempWide,
+ 0,
+ 0);
+ if( dwLen > 0 ){
+ /* allocate a buffer and convert to UTF8 */
+ zOut = unicodeToUtf8(zTempWide);
+ /* free the system buffer allocated by FormatMessage */
+ LocalFree(zTempWide);
+ }
+/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
+** Since the ASCII version of these Windows API do not exist for WINCE,
+** it's important to not reference them for WINCE builds.
+*/
+#if SQLITE_OS_WINCE==0
+ }else{
+ char *zTemp = NULL;
+ dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ error,
+ 0,
+ (LPSTR) &zTemp,
+ 0,
+ 0);
+ if( dwLen > 0 ){
+ /* allocate a buffer and convert to UTF8 */
+ zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
+ /* free the system buffer allocated by FormatMessage */
+ LocalFree(zTemp);
+ }
+#endif
+ }
+ if( 0 == dwLen ){
+ sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error);
+ }else{
+ /* copy a maximum of nBuf chars to output buffer */
+ sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
+ /* free the UTF8 buffer */
+ 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 the associated file-system path, if any.
+*/
+#define winLogError(a,b,c) winLogErrorAtLine(a,b,c,__LINE__)
+static int winLogErrorAtLine(
+ 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 zMsg[500]; /* Human readable error text */
+ int i; /* Loop counter */
+ DWORD iErrno = GetLastError(); /* Error code */
+
+ zMsg[0] = 0;
+ getLastErrorMsg(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: (%d) %s(%s) - %s",
+ iLine, iErrno, zFunc, zPath, zMsg
+ );
+
+ return errcode;
+}
+
+/*
+** 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
+#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;
+
+/*
+** 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 e;
+ if( *pnRetry>=win32IoerrRetry ){
+ return 0;
+ }
+ e = GetLastError();
+ if( e==ERROR_ACCESS_DENIED ||
+ e==ERROR_LOCK_VIOLATION ||
+ e==ERROR_SHARING_VIOLATION ){
+ Sleep(win32IoerrRetryDelay*(1+*pnRetry));
+ ++*pnRetry;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+** 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
+ );
+ }
+}
+
#if SQLITE_OS_WINCE
/*************************************************************************
** This section contains code for WinCE only.
@@ -28371,6 +32267,7 @@ static char *utf8ToMbcs(const char *zFilename){
** WindowsCE does not have a localtime() function. So create a
** substitute.
*/
+/* #include */
struct tm *__cdecl localtime(const time_t *t)
{
static struct tm y;
@@ -28439,23 +32336,24 @@ static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
pFile->hMutex = CreateMutexW(NULL, FALSE, zName);
if (!pFile->hMutex){
pFile->lastErrno = GetLastError();
+ winLogError(SQLITE_ERROR, "winceCreateLock1", zFilename);
free(zName);
return FALSE;
}
/* Acquire the mutex before continuing */
winceMutexAcquire(pFile->hMutex);
-
- /* Since the names of named mutexes, semaphores, file mappings etc are
+
+ /* 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.
*/
CharUpperW(zName);
pFile->hShared = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
PAGE_READWRITE, 0, sizeof(winceLock),
- zName);
+ zName);
- /* Set a flag that indicates we're the first to create the memory so it
+ /* Set a flag that indicates we're the first to create the memory so it
** must be zero-initialized */
if (GetLastError() == ERROR_ALREADY_EXISTS){
bInit = FALSE;
@@ -28465,11 +32363,12 @@ static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
/* If we succeeded in making the shared memory handle, map it. */
if (pFile->hShared){
- pFile->shared = (winceLock*)MapViewOfFile(pFile->hShared,
+ pFile->shared = (winceLock*)MapViewOfFile(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 = GetLastError();
+ winLogError(SQLITE_ERROR, "winceCreateLock2", zFilename);
CloseHandle(pFile->hShared);
pFile->hShared = NULL;
}
@@ -28482,7 +32381,7 @@ static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
pFile->hMutex = NULL;
return FALSE;
}
-
+
/* Initialize the shared memory if we're supposed to */
if (bInit) {
ZeroMemory(pFile->shared, sizeof(winceLock));
@@ -28520,13 +32419,13 @@ static void winceDestroyLock(winFile *pFile){
CloseHandle(pFile->hShared);
/* Done with the mutex */
- winceMutexRelease(pFile->hMutex);
+ winceMutexRelease(pFile->hMutex);
CloseHandle(pFile->hMutex);
pFile->hMutex = NULL;
}
}
-/*
+/*
** An implementation of the LockFile() API of windows for wince
*/
static BOOL winceLockFile(
@@ -28685,6 +32584,43 @@ static BOOL winceLockFileEx(
** 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){
+ LONG upperBits; /* Most sig. 32 bits of new offset */
+ LONG lowerBits; /* Least sig. 32 bits of new offset */
+ DWORD dwRet; /* Value returned by SetFilePointer() */
+
+ 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 occured, it is also necessary to call
+ ** GetLastError().
+ */
+ dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
+ if( (dwRet==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR) ){
+ pFile->lastErrno = GetLastError();
+ winLogError(SQLITE_IOERR_SEEK, "seekWinFile", pFile->zPath);
+ return 1;
+ }
+
+ return 0;
+}
+
/*
** Close a file.
**
@@ -28701,9 +32637,11 @@ static int winClose(sqlite3_file *id){
winFile *pFile = (winFile*)id;
assert( id!=0 );
- OSTRACE2("CLOSE %d\n", pFile->h);
+ assert( pFile->pShm==0 );
+ OSTRACE(("CLOSE %d\n", pFile->h));
do{
rc = CloseHandle(pFile->h);
+ /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */
}while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (Sleep(100), 1) );
#if SQLITE_OS_WINCE
#define WINCE_DELETION_ATTEMPTS 3
@@ -28712,7 +32650,7 @@ static int winClose(sqlite3_file *id){
int cnt = 0;
while(
DeleteFileW(pFile->zDeleteOnClose)==0
- && GetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff
+ && GetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff
&& cnt++ < WINCE_DELETION_ATTEMPTS
){
Sleep(100); /* Wait a little before trying again */
@@ -28720,17 +32658,12 @@ static int winClose(sqlite3_file *id){
free(pFile->zDeleteOnClose);
}
#endif
+ OSTRACE(("CLOSE %d %s\n", pFile->h, rc ? "ok" : "failed"));
OpenCounter(-1);
- return rc ? SQLITE_OK : SQLITE_IOERR;
+ return rc ? SQLITE_OK
+ : winLogError(SQLITE_IOERR_CLOSE, "winClose", pFile->zPath);
}
-/*
-** Some microsoft compilers lack this definition.
-*/
-#ifndef INVALID_SET_FILE_POINTER
-# define INVALID_SET_FILE_POINTER ((DWORD)-1)
-#endif
-
/*
** Read data from a file into a buffer. Return SQLITE_OK if all
** bytes were read successfully and SQLITE_IOERR if anything goes
@@ -28742,32 +32675,30 @@ static int winRead(
int amt, /* Number of bytes to read */
sqlite3_int64 offset /* Begin reading at this offset */
){
- LONG upperBits = (LONG)((offset>>32) & 0x7fffffff);
- LONG lowerBits = (LONG)(offset & 0xffffffff);
- DWORD rc;
- winFile *pFile = (winFile*)id;
- DWORD error;
- DWORD got;
+ winFile *pFile = (winFile*)id; /* file handle */
+ DWORD nRead; /* Number of bytes actually read from file */
+ int nRetry = 0; /* Number of retrys */
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_READ);
- OSTRACE3("READ %d lock=%d\n", pFile->h, pFile->locktype);
- rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
- if( rc==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
- pFile->lastErrno = error;
+ OSTRACE(("READ %d lock=%d\n", pFile->h, pFile->locktype));
+
+ if( seekWinFile(pFile, offset) ){
return SQLITE_FULL;
}
- if( !ReadFile(pFile->h, pBuf, amt, &got, 0) ){
+ while( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
+ if( retryIoerr(&nRetry) ) continue;
pFile->lastErrno = GetLastError();
- return SQLITE_IOERR_READ;
+ return winLogError(SQLITE_IOERR_READ, "winRead", pFile->zPath);
}
- if( got==(DWORD)amt ){
- return SQLITE_OK;
- }else{
+ logIoerr(nRetry);
+ if( nRead<(DWORD)amt ){
/* Unread parts of the buffer must be zero-filled */
- memset(&((char*)pBuf)[got], 0, amt-got);
+ memset(&((char*)pBuf)[nRead], 0, amt-nRead);
return SQLITE_IOERR_SHORT_READ;
}
+
+ return SQLITE_OK;
}
/*
@@ -28775,39 +32706,51 @@ static int winRead(
** 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 */
+ 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 */
){
- LONG upperBits = (LONG)((offset>>32) & 0x7fffffff);
- LONG lowerBits = (LONG)(offset & 0xffffffff);
- DWORD rc;
- winFile *pFile = (winFile*)id;
- DWORD error;
- DWORD wrote = 0;
+ int rc; /* True if error has occured, else false */
+ winFile *pFile = (winFile*)id; /* File handle */
+ int nRetry = 0; /* Number of retries */
- assert( id!=0 );
+ assert( amt>0 );
+ assert( pFile );
SimulateIOError(return SQLITE_IOERR_WRITE);
SimulateDiskfullError(return SQLITE_FULL);
- OSTRACE3("WRITE %d lock=%d\n", pFile->h, pFile->locktype);
- rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
- if( rc==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
- pFile->lastErrno = error;
- return SQLITE_FULL;
+
+ OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype));
+
+ rc = seekWinFile(pFile, offset);
+ if( rc==0 ){
+ 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 */
+
+ while( nRem>0 ){
+ if( !WriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
+ if( retryIoerr(&nRetry) ) continue;
+ break;
+ }
+ if( nWrite<=0 ) break;
+ aRem += nWrite;
+ nRem -= nWrite;
+ }
+ if( nRem>0 ){
+ pFile->lastErrno = GetLastError();
+ rc = 1;
+ }
}
- assert( amt>0 );
- while(
- amt>0
- && (rc = WriteFile(pFile->h, pBuf, amt, &wrote, 0))!=0
- && wrote>0
- ){
- amt -= wrote;
- pBuf = &((char*)pBuf)[wrote];
- }
- if( !rc || amt>(int)wrote ){
- pFile->lastErrno = GetLastError();
- return SQLITE_FULL;
+
+ if( rc ){
+ if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL )
+ || ( pFile->lastErrno==ERROR_DISK_FULL )){
+ return SQLITE_FULL;
+ }
+ return winLogError(SQLITE_IOERR_WRITE, "winWrite", pFile->zPath);
+ }else{
+ logIoerr(nRetry);
}
return SQLITE_OK;
}
@@ -28816,26 +32759,33 @@ static int winWrite(
** Truncate an open file to a specified size
*/
static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
- LONG upperBits = (LONG)((nByte>>32) & 0x7fffffff);
- LONG lowerBits = (LONG)(nByte & 0xffffffff);
- DWORD rc;
- winFile *pFile = (winFile*)id;
- DWORD error;
+ winFile *pFile = (winFile*)id; /* File handle object */
+ int rc = SQLITE_OK; /* Return code for this function */
- assert( id!=0 );
- OSTRACE3("TRUNCATE %d %lld\n", pFile->h, nByte);
+ assert( pFile );
+
+ OSTRACE(("TRUNCATE %d %lld\n", pFile->h, nByte));
SimulateIOError(return SQLITE_IOERR_TRUNCATE);
- rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
- if( rc==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
- pFile->lastErrno = error;
- 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).
+ */
+ if( pFile->szChunk>0 ){
+ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
}
- /* SetEndOfFile will fail if nByte is negative */
- if( !SetEndOfFile(pFile->h) ){
+
+ /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
+ if( seekWinFile(pFile, nByte) ){
+ rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate1", pFile->zPath);
+ }else if( 0==SetEndOfFile(pFile->h) ){
pFile->lastErrno = GetLastError();
- return SQLITE_IOERR_TRUNCATE;
+ rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate2", pFile->zPath);
}
- return SQLITE_OK;
+
+ OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok"));
+ return rc;
}
#ifdef SQLITE_TEST
@@ -28852,32 +32802,57 @@ SQLITE_API int sqlite3_fullsync_count = 0;
*/
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;
-
- assert( id!=0 );
- OSTRACE3("SYNC %d lock=%d\n", pFile->h, pFile->locktype);
#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
+ );
+
+ 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 );
+
#ifndef SQLITE_TEST
UNUSED_PARAMETER(flags);
#else
- if( flags & SQLITE_SYNC_FULL ){
+ if( (flags&0x0F)==SQLITE_SYNC_FULL ){
sqlite3_fullsync_count++;
}
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;
+ return SQLITE_OK;
#else
- if( FlushFileBuffers(pFile->h) ){
+ rc = FlushFileBuffers(pFile->h);
+ SimulateIOError( rc=FALSE );
+ if( rc ){
return SQLITE_OK;
}else{
pFile->lastErrno = GetLastError();
- return SQLITE_IOERR;
+ return winLogError(SQLITE_IOERR_FSYNC, "winSync", pFile->zPath);
}
#endif
}
@@ -28898,7 +32873,7 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
&& ((error = GetLastError()) != NO_ERROR) )
{
pFile->lastErrno = error;
- return SQLITE_IOERR_FSTAT;
+ return winLogError(SQLITE_IOERR_FSTAT, "winFileSize", pFile->zPath);
}
*pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits;
return SQLITE_OK;
@@ -28925,7 +32900,7 @@ static int getReadLock(winFile *pFile){
ovlp.hEvent = 0;
res = LockFileEx(pFile->h, LOCKFILE_FAIL_IMMEDIATELY,
0, SHARED_SIZE, 0, &ovlp);
-/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
+/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
*/
#if SQLITE_OS_WINCE==0
}else{
@@ -28937,6 +32912,7 @@ static int getReadLock(winFile *pFile){
}
if( res == 0 ){
pFile->lastErrno = GetLastError();
+ /* No need to log a failure to lock */
}
return res;
}
@@ -28948,15 +32924,16 @@ static int unlockReadLock(winFile *pFile){
int res;
if( isNT() ){
res = UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
-/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
+/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
*/
#if SQLITE_OS_WINCE==0
}else{
res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0);
#endif
}
- if( res == 0 ){
+ if( res==0 && GetLastError()!=ERROR_NOT_LOCKED ){
pFile->lastErrno = GetLastError();
+ winLogError(SQLITE_IOERR_UNLOCK, "unlockReadLock", pFile->zPath);
}
return res;
}
@@ -28996,8 +32973,8 @@ static int winLock(sqlite3_file *id, int locktype){
DWORD error = NO_ERROR;
assert( id!=0 );
- OSTRACE5("LOCK %d %d was %d(%d)\n",
- pFile->h, locktype, pFile->locktype, pFile->sharedLockByte);
+ OSTRACE(("LOCK %d %d was %d(%d)\n",
+ pFile->h, locktype, pFile->locktype, pFile->sharedLockByte));
/* 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
@@ -29027,7 +33004,7 @@ static int winLock(sqlite3_file *id, int locktype){
/* Try 3 times to get the pending lock. The pending lock might be
** held by another reader process who will release it momentarily.
*/
- OSTRACE2("could not get a PENDING lock. cnt=%d\n", cnt);
+ OSTRACE(("could not get a PENDING lock. cnt=%d\n", cnt));
Sleep(1);
}
gotPendingLock = res;
@@ -29072,13 +33049,13 @@ static int winLock(sqlite3_file *id, int locktype){
if( locktype==EXCLUSIVE_LOCK && res ){
assert( pFile->locktype>=SHARED_LOCK );
res = unlockReadLock(pFile);
- OSTRACE2("unreadlock = %d\n", res);
+ OSTRACE(("unreadlock = %d\n", res));
res = LockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
if( res ){
newLocktype = EXCLUSIVE_LOCK;
}else{
error = GetLastError();
- OSTRACE2("error-code = %d\n", error);
+ OSTRACE(("error-code = %d\n", error));
getReadLock(pFile);
}
}
@@ -29096,8 +33073,8 @@ static int winLock(sqlite3_file *id, int locktype){
if( res ){
rc = SQLITE_OK;
}else{
- OSTRACE4("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
- locktype, newLocktype);
+ OSTRACE(("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
+ locktype, newLocktype));
pFile->lastErrno = error;
rc = SQLITE_BUSY;
}
@@ -29114,17 +33091,19 @@ static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
int rc;
winFile *pFile = (winFile*)id;
+ SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
+
assert( id!=0 );
if( pFile->locktype>=RESERVED_LOCK ){
rc = 1;
- OSTRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc);
+ OSTRACE(("TEST WR-LOCK %d %d (local)\n", pFile->h, rc));
}else{
rc = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
if( rc ){
UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
}
rc = !rc;
- OSTRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc);
+ OSTRACE(("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc));
}
*pResOut = rc;
return SQLITE_OK;
@@ -29147,15 +33126,15 @@ static int winUnlock(sqlite3_file *id, int locktype){
int rc = SQLITE_OK;
assert( pFile!=0 );
assert( locktype<=SHARED_LOCK );
- OSTRACE5("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
- pFile->locktype, pFile->sharedLockByte);
+ OSTRACE(("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
+ pFile->locktype, pFile->sharedLockByte));
type = pFile->locktype;
if( type>=EXCLUSIVE_LOCK ){
UnlockFile(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 = SQLITE_IOERR_UNLOCK;
+ rc = winLogError(SQLITE_IOERR_UNLOCK, "winUnlock", pFile->zPath);
}
}
if( type>=RESERVED_LOCK ){
@@ -29175,17 +33154,64 @@ static int winUnlock(sqlite3_file *id, int locktype){
** Control and query of the open file handle.
*/
static int winFileControl(sqlite3_file *id, int op, void *pArg){
+ winFile *pFile = (winFile*)id;
switch( op ){
case SQLITE_FCNTL_LOCKSTATE: {
- *(int*)pArg = ((winFile*)id)->locktype;
+ *(int*)pArg = pFile->locktype;
return SQLITE_OK;
}
case SQLITE_LAST_ERRNO: {
- *(int*)pArg = (int)((winFile*)id)->lastErrno;
+ *(int*)pArg = (int)pFile->lastErrno;
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_CHUNK_SIZE: {
+ pFile->szChunk = *(int *)pArg;
+ 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);
+ }
+ }
+ return rc;
+ }
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_PERSIST_WAL: {
+ int bPersist = *(int*)pArg;
+ if( bPersist<0 ){
+ *(int*)pArg = pFile->bPersistWal;
+ }else{
+ pFile->bPersistWal = bPersist!=0;
+ }
+ return SQLITE_OK;
+ }
+ case SQLITE_FCNTL_SYNC_OMITTED: {
+ 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;
+ }
return SQLITE_OK;
}
}
- return SQLITE_ERROR;
+ return SQLITE_NOTFOUND;
}
/*
@@ -29208,34 +33234,674 @@ static int winSectorSize(sqlite3_file *id){
*/
static int winDeviceCharacteristics(sqlite3_file *id){
UNUSED_PARAMETER(id);
- return 0;
+ return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
}
+#ifndef SQLITE_OMIT_WAL
+
+/*
+** 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;
+
+/*
+** 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
+
+/*
+** 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.
+**
+*/
+struct winShmNode {
+ sqlite3_mutex *mutex; /* Mutex to access this object */
+ char *zFilename; /* Name of the file */
+ winFile hFile; /* File handle from winOpen */
+
+ int szRegion; /* Size of shared-memory regions */
+ int nRegion; /* Size of array apRegion */
+ struct ShmRegion {
+ HANDLE hMap; /* File handle from CreateFileMapping */
+ void *pMap;
+ } *aRegion;
+ DWORD lastErrno; /* The Windows errno from the last I/O error */
+
+ int nRef; /* Number of winShm objects pointing to this */
+ winShm *pFirst; /* All winShm objects pointing to this */
+ winShmNode *pNext; /* Next in list of all winShmNode objects */
+#ifdef SQLITE_DEBUG
+ u8 nextShmId; /* Next available winShm.id value */
+#endif
+};
+
+/*
+** 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
+};
+
+/*
+** Constants used for locking
+*/
+#define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
+#define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
+
+/*
+** 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 */
+){
+ OVERLAPPED ovlp;
+ DWORD dwFlags;
+ 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 );
+
+ /* Initialize the locking parameters */
+ dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
+ if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
+
+ memset(&ovlp, 0, sizeof(OVERLAPPED));
+ ovlp.Offset = ofst;
+
+ /* Release/Acquire the system-level lock */
+ if( lockType==_SHM_UNLCK ){
+ rc = UnlockFileEx(pFile->hFile.h, 0, nByte, 0, &ovlp);
+ }else{
+ rc = LockFileEx(pFile->hFile.h, dwFlags, 0, nByte, 0, &ovlp);
+ }
+
+ if( rc!= 0 ){
+ rc = SQLITE_OK;
+ }else{
+ pFile->lastErrno = GetLastError();
+ 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));
+
+ 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);
+
+/*
+** Purge the winShmNodeList list of all entries with winShmNode.nRef==0.
+**
+** This is not a VFS shared-memory method; it is a utility function called
+** by VFS shared-memory methods.
+*/
+static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
+ winShmNode **pp;
+ winShmNode *p;
+ BOOL bRc;
+ assert( winShmMutexHeld() );
+ pp = &winShmNodeList;
+ while( (p = *pp)!=0 ){
+ if( p->nRef==0 ){
+ int i;
+ if( p->mutex ) sqlite3_mutex_free(p->mutex);
+ for(i=0; inRegion; i++){
+ bRc = UnmapViewOfFile(p->aRegion[i].pMap);
+ OSTRACE(("SHM-PURGE pid-%d unmap region=%d %s\n",
+ (int)GetCurrentProcessId(), i,
+ bRc ? "ok" : "failed"));
+ bRc = CloseHandle(p->aRegion[i].hMap);
+ OSTRACE(("SHM-PURGE pid-%d close region=%d %s\n",
+ (int)GetCurrentProcessId(), i,
+ bRc ? "ok" : "failed"));
+ }
+ if( p->hFile.h != INVALID_HANDLE_VALUE ){
+ SimulateIOErrorBenign(1);
+ winClose((sqlite3_file *)&p->hFile);
+ SimulateIOErrorBenign(0);
+ }
+ if( deleteFlag ){
+ SimulateIOErrorBenign(1);
+ winDelete(pVfs, p->zFilename, 0);
+ SimulateIOErrorBenign(0);
+ }
+ *pp = p->pNext;
+ sqlite3_free(p->aRegion);
+ sqlite3_free(p);
+ }else{
+ pp = &p->pNext;
+ }
+ }
+}
+
+/*
+** 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 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 */
+
+ assert( pDbFd->pShm==0 ); /* Not previously opened */
+
+ /* Allocate space for the new sqlite3_shm object. Also speculatively
+ ** allocate space for a new winShmNode and filename.
+ */
+ p = sqlite3_malloc( sizeof(*p) );
+ if( p==0 ) return SQLITE_NOMEM;
+ memset(p, 0, sizeof(*p));
+ nName = sqlite3Strlen30(pDbFd->zPath);
+ pNew = sqlite3_malloc( sizeof(*pShmNode) + nName + 15 );
+ if( pNew==0 ){
+ sqlite3_free(p);
+ return SQLITE_NOMEM;
+ }
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->zFilename = (char*)&pNew[1];
+ sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
+ sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename);
+
+ /* Look to see if there is an existing winShmNode that can be used.
+ ** If no matching winShmNode currently exists, create a new one.
+ */
+ winShmEnterMutex();
+ for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){
+ /* TBD need to come up with better match here. Perhaps
+ ** use FILE_ID_BOTH_DIR_INFO Structure.
+ */
+ if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break;
+ }
+ 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_NOMEM;
+ goto shm_open_err;
+ }
+
+ rc = winOpen(pDbFd->pVfs,
+ pShmNode->zFilename, /* Name of the file (UTF-8) */
+ (sqlite3_file*)&pShmNode->hFile, /* File handle here */
+ SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, /* Mode flags */
+ 0);
+ if( SQLITE_OK!=rc ){
+ rc = SQLITE_CANTOPEN_BKPT;
+ goto shm_open_err;
+ }
+
+ /* Check to see if another process is holding the dead-man switch.
+ ** If not, truncate the file to zero length.
+ */
+ if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
+ rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
+ if( rc!=SQLITE_OK ){
+ rc = winLogError(SQLITE_IOERR_SHMOPEN, "winOpenShm", pDbFd->zPath);
+ }
+ }
+ if( rc==SQLITE_OK ){
+ winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
+ rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1);
+ }
+ if( rc ) goto shm_open_err;
+ }
+
+ /* Make the new connection a child of the winShmNode */
+ p->pShmNode = pShmNode;
+#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;
+}
+
+/*
+** Close a connection to shared-memory. Delete the underlying
+** storage if deleteFlag is true.
+*/
+static int winShmUnmap(
+ sqlite3_file *fd, /* Database holding shared memory */
+ int deleteFlag /* Delete after closing if true */
+){
+ winFile *pDbFd; /* Database holding shared-memory */
+ winShm *p; /* The connection to be closed */
+ winShmNode *pShmNode; /* The underlying shared-memory file */
+ winShm **pp; /* For looping over sibling connections */
+
+ pDbFd = (winFile*)fd;
+ p = pDbFd->pShm;
+ if( p==0 ) return SQLITE_OK;
+ pShmNode = p->pShmNode;
+
+ /* 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 */
+ winShmEnterMutex();
+ assert( pShmNode->nRef>0 );
+ pShmNode->nRef--;
+ if( pShmNode->nRef==0 ){
+ winShmPurge(pDbFd->pVfs, deleteFlag);
+ }
+ winShmLeaveMutex();
+
+ return SQLITE_OK;
+}
+
+/*
+** Change the lock state for a shared-memory segment.
+*/
+static int winShmLock(
+ sqlite3_file *fd, /* Database file holding the shared memory */
+ int ofst, /* First lock to acquire or release */
+ int n, /* Number of locks to acquire or release */
+ int flags /* What to do with the lock */
+){
+ winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */
+ winShm *p = pDbFd->pShm; /* The shared memory being locked */
+ winShm *pX; /* For looping over all siblings */
+ winShmNode *pShmNode = p->pShmNode;
+ int rc = SQLITE_OK; /* Result code */
+ u16 mask; /* Mask of locks to take or release */
+
+ assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
+ assert( n>=1 );
+ assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
+ || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
+ || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
+ || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
+ assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
+
+ mask = (u16)((1U<<(ofst+n)) - (1U<1 || mask==(1<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 = 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;
+ }
+ }
+ }
+ sqlite3_mutex_leave(pShmNode->mutex);
+ OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x %s\n",
+ p->id, (int)GetCurrentProcessId(), p->sharedMask, p->exclMask,
+ rc ? "failed" : "ok"));
+ return rc;
+}
+
+/*
+** 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 winShmBarrier(
+ sqlite3_file *fd /* Database holding the shared memory */
+){
+ UNUSED_PARAMETER(fd);
+ /* MemoryBarrier(); // does not work -- do not know why not */
+ winShmEnterMutex();
+ winShmLeaveMutex();
+}
+
+/*
+** This function is called to obtain a pointer to region iRegion of the
+** shared-memory associated with the database file fd. Shared-memory regions
+** are numbered starting from zero. Each shared-memory region is szRegion
+** bytes in size.
+**
+** If an error occurs, an error code is returned and *pp is set to NULL.
+**
+** Otherwise, if the isWrite parameter is 0 and the requested shared-memory
+** region has not been allocated (by any client, including one running in a
+** separate process), then *pp is set to NULL and SQLITE_OK returned. If
+** isWrite is non-zero and the requested shared-memory region has not yet
+** been allocated, it is allocated by this function.
+**
+** If the shared-memory region has already been allocated or is allocated by
+** this call as described above, then it is mapped into this processes
+** address space (if it is not already), *pp is set to point to the mapped
+** memory and SQLITE_OK returned.
+*/
+static int winShmMap(
+ sqlite3_file *fd, /* Handle open on database file */
+ int iRegion, /* Region to retrieve */
+ int szRegion, /* Size of regions */
+ int isWrite, /* True to extend file if necessary */
+ void volatile **pp /* OUT: Mapped memory */
+){
+ winFile *pDbFd = (winFile*)fd;
+ winShm *p = pDbFd->pShm;
+ winShmNode *pShmNode;
+ int rc = SQLITE_OK;
+
+ if( !p ){
+ rc = winOpenSharedMemory(pDbFd);
+ if( rc!=SQLITE_OK ) return rc;
+ p = pDbFd->pShm;
+ }
+ pShmNode = p->pShmNode;
+
+ sqlite3_mutex_enter(pShmNode->mutex);
+ assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
+
+ if( pShmNode->nRegion<=iRegion ){
+ struct ShmRegion *apNew; /* New aRegion[] array */
+ int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
+ sqlite3_int64 sz; /* Current size of wal-index file */
+
+ pShmNode->szRegion = szRegion;
+
+ /* The requested region is not mapped into this processes address space.
+ ** Check to see if it has been allocated (i.e. if the wal-index file is
+ ** large enough to contain the requested region).
+ */
+ rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz);
+ if( rc!=SQLITE_OK ){
+ rc = winLogError(SQLITE_IOERR_SHMSIZE, "winShmMap1", pDbFd->zPath);
+ goto shmpage_out;
+ }
+
+ if( szhFile, nByte);
+ if( rc!=SQLITE_OK ){
+ rc = winLogError(SQLITE_IOERR_SHMSIZE, "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; /* file-mapping handle */
+ void *pMap = 0; /* Mapped memory region */
+
+ hMap = CreateFileMapping(pShmNode->hFile.h,
+ NULL, PAGE_READWRITE, 0, nByte, NULL
+ );
+ OSTRACE(("SHM-MAP pid-%d create region=%d nbyte=%d %s\n",
+ (int)GetCurrentProcessId(), pShmNode->nRegion, nByte,
+ hMap ? "ok" : "failed"));
+ if( hMap ){
+ int iOffset = pShmNode->nRegion*szRegion;
+ int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
+ pMap = MapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
+ 0, iOffset - iOffsetShift, szRegion + iOffsetShift
+ );
+ OSTRACE(("SHM-MAP pid-%d map region=%d offset=%d size=%d %s\n",
+ (int)GetCurrentProcessId(), pShmNode->nRegion, iOffset, szRegion,
+ pMap ? "ok" : "failed"));
+ }
+ if( !pMap ){
+ pShmNode->lastErrno = GetLastError();
+ rc = winLogError(SQLITE_IOERR_SHMMAP, "winShmMap3", pDbFd->zPath);
+ if( hMap ) CloseHandle(hMap);
+ goto shmpage_out;
+ }
+
+ pShmNode->aRegion[pShmNode->nRegion].pMap = pMap;
+ pShmNode->aRegion[pShmNode->nRegion].hMap = hMap;
+ pShmNode->nRegion++;
+ }
+ }
+
+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;
+ }
+ sqlite3_mutex_leave(pShmNode->mutex);
+ return rc;
+}
+
+#else
+# define winShmMap 0
+# define winShmLock 0
+# define winShmBarrier 0
+# define winShmUnmap 0
+#endif /* #ifndef SQLITE_OMIT_WAL */
+
+/*
+** 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.
*/
static const sqlite3_io_methods winIoMethod = {
- 1, /* iVersion */
- winClose,
- winRead,
- winWrite,
- winTruncate,
- winSync,
- winFileSize,
- winLock,
- winUnlock,
- winCheckReservedLock,
- winFileControl,
- winSectorSize,
- winDeviceCharacteristics
+ 2, /* 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 */
};
-/***************************************************************************
-** Here ends the I/O methods that form the sqlite3_io_methods object.
+/****************************************************************************
+**************************** sqlite3_vfs methods ****************************
**
-** The next block of code implements the VFS methods.
-****************************************************************************/
+** This division contains the implementation of methods on the
+** sqlite3_vfs object.
+*/
/*
** Convert a UTF-8 filename into whatever form the underlying
@@ -29247,11 +33913,11 @@ static void *convertUtf8Filename(const char *zFilename){
void *zConverted = 0;
if( isNT() ){
zConverted = utf8ToUnicode(zFilename);
-/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
+/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
*/
#if SQLITE_OS_WINCE==0
}else{
- zConverted = utf8ToMbcs(zFilename);
+ zConverted = sqlite3_win32_utf8_to_mbcs(zFilename);
#endif
}
/* caller will handle out of memory */
@@ -29269,6 +33935,13 @@ static int getTempname(int nBuf, char *zBuf){
"0123456789";
size_t i, j;
char zTempPath[MAX_PATH+1];
+
+ /* 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 );
+
if( sqlite3_temp_directory ){
sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory);
}else if( isNT() ){
@@ -29282,7 +33955,7 @@ static int getTempname(int nBuf, char *zBuf){
}else{
return SQLITE_NOMEM;
}
-/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
+/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
** Since the ASCII version of these Windows API do not exist for WINCE,
** it's important to not reference them for WINCE builds.
*/
@@ -29300,80 +33973,28 @@ static int getTempname(int nBuf, char *zBuf){
}
#endif
}
+
+ /* Check that the output buffer is large enough for the temporary file
+ ** name. If it is not, return SQLITE_ERROR.
+ */
+ if( (sqlite3Strlen30(zTempPath) + sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX) + 17) >= nBuf ){
+ return SQLITE_ERROR;
+ }
+
for(i=sqlite3Strlen30(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
zTempPath[i] = 0;
- sqlite3_snprintf(nBuf-30, zBuf,
+
+ sqlite3_snprintf(nBuf-17, zBuf,
"%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath);
j = sqlite3Strlen30(zBuf);
- sqlite3_randomness(20, &zBuf[j]);
- for(i=0; i<20; i++, j++){
+ 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;
- OSTRACE2("TEMP FILENAME: %s\n", zBuf);
- return SQLITE_OK;
-}
-/*
-** 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(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 error = GetLastError();
- DWORD dwLen = 0;
- char *zOut = 0;
-
- if( isNT() ){
- WCHAR *zTempWide = NULL;
- dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- error,
- 0,
- (LPWSTR) &zTempWide,
- 0,
- 0);
- if( dwLen > 0 ){
- /* allocate a buffer and convert to UTF8 */
- zOut = unicodeToUtf8(zTempWide);
- /* free the system buffer allocated by FormatMessage */
- LocalFree(zTempWide);
- }
-/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
-** Since the ASCII version of these Windows API do not exist for WINCE,
-** it's important to not reference them for WINCE builds.
-*/
-#if SQLITE_OS_WINCE==0
- }else{
- char *zTemp = NULL;
- dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- error,
- 0,
- (LPSTR) &zTemp,
- 0,
- 0);
- if( dwLen > 0 ){
- /* allocate a buffer and convert to UTF8 */
- zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
- /* free the system buffer allocated by FormatMessage */
- LocalFree(zTemp);
- }
-#endif
- }
- if( 0 == dwLen ){
- sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error);
- }else{
- /* copy a maximum of nBuf chars to output buffer */
- sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
- /* free the UTF8 buffer */
- free(zOut);
- }
- return 0;
+ OSTRACE(("TEMP FILENAME: %s\n", zBuf));
+ return SQLITE_OK;
}
/*
@@ -29395,18 +34016,73 @@ static int winOpen(
int isTemp = 0;
#endif
winFile *pFile = (winFile*)id;
- void *zConverted; /* Filename in OS encoding */
- const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */
- char zTmpname[MAX_PATH+1]; /* Buffer used to create temp filename */
+ 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+1]; /* 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);
+#ifndef NDEBUG
+ int isReadonly = (flags & SQLITE_OPEN_READONLY);
+#endif
+ 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
+
+ /* Check the following statements are true:
+ **
+ ** (a) Exactly one of the READWRITE and READONLY flags must be set, and
+ ** (b) if CREATE is set, then READWRITE must also be set, and
+ ** (c) if EXCLUSIVE is set, then CREATE must also be set.
+ ** (d) if DELETEONCLOSE is set, then CREATE must also be set.
+ */
+ assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
+ assert(isCreate==0 || isReadWrite);
+ assert(isExclusive==0 || isCreate);
+ assert(isDelete==0 || isCreate);
+
+ /* The main DB, main journal, WAL file and master journal are never
+ ** automatically deleted. Nor are they ever temporary files. */
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
+
+ /* Assert that the upper layer has set one of the "file-type" flags. */
+ assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
+ || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
+ || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
+ || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
+ );
assert( id!=0 );
UNUSED_PARAMETER(pVfs);
- /* If the second argument to this function is NULL, generate a
- ** temporary file name to use
+ pFile->h = INVALID_HANDLE_VALUE;
+
+ /* If the second argument to this function is NULL, generate a
+ ** temporary file name to use
*/
if( !zUtf8Name ){
- int rc = getTempname(MAX_PATH+1, zTmpname);
+ assert(isDelete && !isOpenJournal);
+ rc = getTempname(MAX_PATH+1, zTmpname);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -29419,29 +34095,31 @@ static int winOpen(
return SQLITE_NOMEM;
}
- if( flags & SQLITE_OPEN_READWRITE ){
+ if( isReadWrite ){
dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
}else{
dwDesiredAccess = GENERIC_READ;
}
- /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is
- ** created. SQLite doesn't use it to indicate "exclusive access"
+
+ /* 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.
*/
- assert(!(flags & SQLITE_OPEN_EXCLUSIVE) || (flags & SQLITE_OPEN_CREATE));
- if( flags & SQLITE_OPEN_EXCLUSIVE ){
+ if( isExclusive ){
/* Creates a new file, only if it does not already exist. */
/* If the file exists, it fails. */
dwCreationDisposition = CREATE_NEW;
- }else if( flags & SQLITE_OPEN_CREATE ){
+ }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;
}
+
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
- if( flags & SQLITE_OPEN_DELETEONCLOSE ){
+
+ if( isDelete ){
#if SQLITE_OS_WINCE
dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN;
isTemp = 1;
@@ -29458,55 +34136,68 @@ static int winOpen(
#if SQLITE_OS_WINCE
dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
#endif
+
if( isNT() ){
- h = CreateFileW((WCHAR*)zConverted,
- dwDesiredAccess,
- dwShareMode,
- NULL,
- dwCreationDisposition,
- dwFlagsAndAttributes,
- NULL
- );
-/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
+ while( (h = CreateFileW((WCHAR*)zConverted,
+ dwDesiredAccess,
+ dwShareMode, NULL,
+ dwCreationDisposition,
+ dwFlagsAndAttributes,
+ NULL))==INVALID_HANDLE_VALUE &&
+ retryIoerr(&cnt) ){}
+/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
** Since the ASCII version of these Windows API do not exist for WINCE,
** it's important to not reference them for WINCE builds.
*/
#if SQLITE_OS_WINCE==0
}else{
- h = CreateFileA((char*)zConverted,
- dwDesiredAccess,
- dwShareMode,
- NULL,
- dwCreationDisposition,
- dwFlagsAndAttributes,
- NULL
- );
+ while( (h = CreateFileA((char*)zConverted,
+ dwDesiredAccess,
+ dwShareMode, NULL,
+ dwCreationDisposition,
+ dwFlagsAndAttributes,
+ NULL))==INVALID_HANDLE_VALUE &&
+ retryIoerr(&cnt) ){}
#endif
}
+
+ logIoerr(cnt);
+
+ OSTRACE(("OPEN %d %s 0x%lx %s\n",
+ h, zName, dwDesiredAccess,
+ h==INVALID_HANDLE_VALUE ? "failed" : "ok"));
+
if( h==INVALID_HANDLE_VALUE ){
+ pFile->lastErrno = GetLastError();
+ winLogError(SQLITE_CANTOPEN, "winOpen", zUtf8Name);
free(zConverted);
- if( flags & SQLITE_OPEN_READWRITE ){
- return winOpen(pVfs, zName, id,
- ((flags|SQLITE_OPEN_READONLY)&~SQLITE_OPEN_READWRITE), pOutFlags);
+ if( isReadWrite ){
+ return winOpen(pVfs, zName, id,
+ ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags);
}else{
return SQLITE_CANTOPEN_BKPT;
}
}
+
if( pOutFlags ){
- if( flags & SQLITE_OPEN_READWRITE ){
+ if( isReadWrite ){
*pOutFlags = SQLITE_OPEN_READWRITE;
}else{
*pOutFlags = SQLITE_OPEN_READONLY;
}
}
+
memset(pFile, 0, sizeof(*pFile));
pFile->pMethod = &winIoMethod;
pFile->h = h;
pFile->lastErrno = NO_ERROR;
+ pFile->pVfs = pVfs;
+ pFile->pShm = 0;
+ pFile->zPath = zName;
pFile->sectorSize = getSectorSize(pVfs, zUtf8Name);
+
#if SQLITE_OS_WINCE
- if( (flags & (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)) ==
- (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)
+ if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
&& !winceCreateLock(zName, pFile)
){
CloseHandle(h);
@@ -29520,8 +34211,9 @@ static int winOpen(
{
free(zConverted);
}
+
OpenCounter(+1);
- return SQLITE_OK;
+ return rc;
}
/*
@@ -29536,47 +34228,47 @@ static int winOpen(
** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
** up and returning an error.
*/
-#define MX_DELETION_ATTEMPTS 5
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;
- DWORD rc;
- DWORD error = 0;
- void *zConverted = convertUtf8Filename(zFilename);
+ int rc;
+ void *zConverted;
UNUSED_PARAMETER(pVfs);
UNUSED_PARAMETER(syncDir);
+
+ SimulateIOError(return SQLITE_IOERR_DELETE);
+ zConverted = convertUtf8Filename(zFilename);
if( zConverted==0 ){
return SQLITE_NOMEM;
}
- SimulateIOError(return SQLITE_IOERR_DELETE);
if( isNT() ){
- do{
- DeleteFileW(zConverted);
- }while( ( ((rc = GetFileAttributesW(zConverted)) != INVALID_FILE_ATTRIBUTES)
- || ((error = GetLastError()) == ERROR_ACCESS_DENIED))
- && (++cnt < MX_DELETION_ATTEMPTS)
- && (Sleep(100), 1) );
-/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
+ rc = 1;
+ while( GetFileAttributesW(zConverted)!=INVALID_FILE_ATTRIBUTES &&
+ (rc = DeleteFileW(zConverted))==0 && retryIoerr(&cnt) ){}
+ rc = rc ? SQLITE_OK : SQLITE_ERROR;
+/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
** Since the ASCII version of these Windows API do not exist for WINCE,
** it's important to not reference them for WINCE builds.
*/
#if SQLITE_OS_WINCE==0
}else{
- do{
- DeleteFileA(zConverted);
- }while( ( ((rc = GetFileAttributesA(zConverted)) != INVALID_FILE_ATTRIBUTES)
- || ((error = GetLastError()) == ERROR_ACCESS_DENIED))
- && (++cnt < MX_DELETION_ATTEMPTS)
- && (Sleep(100), 1) );
+ rc = 1;
+ while( GetFileAttributesA(zConverted)!=INVALID_FILE_ATTRIBUTES &&
+ (rc = DeleteFileA(zConverted))==0 && retryIoerr(&cnt) ){}
+ rc = rc ? SQLITE_OK : SQLITE_ERROR;
#endif
}
+ if( rc ){
+ rc = winLogError(SQLITE_IOERR_DELETE, "winDelete", zFilename);
+ }else{
+ logIoerr(cnt);
+ }
free(zConverted);
- OSTRACE2("DELETE \"%s\"\n", zFilename);
- return ( (rc == INVALID_FILE_ATTRIBUTES)
- && (error == ERROR_FILE_NOT_FOUND)) ? SQLITE_OK : SQLITE_IOERR_DELETE;
+ OSTRACE(("DELETE \"%s\" %s\n", zFilename, (rc ? "failed" : "ok" )));
+ return rc;
}
/*
@@ -29590,14 +34282,43 @@ static int winAccess(
){
DWORD attr;
int rc = 0;
- void *zConverted = convertUtf8Filename(zFilename);
+ void *zConverted;
UNUSED_PARAMETER(pVfs);
+
+ SimulateIOError( return SQLITE_IOERR_ACCESS; );
+ zConverted = convertUtf8Filename(zFilename);
if( zConverted==0 ){
return SQLITE_NOMEM;
}
if( isNT() ){
- attr = GetFileAttributesW((WCHAR*)zConverted);
-/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
+ int cnt = 0;
+ WIN32_FILE_ATTRIBUTE_DATA sAttrData;
+ memset(&sAttrData, 0, sizeof(sAttrData));
+ while( !(rc = GetFileAttributesExW((WCHAR*)zConverted,
+ GetFileExInfoStandard,
+ &sAttrData)) && retryIoerr(&cnt) ){}
+ 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( GetLastError()!=ERROR_FILE_NOT_FOUND ){
+ winLogError(SQLITE_IOERR_ACCESS, "winAccess", zFilename);
+ free(zConverted);
+ return SQLITE_IOERR_ACCESS;
+ }else{
+ attr = INVALID_FILE_ATTRIBUTES;
+ }
+ }
+/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
** Since the ASCII version of these Windows API do not exist for WINCE,
** it's important to not reference them for WINCE builds.
*/
@@ -29613,7 +34334,8 @@ static int winAccess(
rc = attr!=INVALID_FILE_ATTRIBUTES;
break;
case SQLITE_ACCESS_READWRITE:
- rc = (attr & FILE_ATTRIBUTE_READONLY)==0;
+ rc = attr!=INVALID_FILE_ATTRIBUTES &&
+ (attr & FILE_ATTRIBUTE_READONLY)==0;
break;
default:
assert(!"Invalid flags argument");
@@ -29634,14 +34356,16 @@ static int winFullPathname(
int nFull, /* Size of output buffer in bytes */
char *zFull /* Output buffer */
){
-
+
#if defined(__CYGWIN__)
+ SimulateIOError( return SQLITE_ERROR );
UNUSED_PARAMETER(nFull);
cygwin_conv_to_full_win32_path(zRelative, zFull);
return SQLITE_OK;
#endif
#if SQLITE_OS_WINCE
+ SimulateIOError( return SQLITE_ERROR );
UNUSED_PARAMETER(nFull);
/* WinCE has no concept of a relative pathname, or so I am told. */
sqlite3_snprintf(pVfs->mxPathname, zFull, "%s", zRelative);
@@ -29652,6 +34376,20 @@ static int winFullPathname(
int 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++;
+ }
+
+ /* 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 );
UNUSED_PARAMETER(nFull);
zConverted = convertUtf8Filename(zRelative);
if( isNT() ){
@@ -29666,7 +34404,7 @@ static int winFullPathname(
free(zConverted);
zOut = unicodeToUtf8(zTemp);
free(zTemp);
-/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
+/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
** Since the ASCII version of these Windows API do not exist for WINCE,
** it's important to not reference them for WINCE builds.
*/
@@ -29719,7 +34457,9 @@ static int getSectorSize(
** to get the drive letter to look up the sector
** size.
*/
+ SimulateIOErrorBenign(1);
rc = winFullPathname(pVfs, zRelative, MAX_PATH, zFullpath);
+ SimulateIOErrorBenign(0);
if( rc == SQLITE_OK )
{
void *zConverted = convertUtf8Filename(zFullpath);
@@ -29760,7 +34500,7 @@ static int getSectorSize(
}
}
#endif
- return (int) bytesPerSector;
+ return (int) bytesPerSector;
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
@@ -29781,7 +34521,7 @@ static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
}
if( isNT() ){
h = LoadLibraryW((WCHAR*)zConverted);
-/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
+/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
** Since the ASCII version of these Windows API do not exist for WINCE,
** it's important to not reference them for WINCE builds.
*/
@@ -29867,36 +34607,34 @@ static int winSleep(sqlite3_vfs *pVfs, int microsec){
}
/*
-** The following variable, if set to a non-zero value, becomes the result
-** returned from sqlite3OsCurrentTime(). This is used for testing.
+** 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;
+SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */
#endif
/*
-** 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.
+** 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 0. Return 1 if the time and date cannot be found.
*/
-int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
- FILETIME ft;
- /* FILETIME structure is a 64-bit value representing the number of
- 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
+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).
*/
- sqlite3_int64 timeW; /* Whole days */
- sqlite3_int64 timeF; /* Fractional Days */
-
- /* Number of 100-nanosecond intervals in a single day */
- static const sqlite3_int64 ntuPerDay =
- 10000000*(sqlite3_int64)86400;
-
- /* Number of 100-nanosecond intervals in half of a day */
- static const sqlite3_int64 ntuPerHalfDay =
- 10000000*(sqlite3_int64)43200;
-
+ 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 =
+ static const sqlite3_int64 max32BitValue =
(sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + (sqlite3_int64)294967296;
#if SQLITE_OS_WINCE
@@ -29909,23 +34647,35 @@ int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
#else
GetSystemTimeAsFileTime( &ft );
#endif
- UNUSED_PARAMETER(pVfs);
- timeW = (((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) + (sqlite3_int64)ft.dwLowDateTime;
- timeF = timeW % ntuPerDay; /* fractional days (100-nanoseconds) */
- timeW = timeW / ntuPerDay; /* whole days */
- timeW = timeW + 2305813; /* add whole days (from 2305813.5) */
- timeF = timeF + ntuPerHalfDay; /* add half a day (from 2305813.5) */
- timeW = timeW + (timeF/ntuPerDay); /* add whole day if half day made one */
- timeF = timeF % ntuPerDay; /* compute new fractional days */
- *prNow = (double)timeW + ((double)timeF / (double)ntuPerDay);
+
+ *piNow = winFiletimeEpoch +
+ ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) +
+ (sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)10000;
+
#ifdef SQLITE_TEST
if( sqlite3_current_time ){
- *prNow = ((double)sqlite3_current_time + (double)43200) / (double)86400 + (double)2440587;
+ *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
}
#endif
+ UNUSED_PARAMETER(pVfs);
return 0;
}
+/*
+** 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.
+*/
+int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
+ int rc;
+ sqlite3_int64 i;
+ rc = winCurrentTimeInt64(pVfs, &i);
+ if( !rc ){
+ *prNow = i/86400000.0;
+ }
+ return rc;
+}
+
/*
** The idea is that this function works like a combination of
** GetLastError() and FormatMessage() on windows (or errno and
@@ -29961,36 +34711,48 @@ static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
return getLastErrorMsg(nBuf, zBuf);
}
+
+
/*
** Initialize and deinitialize the operating system interface.
*/
SQLITE_API int sqlite3_os_init(void){
static sqlite3_vfs winVfs = {
- 1, /* 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 */
+ 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 */
+ 0, /* xSetSystemCall */
+ 0, /* xGetSystemCall */
+ 0, /* xNextSystemCall */
};
+#ifndef SQLITE_OMIT_WAL
+ /* get memory map allocation granularity */
+ memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
+ GetSystemInfo(&winSysInfo);
+ assert(winSysInfo.dwAllocationGranularity > 0);
+#endif
+
sqlite3_vfs_register(&winVfs, 1);
- return SQLITE_OK;
+ return SQLITE_OK;
}
-SQLITE_API int sqlite3_os_end(void){
+SQLITE_API int sqlite3_os_end(void){
return SQLITE_OK;
}
@@ -30017,8 +34779,8 @@ SQLITE_API int sqlite3_os_end(void){
** 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
+** 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.
@@ -30036,14 +34798,14 @@ SQLITE_API int sqlite3_os_end(void){
*/
/* Size of the Bitvec structure in bytes. */
-#define BITVEC_SZ (sizeof(void*)*128) /* 512 on 32bit. 1024 on 64bit */
+#define BITVEC_SZ 512
-/* Round the union size down to the nearest pointer boundary, since that's how
+/* 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.
+/* 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
@@ -30056,12 +34818,12 @@ SQLITE_API int sqlite3_os_end(void){
/* Number of u32 values in hash table. */
#define BITVEC_NINT (BITVEC_USIZE/sizeof(u32))
-/* Maximum number of entries in hash table before
+/* 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
+** 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)
@@ -30107,7 +34869,7 @@ struct Bitvec {
/*
** Create a new bitmap object able to handle bits between 0 and iSize,
-** inclusive. Return a pointer to the new object. Return NULL if
+** inclusive. Return a pointer to the new object. Return NULL if
** malloc fails.
*/
SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32 iSize){
@@ -30361,7 +35123,7 @@ SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){
break;
}
case 3:
- case 4:
+ case 4:
default: {
nx = 2;
sqlite3_randomness(sizeof(i), &i);
@@ -30546,17 +35308,21 @@ static void pcacheUnpin(PgHdr *p){
/*************************************************** General Interfaces ******
**
-** Initialize and shutdown the page cache subsystem. Neither of these
+** Initialize and shutdown the page cache subsystem. Neither of these
** functions are threadsafe.
*/
SQLITE_PRIVATE int sqlite3PcacheInitialize(void){
if( sqlite3GlobalConfig.pcache.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.pcache.xInit(sqlite3GlobalConfig.pcache.pArg);
}
SQLITE_PRIVATE void sqlite3PcacheShutdown(void){
if( sqlite3GlobalConfig.pcache.xShutdown ){
+ /* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */
sqlite3GlobalConfig.pcache.xShutdown(sqlite3GlobalConfig.pcache.pArg);
}
}
@@ -30568,8 +35334,8 @@ 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
+** 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(
@@ -30642,14 +35408,14 @@ SQLITE_PRIVATE int sqlite3PcacheFetch(
if( !pPage && eCreate==1 ){
PgHdr *pPg;
- /* Find a dirty page to write-out and recycle. First try to find a
+ /* 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
+ ** 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));
+ for(pPg=pCache->pSynced;
+ pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
pPg=pPg->pDirtyPrev
);
pCache->pSynced = pPg;
@@ -30658,6 +35424,13 @@ SQLITE_PRIVATE int sqlite3PcacheFetch(
}
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),
+ pCache->nMax);
+#endif
rc = pCache->xStress(pCache->pStress, pPg);
if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
return rc;
@@ -30669,15 +35442,17 @@ SQLITE_PRIVATE int sqlite3PcacheFetch(
if( pPage ){
if( !pPage->pData ){
- memset(pPage, 0, sizeof(PgHdr) + pCache->szExtra);
- pPage->pExtra = (void*)&pPage[1];
- pPage->pData = (void *)&((char *)pPage)[sizeof(PgHdr) + pCache->szExtra];
+ memset(pPage, 0, sizeof(PgHdr));
+ pPage->pData = (void *)&pPage[1];
+ pPage->pExtra = (void*)&((char *)pPage->pData)[pCache->szPage];
+ memset(pPage->pExtra, 0, pCache->szExtra);
pPage->pCache = pCache;
pPage->pgno = pgno;
}
assert( pPage->pCache==pCache );
assert( pPage->pgno==pgno );
- assert( pPage->pExtra==(void *)&pPage[1] );
+ assert( pPage->pData==(void *)&pPage[1] );
+ assert( pPage->pExtra==(void *)&((char *)&pPage[1])[pCache->szPage] );
if( 0==pPage->nRef ){
pCache->nRef++;
@@ -30787,7 +35562,7 @@ SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *pCache){
}
/*
-** Change the page number of page p to newPgno.
+** Change the page number of page p to newPgno.
*/
SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
PCache *pCache = p->pCache;
@@ -30816,7 +35591,12 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
PgHdr *pNext;
for(p=pCache->pDirty; p; p=pNext){
pNext = p->pDirtyNext;
- if( p->pgno>pgno ){
+ /* 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);
}
@@ -30838,7 +35618,7 @@ SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){
}
}
-/*
+/*
** Discard the contents of the cache.
*/
SQLITE_PRIVATE void sqlite3PcacheClear(PCache *pCache){
@@ -30926,7 +35706,7 @@ SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
return pcacheSortDirtyList(pCache->pDirty);
}
-/*
+/*
** Return the total number of referenced pages held by the cache.
*/
SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache *pCache){
@@ -30940,7 +35720,7 @@ SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr *p){
return p->nRef;
}
-/*
+/*
** Return the total number of pages in the cache.
*/
SQLITE_PRIVATE int sqlite3PcachePagecount(PCache *pCache){
@@ -31009,24 +35789,123 @@ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHd
typedef struct PCache1 PCache1;
typedef struct PgHdr1 PgHdr1;
typedef struct PgFreeslot PgFreeslot;
+typedef struct PGroup PGroup;
-/* Pointers to structures of this type are cast and returned as
-** opaque sqlite3_pcache* handles
+typedef struct PGroupBlock PGroupBlock;
+typedef struct PGroupBlockList PGroupBlockList;
+
+/* 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.
+**
+** 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 is able recycle pages more efficient.
+**
+** 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 */
+ int nMaxPage; /* Sum of nMax for purgeable caches */
+ int nMinPage; /* Sum of nMin for purgeable caches */
+ int mxPinned; /* nMaxpage + 10 - nMinPage */
+ int nCurrentPage; /* Number of purgeable pages allocated */
+ PgHdr1 *pLruHead, *pLruTail; /* LRU list of unpinned pages */
+#ifdef SQLITE_PAGECACHE_BLOCKALLOC
+ int isBusy; /* Do not run ReleaseMemory() if true */
+ PGroupBlockList *pBlockList; /* List of block-lists for this group */
+#endif
+};
+
+/*
+** If SQLITE_PAGECACHE_BLOCKALLOC is defined when the library is built,
+** each PGroup structure has a linked list of the the following starting
+** at PGroup.pBlockList. There is one entry for each distinct page-size
+** currently used by members of the PGroup (i.e. 1024 bytes, 4096 bytes
+** etc.). Variable PGroupBlockList.nByte is set to the actual allocation
+** size requested by each pcache, which is the database page-size plus
+** the various header structures used by the pcache, pager and btree layers.
+** Usually around (pgsz+200) bytes.
+**
+** This size (pgsz+200) bytes is not allocated efficiently by some
+** implementations of malloc. In particular, some implementations are only
+** able to allocate blocks of memory chunks of 2^N bytes, where N is some
+** integer value. Since the page-size is a power of 2, this means we
+** end up wasting (pgsz-200) bytes in each allocation.
+**
+** If SQLITE_PAGECACHE_BLOCKALLOC is defined, the (pgsz+200) byte blocks
+** are not allocated directly. Instead, blocks of roughly M*(pgsz+200) bytes
+** are requested from malloc allocator. After a block is returned,
+** sqlite3MallocSize() is used to determine how many (pgsz+200) byte
+** allocations can fit in the space returned by malloc(). This value may
+** be more than M.
+**
+** The blocks are stored in a doubly-linked list. Variable PGroupBlock.nEntry
+** contains the number of allocations that will fit in the aData[] space.
+** nEntry is limited to the number of bits in bitmask mUsed. If a slot
+** within aData is in use, the corresponding bit in mUsed is set. Thus
+** when (mUsed+1==(1 << nEntry)) the block is completely full.
+**
+** Each time a slot within a block is freed, the block is moved to the start
+** of the linked-list. And if a block becomes completely full, then it is
+** moved to the end of the list. As a result, when searching for a free
+** slot, only the first block in the list need be examined. If it is full,
+** then it is guaranteed that all blocks are full.
+*/
+struct PGroupBlockList {
+ int nByte; /* Size of each allocation in bytes */
+ PGroupBlock *pFirst; /* First PGroupBlock in list */
+ PGroupBlock *pLast; /* Last PGroupBlock in list */
+ PGroupBlockList *pNext; /* Next block-list attached to group */
+};
+
+struct PGroupBlock {
+ Bitmask mUsed; /* Mask of used slots */
+ int nEntry; /* Maximum number of allocations in aData[] */
+ u8 *aData; /* Pointer to data block */
+ PGroupBlock *pNext; /* Next PGroupBlock in list */
+ PGroupBlock *pPrev; /* Previous PGroupBlock in list */
+ PGroupBlockList *pList; /* Owner list */
+};
+
+/* Minimum value for PGroupBlock.nEntry */
+#define PAGECACHE_BLOCKALLOC_MINENTRY 15
+
+/* 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.
+**
+** 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
+ ** flag (bPurgeable) are set when the cache is created. nMax may be
** modified at any time by a call to the pcache1CacheSize() method.
- ** The global mutex must be held when accessing nMax.
+ ** 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 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 */
/* Hash table of all pages. The following variables may only be accessed
- ** when the accessor is holding the global mutex (see pcache1EnterMutex()
- ** and pcache1LeaveMutex()).
+ ** 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 */
@@ -31037,9 +35916,9 @@ struct PCache1 {
};
/*
-** Each cache entry is represented by an instance of the following
-** structure. A buffer of PgHdr1.pCache->szPage bytes is allocated
-** directly before this structure in memory (see the PGHDR1_TO_PAGE()
+** Each cache entry is represented by an instance of the following
+** structure. A buffer of PgHdr1.pCache->szPage bytes is allocated
+** directly before this structure in memory (see the PGHDR1_TO_PAGE()
** macro below).
*/
struct PgHdr1 {
@@ -31062,18 +35941,27 @@ struct PgFreeslot {
** Global data used by this cache.
*/
static SQLITE_WSD struct PCacheGlobal {
- sqlite3_mutex *mutex; /* static mutex MUTEX_STATIC_LRU */
+ PGroup grp; /* The global PGroup for mode (2) */
- int nMaxPage; /* Sum of nMaxPage for purgeable caches */
- int nMinPage; /* Sum of nMinPage for purgeable caches */
- int nCurrentPage; /* Number of purgeable pages allocated */
- PgHdr1 *pLruHead, *pLruTail; /* LRU list of unpinned pages */
-
- /* Variables related to SQLITE_CONFIG_PAGECACHE settings. */
- int szSlot; /* Size of each free slot */
- void *pStart, *pEnd; /* Bounds of pagecache malloc range */
- PgFreeslot *pFree; /* Free page blocks */
- int isInit; /* True if initialized */
+ /* 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: */
+ int nFreeSlot; /* Number of unused pcache slots */
+ PgFreeslot *pFree; /* Free page blocks */
+ /* 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;
/*
@@ -31099,27 +35987,44 @@ static SQLITE_WSD struct PCacheGlobal {
#define PAGE_TO_PGHDR1(c, p) (PgHdr1*)(((char*)p) + c->szPage)
/*
-** Macros to enter and leave the global LRU mutex.
+** Blocks used by the SQLITE_PAGECACHE_BLOCKALLOC blocks to store/retrieve
+** a PGroupBlock pointer based on a pointer to a page buffer.
*/
-#define pcache1EnterMutex() sqlite3_mutex_enter(pcache1.mutex)
-#define pcache1LeaveMutex() sqlite3_mutex_leave(pcache1.mutex)
+#define PAGE_SET_BLOCKPTR(pCache, pPg, pBlock) \
+ ( *(PGroupBlock **)&(((u8*)pPg)[sizeof(PgHdr1) + pCache->szPage]) = pBlock )
+
+#define PAGE_GET_BLOCKPTR(pCache, pPg) \
+ ( *(PGroupBlock **)&(((u8*)pPg)[sizeof(PgHdr1) + pCache->szPage]) )
+
+
+/*
+** 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)
/******************************************************************************/
/******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/
/*
-** This function is called during initialization if a static buffer is
+** 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.
*/
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;
@@ -31132,34 +36037,41 @@ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
/*
** 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
+** 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;
- assert( sqlite3_mutex_held(pcache1.mutex) );
- if( nByte<=pcache1.szSlot && pcache1.pFree ){
- assert( pcache1.isInit );
+ 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;
- pcache1.pFree = pcache1.pFree->pNext;
- sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
- }else{
-
- /* Allocate a new buffer using sqlite3Malloc. Before doing so, exit the
- ** global pcache mutex and unlock the pager-cache object pCache. This is
- ** so that if the attempt to allocate a new buffer causes the the
- ** configured soft-heap-limit to be breached, it will be possible to
- ** reclaim memory from this pager-cache.
+ if( p ){
+ pcache1.pFree = pcache1.pFree->pNext;
+ pcache1.nFreeSlot--;
+ pcache1.bUnderPressure = 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.
*/
- pcache1LeaveMutex();
p = sqlite3Malloc(nByte);
- pcache1EnterMutex();
if( p ){
int sz = sqlite3MallocSize(p);
+ sqlite3_mutex_enter(pcache1.mutex);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
+ sqlite3_mutex_leave(pcache1.mutex);
}
+ sqlite3MemdebugSetType(p, MEMTYPE_PCACHE);
}
return p;
}
@@ -31168,36 +36080,197 @@ static void *pcache1Alloc(int nByte){
** Free an allocated buffer obtained from pcache1Alloc().
*/
static void pcache1Free(void *p){
- assert( sqlite3_mutex_held(pcache1.mutex) );
if( p==0 ) return;
if( p>=pcache1.pStart && ppNext = pcache1.pFree;
pcache1.pFree = pSlot;
+ pcache1.nFreeSlot++;
+ pcache1.bUnderPressure = pcache1.nFreeSlot=pcache1.pStart && ppPrev = 0;
+ pBlock->pNext = pList->pFirst;
+ pList->pFirst = pBlock;
+ if( pBlock->pNext ){
+ pBlock->pNext->pPrev = pBlock;
+ }else{
+ assert( pList->pLast==0 );
+ pList->pLast = pBlock;
+ }
+}
+
+/*
+** If there are no blocks in the list headed by pList, remove pList
+** from the pGroup->pBlockList list and free it with sqlite3_free().
+*/
+static void freeListIfEmpty(PGroup *pGroup, PGroupBlockList *pList){
+ assert( sqlite3_mutex_held(pGroup->mutex) );
+ if( pList->pFirst==0 ){
+ PGroupBlockList **pp;
+ for(pp=&pGroup->pBlockList; *pp!=pList; pp=&(*pp)->pNext);
+ *pp = (*pp)->pNext;
+ sqlite3_free(pList);
+ }
+}
+#endif /* SQLITE_PAGECACHE_BLOCKALLOC */
+
/*
** Allocate a new page object initially associated with cache pCache.
*/
static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
int nByte = sizeof(PgHdr1) + pCache->szPage;
- void *pPg = pcache1Alloc(nByte);
+ void *pPg = 0;
PgHdr1 *p;
+
+#ifdef SQLITE_PAGECACHE_BLOCKALLOC
+ PGroup *pGroup = pCache->pGroup;
+ PGroupBlockList *pList;
+ PGroupBlock *pBlock;
+ int i;
+
+ nByte += sizeof(PGroupBlockList *);
+ nByte = ROUND8(nByte);
+
+ for(pList=pGroup->pBlockList; pList; pList=pList->pNext){
+ if( pList->nByte==nByte ) break;
+ }
+ if( pList==0 ){
+ PGroupBlockList *pNew;
+ assert( pGroup->isBusy==0 );
+ assert( sqlite3_mutex_held(pGroup->mutex) );
+ pGroup->isBusy = 1; /* Disable sqlite3PcacheReleaseMemory() */
+ pNew = (PGroupBlockList *)sqlite3MallocZero(sizeof(PGroupBlockList));
+ pGroup->isBusy = 0; /* Reenable sqlite3PcacheReleaseMemory() */
+ if( pNew==0 ){
+ /* malloc() failure. Return early. */
+ return 0;
+ }
+#ifdef SQLITE_DEBUG
+ for(pList=pGroup->pBlockList; pList; pList=pList->pNext){
+ assert( pList->nByte!=nByte );
+ }
+#endif
+ pNew->nByte = nByte;
+ pNew->pNext = pGroup->pBlockList;
+ pGroup->pBlockList = pNew;
+ pList = pNew;
+ }
+
+ pBlock = pList->pFirst;
+ if( pBlock==0 || pBlock->mUsed==(((Bitmask)1<nEntry)-1) ){
+ int sz;
+
+ /* Allocate a new block. Try to allocate enough space for the PGroupBlock
+ ** structure and MINENTRY allocations of nByte bytes each. If the
+ ** allocator returns more memory than requested, then more than MINENTRY
+ ** allocations may fit in it. */
+ assert( sqlite3_mutex_held(pGroup->mutex) );
+ pcache1LeaveMutex(pCache->pGroup);
+ sz = sizeof(PGroupBlock) + PAGECACHE_BLOCKALLOC_MINENTRY * nByte;
+ pBlock = (PGroupBlock *)sqlite3Malloc(sz);
+ pcache1EnterMutex(pCache->pGroup);
+
+ if( !pBlock ){
+ freeListIfEmpty(pGroup, pList);
+ return 0;
+ }
+ pBlock->nEntry = (sqlite3MallocSize(pBlock) - sizeof(PGroupBlock)) / nByte;
+ if( pBlock->nEntry>=BMS ){
+ pBlock->nEntry = BMS-1;
+ }
+ pBlock->pList = pList;
+ pBlock->mUsed = 0;
+ pBlock->aData = (u8 *)&pBlock[1];
+ addBlockToList(pList, pBlock);
+
+ sz = sqlite3MallocSize(pBlock);
+ sqlite3_mutex_enter(pcache1.mutex);
+ sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
+ sqlite3_mutex_leave(pcache1.mutex);
+ }
+
+ for(i=0; pPg==0 && ALWAYS(inEntry); i++){
+ if( 0==(pBlock->mUsed & ((Bitmask)1<mUsed |= ((Bitmask)1<aData[pList->nByte * i];
+ }
+ }
+ assert( pPg );
+ PAGE_SET_BLOCKPTR(pCache, pPg, pBlock);
+
+ /* If the block is now full, shift it to the end of the list */
+ if( pBlock->mUsed==(((Bitmask)1<nEntry)-1) && pList->pLast!=pBlock ){
+ assert( pList->pFirst==pBlock );
+ assert( pBlock->pPrev==0 );
+ assert( pList->pLast->pNext==0 );
+ pList->pFirst = pBlock->pNext;
+ pList->pFirst->pPrev = 0;
+ pBlock->pPrev = pList->pLast;
+ pBlock->pNext = 0;
+ pList->pLast->pNext = pBlock;
+ pList->pLast = pBlock;
+ }
+ p = PAGE_TO_PGHDR1(pCache, pPg);
+ if( pCache->bPurgeable ){
+ pCache->pGroup->nCurrentPage++;
+ }
+#else
+ /* 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);
+ pPg = pcache1Alloc(nByte);
+ pcache1EnterMutex(pCache->pGroup);
if( pPg ){
p = PAGE_TO_PGHDR1(pCache, pPg);
if( pCache->bPurgeable ){
- pcache1.nCurrentPage++;
+ pCache->pGroup->nCurrentPage++;
}
}else{
p = 0;
}
+#endif
return p;
}
@@ -31210,10 +36283,53 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
*/
static void pcache1FreePage(PgHdr1 *p){
if( ALWAYS(p) ){
- if( p->pCache->bPurgeable ){
- pcache1.nCurrentPage--;
+ PCache1 *pCache = p->pCache;
+ void *pPg = PGHDR1_TO_PAGE(p);
+
+#ifdef SQLITE_PAGECACHE_BLOCKALLOC
+ PGroupBlock *pBlock = PAGE_GET_BLOCKPTR(pCache, pPg);
+ PGroupBlockList *pList = pBlock->pList;
+ int i = ((u8 *)pPg - pBlock->aData) / pList->nByte;
+
+ assert( pPg==(void *)&pBlock->aData[i*pList->nByte] );
+ assert( pBlock->mUsed & ((Bitmask)1<mUsed &= ~((Bitmask)1<pFirst==pBlock ){
+ pList->pFirst = pBlock->pNext;
+ if( pList->pFirst ) pList->pFirst->pPrev = 0;
+ }else{
+ pBlock->pPrev->pNext = pBlock->pNext;
+ }
+ if( pList->pLast==pBlock ){
+ pList->pLast = pBlock->pPrev;
+ if( pList->pLast ) pList->pLast->pNext = 0;
+ }else{
+ pBlock->pNext->pPrev = pBlock->pPrev;
+ }
+
+ if( pBlock->mUsed==0 ){
+ PGroup *pGroup = p->pCache->pGroup;
+
+ int sz = sqlite3MallocSize(pBlock);
+ sqlite3_mutex_enter(pcache1.mutex);
+ sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -sz);
+ sqlite3_mutex_leave(pcache1.mutex);
+ freeListIfEmpty(pGroup, pList);
+ sqlite3_free(pBlock);
+ }else{
+ addBlockToList(pList, pBlock);
+ }
+#else
+ assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) );
+ pcache1Free(pPg);
+#endif
+ if( pCache->bPurgeable ){
+ pCache->pGroup->nCurrentPage--;
}
- pcache1Free(PGHDR1_TO_PAGE(p));
}
}
@@ -31223,20 +36339,39 @@ static void pcache1FreePage(PgHdr1 *p){
** exists, this function falls back to sqlite3Malloc().
*/
SQLITE_PRIVATE void *sqlite3PageMalloc(int sz){
- void *p;
- pcache1EnterMutex();
- p = pcache1Alloc(sz);
- pcache1LeaveMutex();
- return p;
+ return pcache1Alloc(sz);
}
/*
** Free an allocated buffer obtained from sqlite3PageMalloc().
*/
SQLITE_PRIVATE void sqlite3PageFree(void *p){
- pcache1EnterMutex();
pcache1Free(p);
- pcache1LeaveMutex();
+}
+
+
+/*
+** Return true if it desirable to avoid allocating a new page cache
+** entry.
+**
+** 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 put 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<=pcache1.szSlot ){
+ return pcache1.bUnderPressure;
+ }else{
+ return sqlite3HeapNearlyFull();
+ }
}
/******************************************************************************/
@@ -31246,25 +36381,25 @@ SQLITE_PRIVATE void sqlite3PageFree(void *p){
** This function is used to resize the hash table used by the cache passed
** as the first argument.
**
-** The global mutex must be held when this function is called.
+** The PCache mutex must be held when this function is called.
*/
static int pcache1ResizeHash(PCache1 *p){
PgHdr1 **apNew;
unsigned int nNew;
unsigned int i;
- assert( sqlite3_mutex_held(pcache1.mutex) );
+ assert( sqlite3_mutex_held(p->pGroup->mutex) );
nNew = p->nHash*2;
if( nNew<256 ){
nNew = 256;
}
- pcache1LeaveMutex();
+ pcache1LeaveMutex(p->pGroup);
if( p->nHash ){ sqlite3BeginBenignMalloc(); }
apNew = (PgHdr1 **)sqlite3_malloc(sizeof(PgHdr1 *)*nNew);
if( p->nHash ){ sqlite3EndBenignMalloc(); }
- pcache1EnterMutex();
+ pcache1EnterMutex(p->pGroup);
if( apNew ){
memset(apNew, 0, sizeof(PgHdr1 *)*nNew);
for(i=0; inHash; i++){
@@ -31286,26 +36421,34 @@ static int pcache1ResizeHash(PCache1 *p){
}
/*
-** This function is used internally to remove the page pPage from the
-** global LRU list, if is part of it. If pPage is not part of the global
+** 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 global mutex must be held when this function is called.
+** The PGroup mutex must be held when this function is called.
+**
+** If pPage is NULL then this routine is a no-op.
*/
static void pcache1PinPage(PgHdr1 *pPage){
- assert( sqlite3_mutex_held(pcache1.mutex) );
- if( pPage && (pPage->pLruNext || pPage==pcache1.pLruTail) ){
+ 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( pcache1.pLruHead==pPage ){
- pcache1.pLruHead = pPage->pLruNext;
+ if( pGroup->pLruHead==pPage ){
+ pGroup->pLruHead = pPage->pLruNext;
}
- if( pcache1.pLruTail==pPage ){
- pcache1.pLruTail = pPage->pLruPrev;
+ if( pGroup->pLruTail==pPage ){
+ pGroup->pLruTail = pPage->pLruPrev;
}
pPage->pLruNext = 0;
pPage->pLruPrev = 0;
@@ -31315,16 +36458,17 @@ static void pcache1PinPage(PgHdr1 *pPage){
/*
-** Remove the page supplied as an argument from the hash table
+** Remove the page supplied as an argument from the hash table
** (PCache1.apHash structure) that it is currently stored in.
**
-** The global mutex must be held when this function is called.
+** 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;
+ 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;
@@ -31333,13 +36477,14 @@ static void pcache1RemoveFromHash(PgHdr1 *pPage){
}
/*
-** If there are currently more than pcache.nMaxPage pages allocated, try
-** to recycle pages to reduce the number allocated to pcache.nMaxPage.
+** If there are currently more than nMaxPage pages allocated, try
+** to recycle pages to reduce the number allocated to nMaxPage.
*/
-static void pcache1EnforceMaxPage(void){
- assert( sqlite3_mutex_held(pcache1.mutex) );
- while( pcache1.nCurrentPage>pcache1.nMaxPage && pcache1.pLruTail ){
- PgHdr1 *p = pcache1.pLruTail;
+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);
@@ -31347,21 +36492,21 @@ static void pcache1EnforceMaxPage(void){
}
/*
-** Discard all pages from cache pCache with a page number (key value)
-** greater than or equal to iLimit. Any pinned pages that meet this
+** 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 global mutex must be held when this function is called.
+** The PCache mutex must be held when this function is called.
*/
static void pcache1TruncateUnsafe(
- PCache1 *pCache,
- unsigned int iLimit
+ PCache1 *pCache, /* The cache to truncate */
+ unsigned int iLimit /* Drop pages with this pgno or larger */
){
- TESTONLY( unsigned int nPage = 0; ) /* Used to assert pCache->nPage is correct */
+ TESTONLY( unsigned int nPage = 0; ) /* To assert pCache->nPage is correct */
unsigned int h;
- assert( sqlite3_mutex_held(pcache1.mutex) );
+ assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
for(h=0; hnHash; h++){
- PgHdr1 **pp = &pCache->apHash[h];
+ PgHdr1 **pp = &pCache->apHash[h];
PgHdr1 *pPage;
while( (pPage = *pp)!=0 ){
if( pPage->iKey>=iLimit ){
@@ -31389,15 +36534,17 @@ static int pcache1Init(void *NotUsed){
assert( pcache1.isInit==0 );
memset(&pcache1, 0, sizeof(pcache1));
if( sqlite3GlobalConfig.bCoreMutex ){
- pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
+ pcache1.grp.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
+ pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PMEM);
}
+ pcache1.grp.mxPinned = 10;
pcache1.isInit = 1;
return SQLITE_OK;
}
/*
** Implementation of the sqlite3_pcache.xShutdown method.
-** Note that the static mutex allocated in xInit does
+** Note that the static mutex allocated in xInit does
** not need to be freed.
*/
static void pcache1Shutdown(void *NotUsed){
@@ -31412,58 +36559,91 @@ static void pcache1Shutdown(void *NotUsed){
** Allocate a new cache.
*/
static sqlite3_pcache *pcache1Create(int szPage, int bPurgeable){
- PCache1 *pCache;
+ 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 */
- pCache = (PCache1 *)sqlite3_malloc(sizeof(PCache1));
+ /*
+ ** 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
+
+ sz = sizeof(PCache1) + sizeof(PGroup)*separateCache;
+ pCache = (PCache1 *)sqlite3_malloc(sz);
if( pCache ){
- memset(pCache, 0, sizeof(PCache1));
+ memset(pCache, 0, sz);
+ if( separateCache ){
+ pGroup = (PGroup*)&pCache[1];
+ pGroup->mxPinned = 10;
+ }else{
+ pGroup = &pcache1.grp;
+ }
+ pCache->pGroup = pGroup;
pCache->szPage = szPage;
pCache->bPurgeable = (bPurgeable ? 1 : 0);
if( bPurgeable ){
pCache->nMin = 10;
- pcache1EnterMutex();
- pcache1.nMinPage += pCache->nMin;
- pcache1LeaveMutex();
+ pcache1EnterMutex(pGroup);
+ pGroup->nMinPage += pCache->nMin;
+ pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
+ pcache1LeaveMutex(pGroup);
}
}
return (sqlite3_pcache *)pCache;
}
/*
-** Implementation of the sqlite3_pcache.xCachesize method.
+** Implementation of the sqlite3_pcache.xCachesize method.
**
** Configure the cache_size limit for a cache.
*/
static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
PCache1 *pCache = (PCache1 *)p;
if( pCache->bPurgeable ){
- pcache1EnterMutex();
- pcache1.nMaxPage += (nMax - pCache->nMax);
+ PGroup *pGroup = pCache->pGroup;
+ pcache1EnterMutex(pGroup);
+ pGroup->nMaxPage += (nMax - pCache->nMax);
+ pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
pCache->nMax = nMax;
- pcache1EnforceMaxPage();
- pcache1LeaveMutex();
+ pCache->n90pct = pCache->nMax*9/10;
+ pcache1EnforceMaxPage(pGroup);
+ pcache1LeaveMutex(pGroup);
}
}
/*
-** Implementation of the sqlite3_pcache.xPagecount method.
+** Implementation of the sqlite3_pcache.xPagecount method.
*/
static int pcache1Pagecount(sqlite3_pcache *p){
int n;
- pcache1EnterMutex();
- n = ((PCache1 *)p)->nPage;
- pcache1LeaveMutex();
+ PCache1 *pCache = (PCache1*)p;
+ pcache1EnterMutex(pCache->pGroup);
+ n = pCache->nPage;
+ pcache1LeaveMutex(pCache->pGroup);
return n;
}
/*
-** Implementation of the sqlite3_pcache.xFetch method.
+** 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
+** 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
@@ -31474,62 +36654,87 @@ static int pcache1Pagecount(sqlite3_pcache *p){
** 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
+** 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,
-** and if either of the following are true, return NULL:
+** 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.
+** 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
+** (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.
+** proceed to step 5.
**
** 5. Otherwise, allocate and return a new page buffer.
*/
static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
- unsigned int nPinned;
+ int nPinned;
PCache1 *pCache = (PCache1 *)p;
+ PGroup *pGroup;
PgHdr1 *pPage = 0;
assert( pCache->bPurgeable || createFlag!=1 );
- pcache1EnterMutex();
- if( createFlag==1 ) sqlite3BeginBenignMalloc();
+ assert( pCache->bPurgeable || pCache->nMin==0 );
+ assert( pCache->bPurgeable==0 || pCache->nMin==10 );
+ assert( pCache->nMin==0 || pCache->bPurgeable );
+ pcache1EnterMutex(pGroup = pCache->pGroup);
- /* Search the hash table for an existing entry. */
+ /* 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);
}
+ /* Step 2: Abort if no existing page is found and createFlag is 0 */
if( pPage || createFlag==0 ){
pcache1PinPage(pPage);
goto fetch_out;
}
- /* Step 3 of header comment. */
+ /* The pGroup local variable will normally be initialized by the
+ ** pcache1EnterMutex() macro above. But if SQLITE_MUTEX_OMIT is defined,
+ ** then pcache1EnterMutex() is a no-op, so we have to initialize the
+ ** local variable here. Delaying the initialization of pGroup is an
+ ** optimization: The common case is to exit the module before reaching
+ ** this point.
+ */
+#ifdef SQLITE_MUTEX_OMIT
+ pGroup = pCache->pGroup;
+#endif
+
+
+ /* Step 3: Abort if createFlag is 1 but the cache is nearly full */
nPinned = pCache->nPage - pCache->nRecyclable;
+ assert( nPinned>=0 );
+ assert( pGroup->mxPinned == pGroup->nMaxPage + 10 - pGroup->nMinPage );
+ assert( pCache->n90pct == pCache->nMax*9/10 );
if( createFlag==1 && (
- nPinned>=(pcache1.nMaxPage+pCache->nMin-pcache1.nMinPage)
- || nPinned>=(pCache->nMax * 9 / 10)
+ nPinned>=pGroup->mxPinned
+ || nPinned>=(int)pCache->n90pct
+ || pcache1UnderMemoryPressure(pCache)
)){
goto fetch_out;
}
@@ -31538,26 +36743,32 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
goto fetch_out;
}
- /* Step 4. Try to recycle a page buffer if appropriate. */
- if( pCache->bPurgeable && pcache1.pLruTail && (
- (pCache->nPage+1>=pCache->nMax) || pcache1.nCurrentPage>=pcache1.nMaxPage
+ /* Step 4. Try to recycle a page. */
+ if( pCache->bPurgeable && pGroup->pLruTail && (
+ (pCache->nPage+1>=pCache->nMax)
+ || pGroup->nCurrentPage>=pGroup->nMaxPage
+ || pcache1UnderMemoryPressure(pCache)
)){
- pPage = pcache1.pLruTail;
+ PCache1 *pOtherCache;
+ pPage = pGroup->pLruTail;
pcache1RemoveFromHash(pPage);
pcache1PinPage(pPage);
- if( pPage->pCache->szPage!=pCache->szPage ){
+ if( (pOtherCache = pPage->pCache)->szPage!=pCache->szPage ){
pcache1FreePage(pPage);
pPage = 0;
}else{
- pcache1.nCurrentPage -= (pPage->pCache->bPurgeable - pCache->bPurgeable);
+ pGroup->nCurrentPage -=
+ (pOtherCache->bPurgeable - pCache->bPurgeable);
}
}
- /* Step 5. If a usable page buffer has still not been found,
- ** attempt to allocate a new one.
+ /* Step 5. If a usable page buffer has still not been found,
+ ** attempt to allocate a new one.
*/
if( !pPage ){
+ if( createFlag==1 ) sqlite3BeginBenignMalloc();
pPage = pcache1AllocPage(pCache);
+ if( createFlag==1 ) sqlite3EndBenignMalloc();
}
if( pPage ){
@@ -31576,8 +36787,7 @@ fetch_out:
if( pPage && iKey>pCache->iMaxKey ){
pCache->iMaxKey = iKey;
}
- if( createFlag==1 ) sqlite3EndBenignMalloc();
- pcache1LeaveMutex();
+ pcache1LeaveMutex(pGroup);
return (pPage ? PGHDR1_TO_PAGE(pPage) : 0);
}
@@ -31590,41 +36800,38 @@ fetch_out:
static void pcache1Unpin(sqlite3_pcache *p, void *pPg, int reuseUnlikely){
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = PAGE_TO_PGHDR1(pCache, pPg);
-
+ PGroup *pGroup = pCache->pGroup;
+
assert( pPage->pCache==pCache );
- pcache1EnterMutex();
+ pcache1EnterMutex(pGroup);
- /* It is an error to call this function if the page is already
- ** part of the global LRU list.
+ /* 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( pcache1.pLruHead!=pPage && pcache1.pLruTail!=pPage );
+ assert( pGroup->pLruHead!=pPage && pGroup->pLruTail!=pPage );
- if( reuseUnlikely || pcache1.nCurrentPage>pcache1.nMaxPage ){
+ if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){
pcache1RemoveFromHash(pPage);
pcache1FreePage(pPage);
}else{
- /* Add the page to the global LRU list. Normally, the page is added to
- ** the head of the list (last page to be recycled). However, if the
- ** reuseUnlikely flag passed to this function is true, the page is added
- ** to the tail of the list (first page to be recycled).
- */
- if( pcache1.pLruHead ){
- pcache1.pLruHead->pLruPrev = pPage;
- pPage->pLruNext = pcache1.pLruHead;
- pcache1.pLruHead = pPage;
+ /* Add the page to the PGroup LRU list. */
+ if( pGroup->pLruHead ){
+ pGroup->pLruHead->pLruPrev = pPage;
+ pPage->pLruNext = pGroup->pLruHead;
+ pGroup->pLruHead = pPage;
}else{
- pcache1.pLruTail = pPage;
- pcache1.pLruHead = pPage;
+ pGroup->pLruTail = pPage;
+ pGroup->pLruHead = pPage;
}
pCache->nRecyclable++;
}
- pcache1LeaveMutex();
+ pcache1LeaveMutex(pCache->pGroup);
}
/*
-** Implementation of the sqlite3_pcache.xRekey method.
+** Implementation of the sqlite3_pcache.xRekey method.
*/
static void pcache1Rekey(
sqlite3_pcache *p,
@@ -31635,11 +36842,11 @@ static void pcache1Rekey(
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = PAGE_TO_PGHDR1(pCache, pPg);
PgHdr1 **pp;
- unsigned int h;
+ unsigned int h;
assert( pPage->iKey==iOld );
assert( pPage->pCache==pCache );
- pcache1EnterMutex();
+ pcache1EnterMutex(pCache->pGroup);
h = iOld%pCache->nHash;
pp = &pCache->apHash[h];
@@ -31656,11 +36863,11 @@ static void pcache1Rekey(
pCache->iMaxKey = iNew;
}
- pcache1LeaveMutex();
+ pcache1LeaveMutex(pCache->pGroup);
}
/*
-** Implementation of the sqlite3_pcache.xTruncate method.
+** 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
@@ -31668,27 +36875,30 @@ static void pcache1Rekey(
*/
static void pcache1Truncate(sqlite3_pcache *p, unsigned int iLimit){
PCache1 *pCache = (PCache1 *)p;
- pcache1EnterMutex();
+ pcache1EnterMutex(pCache->pGroup);
if( iLimit<=pCache->iMaxKey ){
pcache1TruncateUnsafe(pCache, iLimit);
pCache->iMaxKey = iLimit-1;
}
- pcache1LeaveMutex();
+ pcache1LeaveMutex(pCache->pGroup);
}
/*
-** Implementation of the sqlite3_pcache.xDestroy method.
+** Implementation of the sqlite3_pcache.xDestroy method.
**
** Destroy a cache allocated using pcache1Create().
*/
static void pcache1Destroy(sqlite3_pcache *p){
PCache1 *pCache = (PCache1 *)p;
- pcache1EnterMutex();
+ PGroup *pGroup = pCache->pGroup;
+ assert( pCache->bPurgeable || (pCache->nMax==0 && pCache->nMin==0) );
+ pcache1EnterMutex(pGroup);
pcache1TruncateUnsafe(pCache, 0);
- pcache1.nMaxPage -= pCache->nMax;
- pcache1.nMinPage -= pCache->nMin;
- pcache1EnforceMaxPage();
- pcache1LeaveMutex();
+ pGroup->nMaxPage -= pCache->nMax;
+ pGroup->nMinPage -= pCache->nMin;
+ pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
+ pcache1EnforceMaxPage(pGroup);
+ pcache1LeaveMutex(pGroup);
sqlite3_free(pCache->apHash);
sqlite3_free(pCache);
}
@@ -31699,7 +36909,7 @@ static void pcache1Destroy(sqlite3_pcache *p){
** already provided an alternative.
*/
SQLITE_PRIVATE void sqlite3PCacheSetDefault(void){
- static sqlite3_pcache_methods defaultMethods = {
+ static const sqlite3_pcache_methods defaultMethods = {
0, /* pArg */
pcache1Init, /* xInit */
pcache1Shutdown, /* xShutdown */
@@ -31722,21 +36932,26 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void){
** 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
+** been released, the function returns. The return value is the total number
** of bytes of memory released.
*/
SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
int nFree = 0;
+#ifdef SQLITE_PAGECACHE_BLOCKALLOC
+ if( pcache1.grp.isBusy ) return 0;
+#endif
+ assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
+ assert( sqlite3_mutex_notheld(pcache1.mutex) );
if( pcache1.pStart==0 ){
PgHdr1 *p;
- pcache1EnterMutex();
- while( (nReq<0 || nFreepLruNext){
+ for(p=pcache1.grp.pLruHead; p; p=p->pLruNext){
nRecyclable++;
}
- *pnCurrent = pcache1.nCurrentPage;
- *pnMax = pcache1.nMaxPage;
- *pnMin = pcache1.nMinPage;
+ *pnCurrent = pcache1.grp.nCurrentPage;
+ *pnMax = pcache1.grp.nMaxPage;
+ *pnMin = pcache1.grp.nMinPage;
*pnRecyclable = nRecyclable;
}
#endif
@@ -31804,7 +37019,7 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
** extracts the least value from the RowSet.
**
** The INSERT primitive might allocate additional memory. Memory is
-** allocated in chunks so most INSERTs do no allocation. There is an
+** 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.
**
@@ -31845,7 +37060,7 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
/*
** Each entry in a RowSet is an instance of the following object.
*/
-struct RowSetEntry {
+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) */
@@ -31887,7 +37102,7 @@ struct RowSet {
**
** 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.
*/
@@ -31967,7 +37182,7 @@ SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){
/*
** Merge two lists of RowSetEntry objects. Remove duplicates.
**
-** The input lists are connected via pRight pointers and are
+** The input lists are connected via pRight pointers and are
** assumed to each already be in sorted order.
*/
static struct RowSetEntry *rowSetMerge(
@@ -32005,7 +37220,7 @@ static struct RowSetEntry *rowSetMerge(
/*
** Sort all elements on the pEntry list of the RowSet into ascending order.
-*/
+*/
static void rowSetSort(RowSet *p){
unsigned int i;
struct RowSetEntry *pEntry;
@@ -32145,7 +37360,7 @@ static void rowSetToList(RowSet *p){
** 0 if the RowSet is already empty.
**
** After this routine has been called, the sqlite3RowSetInsert()
-** routine may not be called again.
+** routine may not be called again.
*/
SQLITE_PRIVATE int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
rowSetToList(p);
@@ -32203,7 +37418,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 i
**
*************************************************************************
** 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
@@ -32212,6 +37427,219 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 i
** 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.
+*/
+
+#ifndef _WAL_H_
+#define _WAL_H_
+
+
+#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 sqlite3WalRead(v,w,x,y,z) 0
+# 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
+#else
+
+#define WAL_SAVEPOINT_NDATA 4
+
+/* Connection to a write-ahead log (WAL) file.
+** There is one object of this type for each pager.
+*/
+typedef struct Wal Wal;
+
+/* Open and close a connection to a write-ahead log. */
+SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**);
+SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
+
+/* Set the limiting size of a WAL file. */
+SQLITE_PRIVATE void sqlite3WalLimit(Wal*, i64);
+
+/* Used by readers to open (lock) and close (unlock) a snapshot. A
+** snapshot is like a read-transaction. It is the state of the database
+** at an instant in time. sqlite3WalOpenSnapshot gets a read lock and
+** preserves the current state even if the other threads or processes
+** write to or checkpoint the WAL. sqlite3WalCloseSnapshot() closes the
+** transaction and releases the lock.
+*/
+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);
+
+/* If the WAL is not empty, return the size of the database. */
+SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal);
+
+/* Obtain or release the WRITER lock. */
+SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal);
+SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal);
+
+/* Undo any frames written (but not committed) to the log */
+SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx);
+
+/* Return an integer that records the current (uncommitted) write
+** position in the WAL */
+SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData);
+
+/* Move the write position of the WAL back to iFrame. Called in
+** response to a ROLLBACK TO command. */
+SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData);
+
+/* Write a frame or frames to the log. */
+SQLITE_PRIVATE int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
+
+/* Copy pages from the log to the database file */
+SQLITE_PRIVATE int sqlite3WalCheckpoint(
+ Wal *pWal, /* Write-ahead log connection */
+ int eMode, /* One of PASSIVE, FULL and RESTART */
+ int (*xBusy)(void*), /* Function to call when busy */
+ void *pBusyArg, /* Context argument for xBusyHandler */
+ int sync_flags, /* Flags to sync db file with (or 0) */
+ int nBuf, /* Size of buffer nBuf */
+ u8 *zBuf, /* Temporary buffer to use */
+ int *pnLog, /* OUT: Number of frames in WAL */
+ int *pnCkpt /* OUT: Number of backfilled frames in WAL */
+);
+
+/* Return the value to pass to a sqlite3_wal_hook callback, the
+** number of frames in the WAL at the point of the last commit since
+** sqlite3WalCallback() was called. If no commits have occurred since
+** the last call, then return 0.
+*/
+SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal);
+
+/* 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);
+
+/* Return true if the argument is non-NULL and the WAL module is using
+** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
+** WAL module is using shared-memory, return false.
+*/
+SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal);
+
+#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 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.
+**
+******************************************************************************/
/*
** Macros for troubleshooting. Normally turned off
@@ -32226,7 +37654,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
/*
** The following two macros are used within the PAGERTRACE() macros above
-** to print out file-descriptors.
+** to print out file-descriptors.
**
** PAGERID() takes a pointer to a Pager struct as its argument. The
** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file
@@ -32236,58 +37664,279 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
#define FILEHANDLEID(fd) ((int)fd)
/*
-** The page cache as a whole is always in one of the following
-** states:
+** 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.
**
-** PAGER_UNLOCK The page cache is not currently reading or
-** writing the database file. There is no
-** data held in memory. This is the initial
-** state.
+** OPEN <------+------+
+** | | |
+** V | |
+** +---------> READER-------+ |
+** | | |
+** | V |
+** |<-------WRITER_LOCKED------> ERROR
+** | | ^
+** | V |
+** |<------WRITER_CACHEMOD-------->|
+** | | |
+** | V |
+** |<-------WRITER_DBMOD---------->|
+** | | |
+** | V |
+** +<------WRITER_FINISHED-------->+
**
-** PAGER_SHARED The page cache is reading the database.
-** Writing is not permitted. There can be
-** multiple readers accessing the same database
-** file at the same time.
**
-** PAGER_RESERVED This process has reserved the database for writing
-** but has not yet made any changes. Only one process
-** at a time can reserve the database. The original
-** database file has not been modified so other
-** processes may still be reading the on-disk
-** database file.
+** List of state transitions and the C [function] that performs each:
+**
+** OPEN -> READER [sqlite3PagerSharedLock]
+** READER -> OPEN [pager_unlock]
**
-** PAGER_EXCLUSIVE The page cache is writing the database.
-** Access is exclusive. No other processes or
-** threads can be reading or writing while one
-** process is writing.
+** 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]
**
-** PAGER_SYNCED The pager moves to this state from PAGER_EXCLUSIVE
-** after all dirty pages have been written to the
-** database file and the file has been synced to
-** disk. All that remains to do is to remove or
-** truncate the journal file and the transaction
-** will be committed.
+** WRITER_*** -> ERROR [pager_error]
+** ERROR -> OPEN [pager_unlock]
+**
**
-** The page cache comes up in PAGER_UNLOCK. The first time a
-** sqlite3PagerGet() occurs, the state transitions to PAGER_SHARED.
-** After all pages have been released using sqlite_page_unref(),
-** the state transitions back to PAGER_UNLOCK. The first time
-** that sqlite3PagerWrite() is called, the state transitions to
-** PAGER_RESERVED. (Note that sqlite3PagerWrite() can only be
-** called on an outstanding page which means that the pager must
-** be in PAGER_SHARED before it transitions to PAGER_RESERVED.)
-** PAGER_RESERVED means that there is an open rollback journal.
-** The transition to PAGER_EXCLUSIVE occurs before any changes
-** are made to the database file, though writes to the rollback
-** journal occurs with just PAGER_RESERVED. After an sqlite3PagerRollback()
-** or sqlite3PagerCommitPhaseTwo(), the state can go back to PAGER_SHARED,
-** or it can stay at PAGER_EXCLUSIVE if we are in exclusive access mode.
+** 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 occured, 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.
+**
+** * 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().
*/
-#define PAGER_UNLOCK 0
-#define PAGER_SHARED 1 /* same as SHARED_LOCK */
-#define PAGER_RESERVED 2 /* same as RESERVED_LOCK */
-#define PAGER_EXCLUSIVE 4 /* same as EXCLUSIVE_LOCK */
-#define PAGER_SYNCED 5
+#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.
+**
+** If the VFS xLock() or xUnlock() returns an error other than SQLITE_BUSY
+** (i.e. one of the SQLITE_IOERR subtypes), it is not clear whether or not
+** the operation was successful. In these circumstances pagerLockDb() and
+** pagerUnlockDb() take a conservative approach - eLock is always updated
+** when unlocking the file, and only updated when locking the file if the
+** VFS call is successful. This way, the Pager.eLock variable may be set
+** to a less exclusive (lower) value than the lock that is actually held
+** at the system level, but it is never set to a more exclusive value.
+**
+** This is usually safe. If an xUnlock fails or appears to fail, there may
+** be a few redundant xLock() calls or a lock may be held for longer than
+** required, but nothing really goes wrong.
+**
+** The exception is when the database file is unlocked as the pager moves
+** from ERROR to OPEN state. At this point there may be a hot-journal file
+** in the file-system that needs to be rolled back (as part of 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.
+*/
+#define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1)
/*
** A macro used for invoking the codec if there is one
@@ -32304,7 +37953,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
#endif
/*
-** The maximum allowed sector size. 64KiB. If the xSectorsize() method
+** 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.
@@ -32319,7 +37968,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
**
** 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
+** 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()).
@@ -32331,140 +37980,199 @@ struct PagerSavepoint {
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
};
/*
-** A open page cache is an instance of the following structure.
+** A open page cache is an instance of struct Pager. A description of
+** some of the more important member variables follows:
**
-** errCode
+** eState
**
-** Pager.errCode may be set to SQLITE_IOERR, SQLITE_CORRUPT, or
-** or SQLITE_FULL. Once one of the first three errors occurs, it persists
-** and is returned as the result of every major pager API call. The
-** SQLITE_FULL return code is slightly different. It persists only until the
-** next successful rollback is performed on the pager cache. Also,
-** SQLITE_FULL does not affect the sqlite3PagerGet() and sqlite3PagerLookup()
-** APIs, they may still be used successfully.
+** The current 'state' of the pager object. See the comment and state
+** diagram above for a description of the pager state.
**
-** dbSizeValid, dbSize, dbOrigSize, dbFileSize
+** eLock
**
-** Managing the size of the database file in pages is a little complicated.
-** The variable Pager.dbSize contains the number of pages that the database
-** image currently contains. As the database image grows or shrinks this
-** variable is updated. The variable Pager.dbFileSize contains the number
-** of pages in the database file. This may be different from Pager.dbSize
-** if some pages have been appended to the database image but not yet written
-** out from the cache to the actual file on disk. Or if the image has been
-** truncated by an incremental-vacuum operation. The Pager.dbOrigSize variable
-** contains the number of pages in the database image when the current
-** transaction was opened. The contents of all three of these variables is
-** only guaranteed to be correct if the boolean Pager.dbSizeValid is true.
+** For a real on-disk database, the current lock held on the database file -
+** NO_LOCK, SHARED_LOCK, RESERVED_LOCK or EXCLUSIVE_LOCK.
**
-** TODO: Under what conditions is dbSizeValid set? Cleared?
+** 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.
+** 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
+** 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
+** 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
+** This mechanism means that when running in exclusive mode, a connection
** need only update the change-counter once, for the first transaction
** committed.
**
-** dbModified
-**
-** The dbModified flag is set whenever a database page is dirtied.
-** It is cleared at the end of each transaction.
-**
-** It is used when committing or otherwise ending a transaction. If
-** the dbModified flag is clear then less work has to be done.
-**
-** journalStarted
-**
-** This flag is set whenever the the main journal is synced.
-**
-** The point of this flag is that it must be set after the
-** first journal header in a journal file has been synced to disk.
-** After this has happened, new pages appended to the database
-** do not need the PGHDR_NEED_SYNC flag set, as they do not need
-** to wait for a journal sync before they can be written out to
-** the database file (see function pager_write()).
-**
** setMaster
**
-** This variable is used to ensure that the master journal file name
-** (if any) is only written into the journal file once.
+** 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.
**
-** When committing a transaction, the master journal file name (if any)
-** may be written into the journal file while the pager is still in
-** PAGER_RESERVED state (see CommitPhaseOne() for the action). It
-** then attempts to upgrade to an exclusive lock. If this attempt
-** fails, then SQLITE_BUSY may be returned to the user and the user
-** may attempt to commit the transaction again later (calling
-** CommitPhaseOne() again). This flag is used to ensure that the
-** master journal name is only written to the journal file the first
-** time CommitPhaseOne() is called.
+** 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.
**
-** doNotSync
+** 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.
**
-** This variable is set and cleared by sqlite3PagerWrite().
+** 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).
**
-** needSync
+** doNotSpill, doNotSyncSpill
**
-** TODO: It might be easier to set this variable in writeJournalHdr()
-** and writeMasterJournal() only. Change its meaning to "unsynced data
-** has been written to the journal".
+** These two boolean variables control the behaviour 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.
*/
struct Pager {
sqlite3_vfs *pVfs; /* OS functions to use for IO */
u8 exclusiveMode; /* Boolean. True if locking_mode==EXCLUSIVE */
- u8 journalMode; /* On of the PAGER_JOURNALMODE_* values */
+ u8 journalMode; /* One of the PAGER_JOURNALMODE_* values */
u8 useJournal; /* Use a rollback journal on this file */
u8 noReadlock; /* Do not bother to obtain readlocks */
u8 noSync; /* Do not sync the journal if true */
u8 fullSync; /* Do extra syncs of the journal for robustness */
- u8 sync_flags; /* One of SYNC_NORMAL or SYNC_FULL */
+ u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */
+ 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 */
- /* The following block contains those class members that are dynamically
- ** modified during normal operations. The other variables in this structure
- ** are either constant throughout the lifetime of the pager, or else
- ** used to store configuration parameters that affect the way the pager
- ** operates.
- **
- ** The 'state' variable is described in more detail along with the
- ** descriptions of the values it may take - PAGER_UNLOCK etc. Many of the
- ** other variables in this block are described in the comment directly
- ** above this class definition.
+ /**************************************************************************
+ ** 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 state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */
- u8 dbModified; /* True if there are any changes to the Db */
- u8 needSync; /* True if an fsync() is needed on the journal */
- u8 journalStarted; /* True if header of journal is synced */
+ 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 doNotSync; /* Boolean. While true, do not spill the cache */
- u8 dbSizeValid; /* Set when dbSize is correct */
+ 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 */
@@ -32475,16 +38183,21 @@ struct Pager {
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 */
- u32 sectorSize; /* Assumed sector size during rollback */
+ /*
+ ** 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 */
@@ -32501,9 +38214,11 @@ struct Pager {
void *pCodec; /* First argument to xCodec... methods */
#endif
char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */
- i64 journalSizeLimit; /* Size limit for persistent journal files */
PCache *pPCache; /* Pointer to page cache object */
- sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */
+#ifndef SQLITE_OMIT_WAL
+ Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */
+ char *zWal; /* File name for write-ahead log */
+#endif
};
/*
@@ -32556,7 +38271,7 @@ static const unsigned char aJournalMagic[] = {
#define JOURNAL_PG_SZ(pPager) ((pPager->pageSize) + 8)
/*
-** The journal header size for this pager. This is usually the same
+** 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)
@@ -32578,22 +38293,223 @@ static const unsigned char aJournalMagic[] = {
*/
#define PAGER_MAX_PGNO 2147483647
-#ifndef NDEBUG
+/*
+** 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 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,z) 0
+# define pagerOpenWalIfPresent(z) SQLITE_OK
+# define pagerBeginReadTransaction(z) SQLITE_OK
+#endif
+
+#ifndef NDEBUG
/*
** Usage:
**
** assert( assert_pager_state(pPager) );
+**
+** This function runs many asserts to try to find inconsistencies in
+** the internal state of the Pager object.
*/
-static int assert_pager_state(Pager *pPager){
+static int assert_pager_state(Pager *p){
+ Pager *pPager = p;
- /* A temp-file is always in PAGER_EXCLUSIVE or PAGER_SYNCED state. */
- assert( pPager->tempFile==0 || pPager->state>=PAGER_EXCLUSIVE );
+ /* 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
+ );
- /* The changeCountDone flag is always set for temp-files */
- assert( pPager->tempFile==0 || pPager->changeCountDone );
+ /* 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 );
+
+ /* If the useJournal flag is clear, the journal-mode must be "OFF".
+ ** And if the journal-mode is "OFF", the journal file must not be open.
+ */
+ assert( p->journalMode==PAGER_JOURNALMODE_OFF || p->useJournal );
+ assert( p->journalMode!=PAGER_JOURNALMODE_OFF || !isOpen(p->jfd) );
+
+ /* Check that MEMDB implies noSync. And an in-memory journal. Since
+ ** this means an in-memory pager performs no IO at all, it cannot encounter
+ ** either SQLITE_IOERR or SQLITE_FULL during rollback or while finalizing
+ ** a journal file. (although the in-memory journal implementation may
+ ** return SQLITE_IOERR_NOMEM while the journal file is being written). It
+ ** is therefore not possible for an in-memory pager to enter the ERROR
+ ** state.
+ */
+ if( MEMDB ){
+ assert( p->noSync );
+ assert( p->journalMode==PAGER_JOURNALMODE_OFF
+ || p->journalMode==PAGER_JOURNALMODE_MEMORY
+ );
+ assert( p->eState!=PAGER_ERROR && p->eState!=PAGER_OPEN );
+ assert( pagerUseWal(p)==0 );
+ }
+
+ /* If changeCountDone is set, a RESERVED lock or greater must be held
+ ** on the file.
+ */
+ assert( pPager->changeCountDone==0 || pPager->eLock>=RESERVED_LOCK );
+ assert( p->eLock!=PENDING_LOCK );
+
+ switch( p->eState ){
+ case PAGER_OPEN:
+ assert( !MEMDB );
+ assert( pPager->errCode==SQLITE_OK );
+ assert( sqlite3PcacheRefCount(pPager->pPCache)==0 || pPager->tempFile );
+ break;
+
+ case PAGER_READER:
+ assert( pPager->errCode==SQLITE_OK );
+ assert( p->eLock!=UNKNOWN_LOCK );
+ assert( p->eLock>=SHARED_LOCK || p->noReadlock );
+ break;
+
+ case PAGER_WRITER_LOCKED:
+ assert( p->eLock!=UNKNOWN_LOCK );
+ assert( pPager->errCode==SQLITE_OK );
+ if( !pagerUseWal(pPager) ){
+ assert( p->eLock>=RESERVED_LOCK );
+ }
+ assert( pPager->dbSize==pPager->dbOrigSize );
+ assert( pPager->dbOrigSize==pPager->dbFileSize );
+ assert( pPager->dbOrigSize==pPager->dbHintSize );
+ assert( pPager->setMaster==0 );
+ break;
+
+ case PAGER_WRITER_CACHEMOD:
+ assert( p->eLock!=UNKNOWN_LOCK );
+ assert( pPager->errCode==SQLITE_OK );
+ if( !pagerUseWal(pPager) ){
+ /* It is possible that if journal_mode=wal here that neither the
+ ** journal file nor the WAL file are open. This happens during
+ ** a rollback transaction that switches from journal_mode=off
+ ** to journal_mode=wal.
+ */
+ assert( p->eLock>=RESERVED_LOCK );
+ assert( isOpen(p->jfd)
+ || p->journalMode==PAGER_JOURNALMODE_OFF
+ || p->journalMode==PAGER_JOURNALMODE_WAL
+ );
+ }
+ assert( pPager->dbOrigSize==pPager->dbFileSize );
+ assert( pPager->dbOrigSize==pPager->dbHintSize );
+ break;
+
+ case PAGER_WRITER_DBMOD:
+ assert( p->eLock==EXCLUSIVE_LOCK );
+ assert( pPager->errCode==SQLITE_OK );
+ assert( !pagerUseWal(pPager) );
+ assert( p->eLock>=EXCLUSIVE_LOCK );
+ assert( isOpen(p->jfd)
+ || p->journalMode==PAGER_JOURNALMODE_OFF
+ || p->journalMode==PAGER_JOURNALMODE_WAL
+ );
+ assert( pPager->dbOrigSize<=pPager->dbHintSize );
+ break;
+
+ case PAGER_WRITER_FINISHED:
+ assert( p->eLock==EXCLUSIVE_LOCK );
+ assert( pPager->errCode==SQLITE_OK );
+ assert( !pagerUseWal(pPager) );
+ assert( isOpen(p->jfd)
+ || p->journalMode==PAGER_JOURNALMODE_OFF
+ || p->journalMode==PAGER_JOURNALMODE_WAL
+ );
+ break;
+
+ case PAGER_ERROR:
+ /* There must be at least one outstanding reference to the pager if
+ ** in ERROR state. Otherwise the pager should have already dropped
+ ** back to OPEN state.
+ */
+ assert( pPager->errCode!=SQLITE_OK );
+ assert( sqlite3PcacheRefCount(pPager->pPCache)>0 );
+ break;
+ }
return 1;
}
+#endif /* ifndef NDEBUG */
+
+#ifdef SQLITE_DEBUG
+/*
+** Return a pointer to a human readable string in a static buffer
+** containing the state of the Pager object passed as an argument. This
+** is intended to be used within debuggers. For example, as an alternative
+** to "print *pPager" in gdb:
+**
+** (gdb) printf "%s", print_pager_state(pPager)
+*/
+static char *print_pager_state(Pager *p){
+ static char zRet[1024];
+
+ sqlite3_snprintf(1024, zRet,
+ "Filename: %s\n"
+ "State: %s errCode=%d\n"
+ "Lock: %s\n"
+ "Locking mode: locking_mode=%s\n"
+ "Journal mode: journal_mode=%s\n"
+ "Backing store: tempFile=%d memDb=%d useJournal=%d\n"
+ "Journal: journalOff=%lld journalHdr=%lld\n"
+ "Size: dbsize=%d dbOrigSize=%d dbFileSize=%d\n"
+ , p->zFilename
+ , p->eState==PAGER_OPEN ? "OPEN" :
+ p->eState==PAGER_READER ? "READER" :
+ p->eState==PAGER_WRITER_LOCKED ? "WRITER_LOCKED" :
+ p->eState==PAGER_WRITER_CACHEMOD ? "WRITER_CACHEMOD" :
+ p->eState==PAGER_WRITER_DBMOD ? "WRITER_DBMOD" :
+ p->eState==PAGER_WRITER_FINISHED ? "WRITER_FINISHED" :
+ p->eState==PAGER_ERROR ? "ERROR" : "?error?"
+ , (int)p->errCode
+ , p->eLock==NO_LOCK ? "NO_LOCK" :
+ p->eLock==RESERVED_LOCK ? "RESERVED" :
+ p->eLock==EXCLUSIVE_LOCK ? "EXCLUSIVE" :
+ p->eLock==SHARED_LOCK ? "SHARED" :
+ p->eLock==UNKNOWN_LOCK ? "UNKNOWN" : "?error?"
+ , p->exclusiveMode ? "exclusive" : "normal"
+ , p->journalMode==PAGER_JOURNALMODE_MEMORY ? "memory" :
+ p->journalMode==PAGER_JOURNALMODE_OFF ? "off" :
+ p->journalMode==PAGER_JOURNALMODE_DELETE ? "delete" :
+ p->journalMode==PAGER_JOURNALMODE_PERSIST ? "persist" :
+ p->journalMode==PAGER_JOURNALMODE_TRUNCATE ? "truncate" :
+ p->journalMode==PAGER_JOURNALMODE_WAL ? "wal" : "?error?"
+ , (int)p->tempFile, (int)p->memDb, (int)p->useJournal
+ , p->journalOff, p->journalHdr
+ , (int)p->dbSize, (int)p->dbOrigSize, (int)p->dbFileSize
+ );
+
+ return zRet;
+}
#endif
/*
@@ -32646,6 +38562,7 @@ static int read32bits(sqlite3_file *fd, i64 offset, u32 *pRes){
*/
#define put32bits(A,B) sqlite3Put4byte((u8*)A,B)
+
/*
** Write a 32-bit integer into the given file descriptor. Return SQLITE_OK
** on success or an error code is something goes wrong.
@@ -32657,27 +38574,53 @@ static int write32bits(sqlite3_file *fd, i64 offset, u32 val){
}
/*
-** 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.
+** 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.
**
-** This is so that expressions can be written as:
-**
-** if( isOpen(pPager->jfd) ){ ...
-**
-** instead of
-**
-** if( pPager->jfd->pMethods ){ ...
+** 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.
*/
-#define isOpen(pFd) ((pFd)->pMethods)
+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;
+}
/*
-** If file pFd is open, call sqlite3OsUnlock() on it.
+** Lock the database file to level eLock, which must be either SHARED_LOCK,
+** RESERVED_LOCK or EXCLUSIVE_LOCK. If the caller is successful, set the
+** Pager.eLock variable to the new locking state.
+**
+** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is
+** called, do not modify it unless the new locking state is EXCLUSIVE_LOCK.
+** See the comment above the #define of UNKNOWN_LOCK for an explanation
+** of this.
*/
-static int osUnlock(sqlite3_file *pFd, int eLock){
- if( !isOpen(pFd) ){
- return SQLITE_OK;
+static int pagerLockDb(Pager *pPager, int eLock){
+ int rc = SQLITE_OK;
+
+ assert( eLock==SHARED_LOCK || eLock==RESERVED_LOCK || eLock==EXCLUSIVE_LOCK );
+ if( pPager->eLockeLock==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 sqlite3OsUnlock(pFd, eLock);
+ return rc;
}
/*
@@ -32753,20 +38696,21 @@ static void pager_set_pagehash(PgHdr *pPage){
#define CHECK_PAGE(x) checkPage(x)
static void checkPage(PgHdr *pPg){
Pager *pPager = pPg->pPager;
- assert( !pPg->pageHash || pPager->errCode
- || (pPg->flags&PGHDR_DIRTY) || pPg->pageHash==pager_pagehash(pPg) );
+ 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 */
/*
** 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
+** 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.
**
@@ -32782,7 +38726,7 @@ static void checkPage(PgHdr *pPg){
** nul-terminator byte is appended to the buffer following the master
** journal file name.
**
-** If it is determined that no master journal file name is present
+** If it is determined that no master journal file name is present
** zMaster[0] is set to 0 and SQLITE_OK returned.
**
** If an error occurs while reading from the journal file, an SQLite
@@ -32800,7 +38744,7 @@ static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){
if( SQLITE_OK!=(rc = sqlite3OsFileSize(pJrnl, &szJ))
|| szJ<16
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len))
- || len>=nMaster
+ || len>=nMaster
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum))
|| SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8))
|| memcmp(aMagic, aJournalMagic, 8)
@@ -32822,13 +38766,13 @@ static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){
len = 0;
}
zMaster[len] = '\0';
-
+
return SQLITE_OK;
}
/*
-** Return the offset of the sector boundary at or immediately
-** following the value in pPager->journalOff, assuming a sector
+** 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:
@@ -32839,7 +38783,7 @@ static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){
** 512 512
** 100 512
** 2000 2048
-**
+**
*/
static i64 journalHdrOffset(Pager *pPager){
i64 offset = 0;
@@ -32861,12 +38805,12 @@ static i64 journalHdrOffset(Pager *pPager){
**
** 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
+** 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
+** 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.
@@ -32888,11 +38832,11 @@ static int zeroJournalHdr(Pager *pPager, int doTruncate){
rc = sqlite3OsWrite(pPager->jfd, zeroHdr, sizeof(zeroHdr), 0);
}
if( rc==SQLITE_OK && !pPager->noSync ){
- rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_DATAONLY|pPager->sync_flags);
+ 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
+ /* 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.
@@ -32920,13 +38864,13 @@ static int zeroJournalHdr(Pager *pPager, int doTruncate){
** - 4 bytes: Initial database page count.
** - 4 bytes: Sector size used by the process that wrote this journal.
** - 4 bytes: Database page size.
-**
+**
** Followed by (JOURNAL_HDR_SZ - 28) bytes of unused space.
*/
static int writeJournalHdr(Pager *pPager){
int rc = SQLITE_OK; /* Return code */
char *zHeader = pPager->pTmpSpace; /* Temporary space used to build header */
- u32 nHeader = pPager->pageSize; /* Size of buffer pointed to by zHeader */
+ u32 nHeader = (u32)pPager->pageSize;/* Size of buffer pointed to by zHeader */
u32 nWrite; /* Bytes of header sector written */
int ii; /* Loop counter */
@@ -32936,8 +38880,8 @@ static int writeJournalHdr(Pager *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
+ /* 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; iinSavepoint; ii++){
@@ -32948,10 +38892,10 @@ static int writeJournalHdr(Pager *pPager){
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,
+ ** 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()).
**
@@ -32969,8 +38913,8 @@ static int writeJournalHdr(Pager *pPager){
** 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)
+ 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);
@@ -32978,7 +38922,7 @@ static int writeJournalHdr(Pager *pPager){
memset(zHeader, 0, sizeof(aJournalMagic)+4);
}
- /* The random check-hash initialiser */
+ /* The random check-hash initialiser */
sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit);
/* The initial database size */
@@ -32997,26 +38941,27 @@ static int writeJournalHdr(Pager *pPager){
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
+ /* 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
+ ** 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
+ ** 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.
+ ** is done.
**
- ** The loop is required here in case the sector-size is larger than the
+ ** 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&&nWritejournalHdr, nHeader))
rc = sqlite3OsWrite(pPager->jfd, zHeader, nHeader, pPager->journalOff);
+ assert( pPager->journalHdr <= pPager->journalOff );
pPager->journalOff += nHeader;
}
@@ -33092,7 +39037,6 @@ static int readJournalHdr(
if( pPager->journalOff==0 ){
u32 iPageSize; /* Page-size field of journal header */
u32 iSectorSize; /* Sector-size field of journal header */
- u16 iPageSize16; /* Copy of iPageSize in 16-bit variable */
/* Read the page-size and sector-size journal header fields. */
if( SQLITE_OK!=(rc = read32bits(pPager->jfd, iHdrOff+20, &iSectorSize))
@@ -33101,33 +39045,39 @@ static int readJournalHdr(
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
+ ** 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
+ || ((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
+ /* 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
+ /* 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.
*/
- iPageSize16 = (u16)iPageSize;
- rc = sqlite3PagerSetPagesize(pPager, &iPageSize16, -1);
+ rc = sqlite3PagerSetPagesize(pPager, &iPageSize, -1);
testcase( rc!=SQLITE_OK );
- assert( rc!=SQLITE_OK || iPageSize16==(u16)iPageSize );
- /* Update the assumed sector-size to match the value used by
+ /* 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
@@ -33157,7 +39107,7 @@ static int readJournalHdr(
** 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),
+** 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){
@@ -33167,14 +39117,18 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
i64 jrnlSize; /* Size of journal file on disk */
u32 cksum = 0; /* Checksum of string zMaster */
- if( !zMaster || pPager->setMaster
- || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
- || pPager->journalMode==PAGER_JOURNALMODE_OFF
+ assert( pPager->setMaster==0 );
+ assert( !pagerUseWal(pPager) );
+
+ 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 );
/* Calculate the length in bytes and the checksum of zMaster */
for(nMaster=0; zMaster[nMaster]; nMaster++){
@@ -33202,18 +39156,17 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
return rc;
}
pPager->journalOff += (nMaster+20);
- pPager->needSync = !pPager->noSync;
- /* If the pager is in peristent-journal mode, then the physical
+ /* 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
+ ** 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.
+ ** 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
+ ** 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
){
@@ -33224,7 +39177,7 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
/*
** Find a page in the hash table given its page number. Return
-** a pointer to the page or NULL if the requested page is not
+** a pointer to the page or NULL if the requested page is not
** already in memory.
*/
static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
@@ -33238,17 +39191,11 @@ static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
}
/*
-** Unless the pager is in error-state, discard all in-memory pages. If
-** the pager is in error-state, then this call is a no-op.
-**
-** TODO: Why can we not reset the pager while in error state?
+** Discard the entire contents of the in-memory page-cache.
*/
static void pager_reset(Pager *pPager){
- if( SQLITE_OK==pPager->errCode ){
- sqlite3BackupRestart(pPager->pBackup);
- sqlite3PcacheClear(pPager->pPCache);
- pPager->dbSizeValid = 0;
- }
+ sqlite3BackupRestart(pPager->pBackup);
+ sqlite3PcacheClear(pPager->pPCache);
}
/*
@@ -33271,7 +39218,7 @@ static void releaseAllSavepoints(Pager *pPager){
}
/*
-** Set the bit number pgno in the PagerSavepoint.pInSavepoint
+** 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.
*/
@@ -33291,72 +39238,109 @@ static int addToSavepointBitvecs(Pager *pPager, Pgno pgno){
}
/*
-** Unlock the database file. This function is a no-op if the pager
-** is in exclusive mode.
+** 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 currently in error state, discard the contents of
-** the cache and reset the Pager structure internal state. If there is
-** an open journal-file, then the next time a shared-lock is obtained
-** on the pager file (by this or any other process), it will be
-** treated as a hot-journal and rolled back.
+** 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 void pager_unlock(Pager *pPager){
- if( !pPager->exclusiveMode ){
- int rc; /* Return code */
- /* Always 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( 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.
*/
- sqlite3OsClose(pPager->jfd);
- sqlite3BitvecDestroy(pPager->pInJournal);
- pPager->pInJournal = 0;
- releaseAllSavepoints(pPager);
-
- /* If the file is unlocked, somebody else might change it. The
- ** values stored in Pager.dbSize etc. might become invalid if
- ** this happens. TODO: Really, this doesn't need to be cleared
- ** until the change-counter check fails in PagerSharedLock().
- */
- pPager->dbSizeValid = 0;
-
- rc = osUnlock(pPager->fd, NO_LOCK);
- if( rc ){
- pPager->errCode = rc;
- }
- IOTRACE(("UNLOCK %p\n", pPager))
-
- /* If Pager.errCode is set, the contents of the pager cache cannot be
- ** trusted. Now that the pager file is unlocked, the contents of the
- ** cache can be discarded and the error code safely cleared.
- */
- if( pPager->errCode ){
- if( rc==SQLITE_OK ){
- pPager->errCode = SQLITE_OK;
- }
- pager_reset(pPager);
+ 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->state = PAGER_UNLOCK;
- pPager->dbModified = 0;
+ pPager->eState = PAGER_OPEN;
}
+
+ /* If Pager.errCode is set, the contents of the pager cache cannot be
+ ** trusted. Now that there are no outstanding references to the pager,
+ ** it can safely move back to PAGER_OPEN state. This happens in both
+ ** normal and exclusive-locking mode.
+ */
+ if( pPager->errCode ){
+ assert( !MEMDB );
+ pager_reset(pPager);
+ pPager->changeCountDone = pPager->tempFile;
+ pPager->eState = PAGER_OPEN;
+ pPager->errCode = SQLITE_OK;
+ }
+
+ pPager->journalOff = 0;
+ pPager->journalHdr = 0;
+ pPager->setMaster = 0;
}
/*
-** This function should be called when an IOERR, CORRUPT or FULL error
-** may have 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.
+** 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_IOERR, SQLITE_CORRUPT, or SQLITE_FULL
-** the error becomes persistent. Until the persisten error is cleared,
-** subsequent API calls on this Pager will immediately return the same
-** 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.
**
-** A persistent error indicates that the contents of the pager-cache
-** cannot be trusted. This state can be cleared by completely discarding
+** 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
@@ -33372,57 +39356,33 @@ static int pager_error(Pager *pPager, int rc){
);
if( rc2==SQLITE_FULL || rc2==SQLITE_IOERR ){
pPager->errCode = rc;
+ pPager->eState = PAGER_ERROR;
}
return rc;
}
/*
-** 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 clear the error 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 pagerUnlockAndRollback(Pager *pPager){
- if( pPager->errCode==SQLITE_OK && pPager->state>=PAGER_RESERVED ){
- sqlite3BeginBenignMalloc();
- sqlite3PagerRollback(pPager);
- sqlite3EndBenignMalloc();
- }
- pager_unlock(pPager);
-}
-
-/*
-** This routine ends a transaction. A transaction is usually ended by
-** either a COMMIT or a ROLLBACK operation. This routine may be called
+** 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.
-**
-** If the pager is in PAGER_SHARED or PAGER_UNLOCK state when this
-** routine is called, it is a no-op (returns SQLITE_OK).
+**
+** 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
+** 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
+** Journal file descriptor is simply closed. This destroys an
** in-memory journal.
**
** journalMode==TRUNCATE
@@ -33441,17 +39401,13 @@ static void pagerUnlockAndRollback(Pager *pPager){
** DELETE and the pager is in exclusive mode, the method described under
** journalMode==PERSIST is used instead.
**
-** After the journal is finalized, if running in non-exclusive mode, the
-** pager moves to PAGER_SHARED state (and downgrades the lock on the
-** database file accordingly).
-**
-** If the pager is running in exclusive mode and is in PAGER_SYNCED state,
-** it moves to PAGER_EXCLUSIVE. No locks are downgraded when running in
-** exclusive mode.
+** 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
+** 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
@@ -33462,13 +39418,29 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
int rc = SQLITE_OK; /* Error code from journal finalization operation */
int rc2 = SQLITE_OK; /* Error code from db file unlock operation */
- if( pPager->stateeState!=PAGER_ERROR );
+ if( pPager->eStateeLockjfd) || pPager->pInJournal==0 );
if( isOpen(pPager->jfd) ){
+ assert( !pagerUseWal(pPager) );
/* Finalize the journal file. */
if( sqlite3IsMemJournal(pPager->jfd) ){
@@ -33481,66 +39453,103 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
rc = sqlite3OsTruncate(pPager->jfd, 0);
}
pPager->journalOff = 0;
- pPager->journalStarted = 0;
- }else if( pPager->exclusiveMode
- || pPager->journalMode==PAGER_JOURNALMODE_PERSIST
+ }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST
+ || (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL)
){
rc = zeroJournalHdr(pPager, hasMaster);
- pager_error(pPager, rc);
pPager->journalOff = 0;
- pPager->journalStarted = 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. */
- assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE
- || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
+ ** the database file, it will do so using an in-memory journal.
+ */
+ assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE
+ || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
+ || pPager->journalMode==PAGER_JOURNALMODE_WAL
);
sqlite3OsClose(pPager->jfd);
if( !pPager->tempFile ){
rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
}
}
+ }
#ifdef SQLITE_CHECK_PAGES
- sqlite3PcacheIterateDirty(pPager->pPCache, pager_set_pagehash);
+ 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);
+ }
+ }
#endif
- sqlite3PcacheCleanAll(pPager->pPCache);
- sqlite3BitvecDestroy(pPager->pInJournal);
- pPager->pInJournal = 0;
- pPager->nRec = 0;
- }
-
- if( !pPager->exclusiveMode ){
- rc2 = osUnlock(pPager->fd, SHARED_LOCK);
- pPager->state = PAGER_SHARED;
- pPager->changeCountDone = 0;
- }else if( pPager->state==PAGER_SYNCED ){
- pPager->state = PAGER_EXCLUSIVE;
- }
- pPager->setMaster = 0;
- pPager->needSync = 0;
- pPager->dbModified = 0;
-
- /* TODO: Is this optimal? Why is the db size invalidated here
- ** when the database file is not unlocked? */
- pPager->dbOrigSize = 0;
+ sqlite3BitvecDestroy(pPager->pInJournal);
+ pPager->pInJournal = 0;
+ pPager->nRec = 0;
+ sqlite3PcacheCleanAll(pPager->pPCache);
sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize);
- if( !MEMDB ){
- pPager->dbSizeValid = 0;
+
+ 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 );
}
+ if( !pPager->exclusiveMode
+ && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
+ ){
+ rc2 = pagerUnlockDb(pPager, SHARED_LOCK);
+ pPager->changeCountDone = 0;
+ }
+ pPager->eState = PAGER_READER;
+ pPager->setMaster = 0;
return (rc==SQLITE_OK?rc2:rc);
}
+/*
+** Execute a rollback if a transaction is active and unlock the
+** database file.
+**
+** 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 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);
+ }
+ }
+ pager_unlock(pPager);
+}
+
/*
** Parameter aData must point to a buffer of pPager->pageSize bytes
-** of data. Compute and return a checksum based ont the contents of the
+** 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
+** 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.
@@ -33548,8 +39557,8 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
** 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.
+** 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.
@@ -33564,15 +39573,29 @@ static u32 pager_cksum(Pager *pPager, const u8 *aData){
return cksum;
}
+/*
+** Report the current page size and number of reserved bytes back
+** to the codec.
+*/
+#ifdef SQLITE_HAS_CODEC
+static void pagerReportSize(Pager *pPager){
+ if( pPager->xCodecSizeChng ){
+ pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize,
+ (int)pPager->nReserve);
+ }
+}
+#else
+# define pagerReportSize(X) /* No-op if we do not support a codec */
+#endif
+
/*
** Read a single page from either the journal file (if isMainJrnl==1) or
** from the sub-journal (if isMainJrnl==0) and playback that page.
** The page begins at offset *pOffset into the file. The *pOffset
** value is increased to the start of the next page in the journal.
**
-** The isMainJrnl flag is true if this is the main rollback journal and
-** false for the statement journal. The main rollback journal uses
-** checksums - the statement journal does not.
+** 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
@@ -33591,7 +39614,7 @@ static u32 pager_cksum(Pager *pPager, const u8 *aData){
** 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.
@@ -33604,11 +39627,10 @@ static u32 pager_cksum(Pager *pPager, const u8 *aData){
*/
static int pager_playback_one_page(
Pager *pPager, /* The pager being played back */
- int isMainJrnl, /* 1 -> main journal. 0 -> sub-journal. */
- int isUnsync, /* True if reading from unsynced main journal */
i64 *pOffset, /* Offset of record to playback */
- int isSavepnt, /* True for a savepoint rollback */
- Bitvec *pDone /* Bitvec of pages already played back */
+ 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 */
@@ -33616,6 +39638,7 @@ static int pager_playback_one_page(
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 */
@@ -33624,6 +39647,18 @@ static int pager_playback_one_page(
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.
@@ -33655,13 +39690,21 @@ static int pager_playback_one_page(
}
}
+ /* 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;
}
- assert( pPager->state==PAGER_RESERVED || pPager->state>=PAGER_EXCLUSIVE );
+ /* 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 RESERVED state, then there must be a copy of this
+ /* 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.
**
@@ -33672,8 +39715,11 @@ static int pager_playback_one_page(
** either. So the condition described in the above paragraph is not
** assert()able.
**
- ** If in EXCLUSIVE state, then we update the pager cache if it exists
- ** and the main file. The page is then marked not dirty.
+ ** 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.
@@ -33693,18 +39739,29 @@ static int pager_playback_one_page(
** 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.
*/
- pPg = pager_lookup(pPager, pgno);
+ 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( (pPager->state>=PAGER_EXCLUSIVE)
- && (pPg==0 || 0==(pPg->flags&PGHDR_NEED_SYNC))
- && isOpen(pPager->fd)
- && !isUnsync
+ 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;
@@ -33717,24 +39774,27 @@ static int pager_playback_one_page(
}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.
+ ** 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
+ ** 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
+ ** 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 );
- if( (rc = sqlite3PagerAcquire(pPager, pgno, &pPg, 1))!=SQLITE_OK ){
- return rc;
- }
+ 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);
}
@@ -33750,13 +39810,14 @@ static int pager_playback_one_page(
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
+ /* 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.
+ ** 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
+ ** 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
@@ -33768,11 +39829,11 @@ static int pager_playback_one_page(
** segment is synced. If a crash occurs during or following this,
** database corruption may ensue.
*/
+ assert( !pagerUseWal(pPager) );
sqlite3PcacheMakeClean(pPg);
}
-#ifdef SQLITE_CHECK_PAGES
- pPg->pageHash = pager_pagehash(pPg);
-#endif
+ pager_set_pagehash(pPg);
+
/* If this was page 1, then restore the value of Pager.dbFileVers.
** Do this before any decoding. */
if( pgno==1 ){
@@ -33792,26 +39853,26 @@ static int pager_playback_one_page(
** 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
+** 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
+** 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
+** 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
+** 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
+** * 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
@@ -33821,12 +39882,12 @@ static int pager_playback_one_page(
**
** 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
+** 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
+** a couple of kilobytes or so - potentially larger than the page
** size.
*/
static int pager_delmaster(Pager *pPager, const char *zMaster){
@@ -33836,6 +39897,9 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){
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.
@@ -33850,92 +39914,87 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){
}
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;
- if( nMasterJournal>0 ){
- char *zJournal;
- char *zMasterPtr = 0;
- int nMasterPtr = pVfs->mxPathname+1;
-
- /* Load the entire master journal file into space obtained from
- ** sqlite3_malloc() and pointed to by zMasterJournal.
- */
- zMasterJournal = sqlite3Malloc((int)nMasterJournal + nMasterPtr + 1);
- if( !zMasterJournal ){
- rc = SQLITE_NOMEM;
+ zJournal = zMasterJournal;
+ while( (zJournal-zMasterJournal)pageSize bytes). If the file
-** on disk is currently larger than nPage pages, then use the VFS
+** 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.
**
-** 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
+** 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 successful, return SQLITE_OK. If an IO error occurs while modifying
@@ -33943,16 +40002,28 @@ delmaster_out:
*/
static int pager_truncate(Pager *pPager, Pgno nPage){
int rc = SQLITE_OK;
- if( pPager->state>=PAGER_EXCLUSIVE && isOpen(pPager->fd) ){
+ 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 = pPager->pageSize*(i64)nPage;
+ newSize = szPage*(i64)nPage;
if( rc==SQLITE_OK && currentSize!=newSize ){
if( currentSize>newSize ){
rc = sqlite3OsTruncate(pPager->fd, newSize);
}else{
- rc = sqlite3OsWrite(pPager->fd, "", 1, newSize-1);
+ char *pTmp = pPager->pTmpSpace;
+ memset(pTmp, 0, szPage);
+ testcase( (newSize-szPage) < currentSize );
+ testcase( (newSize-szPage) == currentSize );
+ testcase( (newSize-szPage) > currentSize );
+ rc = sqlite3OsWrite(pPager->fd, pTmp, szPage, newSize-szPage);
}
if( rc==SQLITE_OK ){
pPager->dbFileSize = nPage;
@@ -33965,8 +40036,8 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
/*
** 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
+** 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.
@@ -33997,15 +40068,15 @@ static void setSectorSize(Pager *pPager){
/*
** Playback the journal and thus restore the database file to
-** the state it was in before we started making changes.
+** the state it was in before we started making changes.
**
-** The journal file format is as follows:
+** 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
+** (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.
@@ -34034,7 +40105,7 @@ static void setSectorSize(Pager *pPager){
** 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.
+** 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
@@ -34046,7 +40117,7 @@ static void setSectorSize(Pager *pPager){
** 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
+** 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
@@ -34068,7 +40139,7 @@ static int pager_playback(Pager *pPager, int isHot){
*/
assert( isOpen(pPager->jfd) );
rc = sqlite3OsFileSize(pPager->jfd, &szJ);
- if( rc!=SQLITE_OK || szJ==0 ){
+ if( rc!=SQLITE_OK ){
goto end_playback;
}
@@ -34095,20 +40166,18 @@ static int pager_playback(Pager *pPager, int isHot){
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.
+ /* This loop terminates either when a readJournalHdr() or
+ ** pager_playback_one_page() call returns SQLITE_DONE or an IO error
+ ** occurs.
*/
while( 1 ){
- int isUnsync = 0;
-
/* 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 of failed while writing it.
+ ** 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_OK ){
if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
}
@@ -34136,13 +40205,12 @@ static int pager_playback(Pager *pPager, int isHot){
** 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
+ ** 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));
- isUnsync = 1;
}
/* If this is the first header read from the journal, truncate the
@@ -34156,7 +40224,7 @@ static int pager_playback(Pager *pPager, int isHot){
pPager->dbSize = mxPg;
}
- /* Copy original pages out of the journal and back into the
+ /* Copy original pages out of the journal and back into the
** database file and/or page cache.
*/
for(u=0; ujournalOff,0,0);
+ rc = pager_playback_one_page(pPager,&pPager->journalOff,0,1,0);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
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
@@ -34195,10 +40271,10 @@ end_playback:
sqlite3OsFileControl(pPager->fd,SQLITE_FCNTL_DB_UNCHANGED,0)>=SQLITE_OK
);
- /* 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
+ /* 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
@@ -34211,8 +40287,10 @@ end_playback:
rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
testcase( rc!=SQLITE_OK );
}
- if( rc==SQLITE_OK && pPager->noSync==0 && pPager->state>=PAGER_EXCLUSIVE ){
- rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
+ 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');
@@ -34234,23 +40312,386 @@ end_playback:
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.
+**
+** If page 1 is read, then the value of Pager.dbFileVers[] is set to
+** the value read from the database file.
+**
+** If an IO error occurs, then the IO error is returned to the caller.
+** Otherwise, SQLITE_OK is returned.
+*/
+static int readDbPage(PgHdr *pPg){
+ 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 );
+ assert( isOpen(pPager->fd) );
+
+ if( NEVER(!isOpen(pPager->fd)) ){
+ assert( pPager->tempFile );
+ memset(pPg->pData, 0, pPager->pageSize);
+ return SQLITE_OK;
+ }
+
+ if( pagerUseWal(pPager) ){
+ /* Try to pull the page from the write-ahead log. */
+ rc = sqlite3WalRead(pPager->pWal, pgno, &isInWal, pgsz, pPg->pData);
+ }
+ if( rc==SQLITE_OK && !isInWal ){
+ i64 iOffset = (pgno-1)*(i64)pPager->pageSize;
+ rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset);
+ if( rc==SQLITE_IOERR_SHORT_READ ){
+ rc = SQLITE_OK;
+ }
+ }
+
+ if( pgno==1 ){
+ if( rc ){
+ /* If the read is unsuccessful, set the dbFileVers[] to something
+ ** that will never be a valid file version. dbFileVers[] is a copy
+ ** of bytes 24..39 of the database. Bytes 28..31 should always be
+ ** zero or the size of the database in page. Bytes 32..35 and 35..39
+ ** should be page numbers which are never 0xffffffff. So filling
+ ** pPager->dbFileVers[] with all 0xff bytes should suffice.
+ **
+ ** For an encrypted database, the situation is more complex: bytes
+ ** 24..39 of the database are white noise. But the probability of
+ ** white 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);
+
+ PAGER_INCR(sqlite3_pager_readdb_count);
+ PAGER_INCR(pPager->nRead);
+ IOTRACE(("PGIN %p %d\n", pPager, pgno));
+ PAGERTRACE(("FETCH %d page %d hash(%08x)\n",
+ PAGERID(pPager), pgno, pager_pagehash(pPg)));
+
+ return rc;
+}
+
+/*
+** 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.
+*/
+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);
+
+ /* 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
+/*
+** 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.
+*/
+static int pagerUndoCallback(void *pCtx, Pgno iPg){
+ int rc = SQLITE_OK;
+ Pager *pPager = (Pager *)pCtx;
+ PgHdr *pPg;
+
+ pPg = sqlite3PagerLookup(pPager, iPg);
+ if( pPg ){
+ if( sqlite3PcachePageRefcount(pPg)==1 ){
+ sqlite3PcacheDrop(pPg);
+ }else{
+ rc = readDbPage(pPg);
+ 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.
+ */
+ sqlite3BackupRestart(pPager->pBackup);
+
+ return rc;
+}
+
+/*
+** This function is called to rollback a transaction on a WAL database.
+*/
+static int pagerRollbackWal(Pager *pPager){
+ int rc; /* Return Code */
+ PgHdr *pList; /* List of dirty pages to revert */
+
+ /* 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;
+ }
+
+ return rc;
+}
+
+/*
+** This function is a wrapper around sqlite3WalFrames(). As well as logging
+** the contents of the list of pages headed by pList (connected by pDirty),
+** this function notifies any active backup processes that the pages have
+** changed.
+**
+** The 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 syncFlags /* Flags to pass to OsSync() (or 0) */
+){
+ int rc; /* Return code */
+#if defined(SQLITE_DEBUG) || defined(SQLITE_CHECK_PAGES)
+ PgHdr *p; /* For looping over pages */
+#endif
+
+ assert( pPager->pWal );
+#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( 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;
+ for(p=pList; (*ppNext = p); p=p->pDirty){
+ if( p->pgno<=nTruncate ) ppNext = &p->pDirty;
+ }
+ assert( pList );
+ }
+
+ if( pList->pgno==1 ) pager_write_changecounter(pList);
+ rc = sqlite3WalFrames(pPager->pWal,
+ pPager->pageSize, pList, nTruncate, isCommit, syncFlags
+ );
+ if( rc==SQLITE_OK && pPager->pBackup ){
+ PgHdr *p;
+ for(p=pList; p; p=p->pDirty){
+ sqlite3BackupUpdate(pPager->pBackup, p->pgno, (u8 *)p->pData);
+ }
+ }
+
+#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 routine used to be called "pagerOpenSnapshot()" because it essentially
+** makes a snapshot of the database at the current point in time and preserves
+** that snapshot for use by the reader in spite of concurrently changes by
+** other writers or checkpointers.
+*/
+static int pagerBeginReadTransaction(Pager *pPager){
+ int rc; /* Return code */
+ int changed = 0; /* True if cache must be reset */
+
+ 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);
+ }
+
+ return rc;
+}
+#endif
+
+/*
+** This function is called as part of the transition from PAGER_OPEN
+** to PAGER_READER state to determine the size of the database file
+** in pages (assuming the page size currently stored in Pager.pageSize).
+**
+** 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 */
+
+ /* 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 || pPager->noReadlock );
+ nPage = sqlite3WalDbsize(pPager->pWal);
+
+ /* 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);
+ if( nPage==0 && n>0 ){
+ nPage = 1;
+ }
+ }
+
+ /* 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;
+ }
+
+ *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.
+**
+** 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 pagerOpenWalIfPresent(Pager *pPager){
+ int rc = SQLITE_OK;
+ assert( pPager->eState==PAGER_OPEN );
+ assert( pPager->eLock>=SHARED_LOCK || pPager->noReadlock );
+
+ 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);
+ 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;
+ }
+ }
+ }
+ return rc;
+}
+#endif
+
/*
** Playback savepoint pSavepoint. Or, if pSavepoint==NULL, then playback
-** the entire master journal file. The case pSavepoint==NULL occurs when
-** a ROLLBACK TO command is invoked on a SAVEPOINT that is a transaction
+** the entire master journal file. The case pSavepoint==NULL occurs when
+** a ROLLBACK TO command is invoked on a SAVEPOINT that is a transaction
** savepoint.
**
-** When pSavepoint is not NULL (meaning a non-transaction savepoint is
+** When pSavepoint is not NULL (meaning a non-transaction savepoint is
** being rolled back), then the rollback consists of up to three stages,
** performed in the order specified:
**
** * Pages are played back from the main journal starting at byte
-** offset PagerSavepoint.iOffset and continuing to
+** offset PagerSavepoint.iOffset and continuing to
** PagerSavepoint.iHdrOffset, or to the end of the main journal
** file if PagerSavepoint.iHdrOffset is zero.
**
** * If PagerSavepoint.iHdrOffset is not zero, then pages are played
-** back starting from the journal header immediately following
+** back starting from the journal header immediately following
** PagerSavepoint.iHdrOffset to the end of the main journal file.
**
** * Pages are then played back from the sub-journal file, starting
@@ -34266,7 +40707,7 @@ end_playback:
** 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
+** 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.
*/
@@ -34276,7 +40717,8 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
int rc = SQLITE_OK; /* Return code */
Bitvec *pDone = 0; /* Bitvec to ensure pages played back only once */
- assert( pPager->state>=PAGER_SHARED );
+ 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 ){
@@ -34286,10 +40728,15 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
}
}
- /* Set the database size back to the value it was before the savepoint
+ /* Set the database size back to the value it was before the savepoint
** being reverted was opened.
*/
pPager->dbSize = pSavepoint ? pSavepoint->nOrig : pPager->dbOrigSize;
+ pPager->changeCountDone = pPager->tempFile;
+
+ if( !pSavepoint && pagerUseWal(pPager) ){
+ return pagerRollbackWal(pPager);
+ }
/* Use pPager->journalOff as the effective size of the main rollback
** journal. The actual file might be larger than this in
@@ -34297,6 +40744,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
** past pPager->journalOff is off-limits to us.
*/
szJ = pPager->journalOff;
+ assert( pagerUseWal(pPager)==0 || szJ==0 );
/* Begin by rolling back records from the main journal starting at
** PagerSavepoint.iOffset and continuing to the next journal header.
@@ -34305,11 +40753,11 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
** will be skipped automatically. Pages are added to pDone as they
** are played back.
*/
- if( pSavepoint ){
+ if( pSavepoint && !pagerUseWal(pPager) ){
iHdrOff = pSavepoint->iHdrOffset ? pSavepoint->iHdrOffset : szJ;
pPager->journalOff = pSavepoint->iOffset;
while( rc==SQLITE_OK && pPager->journalOffjournalOff, 1, pDone);
+ rc = pager_playback_one_page(pPager, &pPager->journalOff, pDone, 1, 1);
}
assert( rc!=SQLITE_DONE );
}else{
@@ -34333,17 +40781,17 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
** test is related to ticket #2565. See the discussion in the
** pager_playback() function for additional information.
*/
- if( nJRec==0
+ 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 && iijournalOffjournalOff, 1, pDone);
+ rc = pager_playback_one_page(pPager, &pPager->journalOff, pDone, 1, 1);
}
assert( rc!=SQLITE_DONE );
}
- assert( rc!=SQLITE_OK || pPager->journalOff==szJ );
+ assert( rc!=SQLITE_OK || pPager->journalOff>=szJ );
/* Finally, rollback pages from the sub-journal. Page that were
** previously rolled back out of the main journal (and are hence in pDone)
@@ -34352,9 +40800,13 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
if( pSavepoint ){
u32 ii; /* Loop counter */
i64 offset = pSavepoint->iSubRec*(4+pPager->pageSize);
+
+ if( pagerUseWal(pPager) ){
+ rc = sqlite3WalSavepointUndo(pPager->pWal, pSavepoint->aWalData);
+ }
for(ii=pSavepoint->iSubRec; rc==SQLITE_OK && iinSubRec; ii++){
assert( offset==ii*(4+pPager->pageSize) );
- rc = pager_playback_one_page(pPager, 0, 0, &offset, 1, pDone);
+ rc = pager_playback_one_page(pPager, &offset, pDone, 0, 1);
}
assert( rc!=SQLITE_DONE );
}
@@ -34363,6 +40815,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
if( rc==SQLITE_OK ){
pPager->journalOff = szJ;
}
+
return rc;
}
@@ -34396,22 +40849,56 @@ SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){
** 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, int level, int bFullFsync){
+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;
- pPager->sync_flags = (bFullFsync?SQLITE_SYNC_FULL:SQLITE_SYNC_NORMAL);
- if( pPager->noSync ) pPager->needSync = 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;
+ }
}
#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.
+** testing and analysis only.
*/
#ifdef SQLITE_TEST
SQLITE_API int sqlite3_opentemp_count = 0;
@@ -34420,8 +40907,8 @@ SQLITE_API int sqlite3_opentemp_count = 0;
/*
** 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
+** 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
@@ -34453,9 +40940,9 @@ static int pagerOpentemp(
/*
** Set the busy handler function.
**
-** The pager invokes the busy-handler if sqlite3OsLock() returns
+** 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
+** 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:
@@ -34467,7 +40954,7 @@ static int pagerOpentemp(
** SHARED_LOCK -> EXCLUSIVE_LOCK | No
** RESERVED_LOCK -> EXCLUSIVE_LOCK | Yes
**
-** If the busy-handler callback returns non-zero, the lock is
+** 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.
*/
@@ -34475,37 +40962,22 @@ 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;
}
/*
-** Report the current page size and number of reserved bytes back
-** to the codec.
-*/
-#ifdef SQLITE_HAS_CODEC
-static void pagerReportSize(Pager *pPager){
- if( pPager->xCodecSizeChng ){
- pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize,
- (int)pPager->nReserve);
- }
-}
-#else
-# define pagerReportSize(X) /* No-op if we do not support a codec */
-#endif
-
-/*
-** Change the page size used by the Pager object. The new page size
+** Change the page size used by the Pager object. The new page size
** is passed in *pPageSize.
**
** 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, SQLITE_CORRUPT or SQLITE_FULL).
+** 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).
**
** Otherwise, if all of the following are true:
**
-** * the new page size (value of *pPageSize) is valid (a power
+** * the new page size (value of *pPageSize) is valid (a power
** of two between 512 and SQLITE_MAX_PAGE_SIZE, inclusive), and
**
** * there are no outstanding page references, and
@@ -34515,38 +40987,58 @@ static void pagerReportSize(Pager *pPager){
**
** 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.
+** 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,
+** function was called, or because the memory allocation attempt failed,
** then *pPageSize is set to the old, retained page size before returning.
*/
-SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u16 *pPageSize, int nReserve){
- int rc = pPager->errCode;
+SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){
+ int rc = SQLITE_OK;
- if( rc==SQLITE_OK ){
- u16 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!=pPager->pageSize
- ){
- char *pNew = (char *)sqlite3PageMalloc(pageSize);
- if( !pNew ){
- rc = SQLITE_NOMEM;
- }else{
- pager_reset(pPager);
- pPager->pageSize = pageSize;
- sqlite3PageFree(pPager->pTmpSpace);
- pPager->pTmpSpace = pNew;
- sqlite3PcacheSetPageSize(pPager->pPCache, pageSize);
- }
+ /* 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.
+ */
+
+ 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;
+
+ if( pPager->eState>PAGER_OPEN && isOpen(pPager->fd) ){
+ rc = sqlite3OsFileSize(pPager->fd, &nByte);
}
- *pPageSize = (u16)pPager->pageSize;
+ 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);
+ pPager->pageSize = pageSize;
+ sqlite3PageFree(pPager->pTmpSpace);
+ pPager->pTmpSpace = pNew;
+ sqlite3PcacheSetPageSize(pPager->pPCache, pageSize);
+ }
+ }
+
+ *pPageSize = pPager->pageSize;
+ if( rc==SQLITE_OK ){
if( nReserve<0 ) nReserve = pPager->nReserve;
assert( nReserve>=0 && nReserve<1000 );
pPager->nReserve = (i16)nReserve;
@@ -34568,7 +41060,7 @@ SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager *pPager){
}
/*
-** Attempt to set the maximum database page count if mxPage is positive.
+** 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.
**
@@ -34578,7 +41070,8 @@ SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
if( mxPage>0 ){
pPager->mxPgno = mxPage;
}
- sqlite3PagerPagecount(pPager, 0);
+ assert( pPager->eState!=PAGER_OPEN ); /* Called only by OP_MaxPgcnt */
+ assert( pPager->mxPgno>=pPager->dbSize ); /* OP_MaxPgcnt enforces this */
return pPager->mxPgno;
}
@@ -34608,11 +41101,11 @@ void enable_simulated_io_errors(void){
/*
** Read the first N bytes from the beginning of the file into memory
-** that pDest points to.
+** 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
+** 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.
**
@@ -34624,6 +41117,13 @@ SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned cha
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);
@@ -34635,65 +41135,16 @@ SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned cha
}
/*
-** Return the total number of pages in the database file associated
-** with pPager. Normally, this is calculated as (/).
-** However, if the file is between 1 and bytes in size, then
+** 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 bytes in size, then
** this is considered a 1 page file.
-**
-** If the pager is in error state when this function is called, then the
-** error state error code is returned and *pnPage left unchanged. Or,
-** if the file system has to be queried for the size of the file and
-** the query attempt returns an IO error, the IO error code is returned
-** and *pnPage is left unchanged.
-**
-** Otherwise, if everything is successful, then SQLITE_OK is returned
-** and *pnPage is set to the number of pages in the database.
*/
-SQLITE_PRIVATE int sqlite3PagerPagecount(Pager *pPager, int *pnPage){
- Pgno nPage; /* Value to return via *pnPage */
-
- /* If the pager is already in the error state, return the error code. */
- if( pPager->errCode ){
- return pPager->errCode;
- }
-
- /* Determine the number of pages in the file. Store this in nPage. */
- if( pPager->dbSizeValid ){
- nPage = pPager->dbSize;
- }else{
- int rc; /* Error returned by OsFileSize() */
- i64 n = 0; /* File size in bytes returned by OsFileSize() */
-
- assert( isOpen(pPager->fd) || pPager->tempFile );
- if( isOpen(pPager->fd) && (0 != (rc = sqlite3OsFileSize(pPager->fd, &n))) ){
- pager_error(pPager, rc);
- return rc;
- }
- if( n>0 && npageSize ){
- nPage = 1;
- }else{
- nPage = (Pgno)(n / pPager->pageSize);
- }
- if( pPager->state!=PAGER_UNLOCK ){
- pPager->dbSize = nPage;
- pPager->dbFileSize = nPage;
- pPager->dbSizeValid = 1;
- }
- }
-
- /* 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;
- }
-
- /* Set the output variable and return SQLITE_OK */
- if( pnPage ){
- *pnPage = nPage;
- }
- return SQLITE_OK;
+SQLITE_PRIVATE void sqlite3PagerPagecount(Pager *pPager, int *pnPage){
+ assert( pPager->eState>=PAGER_READER );
+ assert( pPager->eState!=PAGER_WRITER_FINISHED );
+ *pnPage = (int)pPager->dbSize;
}
@@ -34702,58 +41153,39 @@ SQLITE_PRIVATE int sqlite3PagerPagecount(Pager *pPager, int *pnPage){
** a similar or greater lock is already held, this function is a no-op
** (returning SQLITE_OK immediately).
**
-** Otherwise, attempt to obtain the lock using sqlite3OsLock(). Invoke
-** the busy callback if the lock is currently not available. Repeat
-** until the busy callback returns false or until the attempt to
+** Otherwise, attempt to obtain the lock using sqlite3OsLock(). Invoke
+** the busy callback if the lock is currently not available. Repeat
+** until the busy callback returns false or until the attempt to
** obtain the lock succeeds.
**
** Return SQLITE_OK on success and an error code if we cannot obtain
-** the lock. If the lock is obtained successfully, set the Pager.state
+** the lock. If the lock is obtained successfully, set the Pager.state
** variable to locktype before returning.
*/
static int pager_wait_on_lock(Pager *pPager, int locktype){
int rc; /* Return code */
- /* The OS lock values must be the same as the Pager lock values */
- assert( PAGER_SHARED==SHARED_LOCK );
- assert( PAGER_RESERVED==RESERVED_LOCK );
- assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK );
-
- /* If the file is currently unlocked then the size must be unknown. It
- ** must not have been modified at this point.
- */
- assert( pPager->state>=PAGER_SHARED || pPager->dbSizeValid==0 );
- assert( pPager->state>=PAGER_SHARED || pPager->dbModified==0 );
-
- /* Check that this is either a no-op (because the requested lock is
+ /* 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->state>=locktype)
- || (pPager->state==PAGER_UNLOCK && locktype==PAGER_SHARED)
- || (pPager->state==PAGER_RESERVED && locktype==PAGER_EXCLUSIVE)
+ assert( (pPager->eLock>=locktype)
+ || (pPager->eLock==NO_LOCK && locktype==SHARED_LOCK)
+ || (pPager->eLock==RESERVED_LOCK && locktype==EXCLUSIVE_LOCK)
);
- if( pPager->state>=locktype ){
- rc = SQLITE_OK;
- }else{
- do {
- rc = sqlite3OsLock(pPager->fd, locktype);
- }while( rc==SQLITE_BUSY && pPager->xBusyHandler(pPager->pBusyHandlerArg) );
- if( rc==SQLITE_OK ){
- pPager->state = (u8)locktype;
- IOTRACE(("LOCK %p %d\n", pPager, locktype))
- }
- }
+ do {
+ rc = pagerLockDb(pPager, locktype);
+ }while( rc==SQLITE_BUSY && pPager->xBusyHandler(pPager->pBusyHandlerArg) );
return rc;
}
/*
-** Function assertTruncateConstraint(pPager) checks that one of the
+** 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
+** 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
@@ -34766,9 +41198,9 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
** the database file. If a savepoint transaction were rolled back after
** this happened, the correct behaviour 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
+** 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
+** database image would become corrupt. It is therefore fortunate that
** this circumstance cannot arise.
*/
#if defined(SQLITE_DEBUG)
@@ -34784,19 +41216,44 @@ static void assertTruncateConstraint(Pager *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
+** 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.
*/
SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){
- assert( pPager->dbSizeValid );
assert( pPager->dbSize>=nPage );
- assert( pPager->state>=PAGER_RESERVED );
+ assert( pPager->eState>=PAGER_WRITER_CACHEMOD );
pPager->dbSize = nPage;
assertTruncateConstraint(pPager);
}
+
+/*
+** 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;
+}
+
/*
** Shutdown the page cache. Free all memory and close all files.
**
@@ -34807,34 +41264,49 @@ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){
** 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
+** 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;
+
+ assert( assert_pager_state(pPager) );
disable_simulated_io_errors();
sqlite3BeginBenignMalloc();
- pPager->errCode = 0;
+ /* pPager->errCode = 0; */
pPager->exclusiveMode = 0;
+#ifndef SQLITE_OMIT_WAL
+ sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, pTmp);
+ pPager->pWal = 0;
+#endif
pager_reset(pPager);
if( MEMDB ){
pager_unlock(pPager);
}else{
- /* Set Pager.journalHdr to -1 for the benefit of the pager_playback()
- ** call which may be made from within pagerUnlockAndRollback(). If it
- ** is not -1, then the unsynced portion of an open journal file may
- ** be played back into the database. If a power failure occurs while
- ** this is happening, the database may become corrupt.
+ /* 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.
*/
- pPager->journalHdr = -1;
+ if( isOpen(pPager->jfd) ){
+ pager_error(pPager, pagerSyncHotJournal(pPager));
+ }
pagerUnlockAndRollback(pPager);
}
sqlite3EndBenignMalloc();
enable_simulated_io_errors();
PAGERTRACE(("CLOSE %d\n", PAGERID(pPager)));
IOTRACE(("CLOSE %p\n", pPager))
+ sqlite3OsClose(pPager->jfd);
sqlite3OsClose(pPager->fd);
- sqlite3PageFree(pPager->pTmpSpace);
+ sqlite3PageFree(pTmp);
sqlite3PcacheClose(pPager->pPCache);
#ifdef SQLITE_HAS_CODEC
@@ -34869,9 +41341,9 @@ SQLITE_PRIVATE void sqlite3PagerRef(DbPage *pPg){
** 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.needSync flag is not set, then this function is a
-** no-op. Otherwise, the actions required depend on the journal-mode
-** and the device characteristics of the the file-system, as follows:
+** 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 the file-system, as follows:
**
** * If the journal file is an in-memory journal file, no action need
** be taken.
@@ -34882,7 +41354,7 @@ SQLITE_PRIVATE void sqlite3PagerRef(DbPage *pPg){
** 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
+** * If the device does not support the SEQUENTIAL property, then
** journal file is synced.
**
** Or, in pseudo-code:
@@ -34891,22 +41363,29 @@ SQLITE_PRIVATE void sqlite3PagerRef(DbPage *pPg){
** if( NOT SAFE_APPEND ){
** if( ) xSync();
**
-** }
+** }
** if( NOT SEQUENTIAL ) xSync();
** }
**
-** The Pager.needSync flag is never be set for temporary files, or any
-** file operating in no-sync mode (Pager.noSync set to non-zero).
-**
-** If successful, this routine clears the PGHDR_NEED_SYNC flag of every
+** If successful, this routine clears the PGHDR_NEED_SYNC flag of every
** page currently held in memory before returning SQLITE_OK. If an IO
** error is encountered, then the IO error code is returned to the caller.
*/
-static int syncJournal(Pager *pPager){
- if( pPager->needSync ){
+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( pPager->journalMode!=PAGER_JOURNALMODE_MEMORY ){
- int rc; /* Return code */
+ if( isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_MEMORY ){
const int iDc = sqlite3OsDeviceCharacteristics(pPager->fd);
assert( isOpen(pPager->jfd) );
@@ -34916,10 +41395,10 @@ static int syncJournal(Pager *pPager){
** 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 connections 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
+ ** 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.
@@ -34929,16 +41408,16 @@ static int syncJournal(Pager *pPager){
** 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
+ ** 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];
+ u8 zHeader[sizeof(aJournalMagic)+4];
- memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic));
- put32bits(&zHeader[sizeof(aJournalMagic)], pPager->nRec);
+ memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic));
+ put32bits(&zHeader[sizeof(aJournalMagic)], pPager->nRec);
iNextHdrOffset = journalHdrOffset(pPager);
rc = sqlite3OsRead(pPager->jfd, aMagic, 8, iNextHdrOffset);
@@ -34956,7 +41435,7 @@ static int syncJournal(Pager *pPager){
** 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
+ ** 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.
@@ -34964,33 +41443,42 @@ static int syncJournal(Pager *pPager){
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->sync_flags);
+ 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->sync_flags|
- (pPager->sync_flags==SQLITE_SYNC_FULL?SQLITE_SYNC_DATAONLY:0)
+ rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags|
+ (pPager->syncFlags==SQLITE_SYNC_FULL?SQLITE_SYNC_DATAONLY:0)
);
if( rc!=SQLITE_OK ) return rc;
}
- }
- /* The journal file was just successfully synced. Set Pager.needSync
- ** to zero and clear the PGHDR_NEED_SYNC flag on all pagess.
- */
- pPager->needSync = 0;
- pPager->journalStarted = 1;
- sqlite3PcacheClearSyncFlags(pPager->pPCache);
+ 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;
+ }
}
+ /* 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;
}
@@ -35005,9 +41493,9 @@ static int syncJournal(Pager *pPager){
** 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
+** 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,
@@ -35022,35 +41510,17 @@ static int syncJournal(Pager *pPager){
** 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
+** 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(PgHdr *pList){
- Pager *pPager; /* Pager object */
- int rc; /* Return code */
+static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
+ int rc = SQLITE_OK; /* Return code */
- if( NEVER(pList==0) ) return SQLITE_OK;
- pPager = pList->pPager;
-
- /* At this point there may be either a RESERVED or EXCLUSIVE lock on the
- ** database file. If there is already an EXCLUSIVE lock, the following
- ** call is a no-op.
- **
- ** Moving the lock from RESERVED to EXCLUSIVE actually involves going
- ** through an intermediate state PENDING. A PENDING lock prevents new
- ** readers from attaching to the database but is unsufficient for us to
- ** write. The idea of a PENDING lock is to prevent new readers from
- ** coming in while we wait for existing readers to clear.
- **
- ** While the pager is in the RESERVED state, the original database file
- ** is unchanged and we can rollback without having to playback the
- ** journal into the original database file. Once we transition to
- ** EXCLUSIVE, it means the database file has been changed and any rollback
- ** will require a journal playback.
- */
- assert( pPager->state>=PAGER_RESERVED );
- rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
+ /* 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
@@ -35061,6 +41531,16 @@ static int pager_write_pagelist(PgHdr *pList){
rc = pagerOpentemp(pPager, pPager->fd, pPager->vfsFlags);
}
+ /* Before the first write, give the VFS a hint of what the final
+ ** file size will be.
+ */
+ assert( rc!=SQLITE_OK || isOpen(pPager->fd) );
+ if( rc==SQLITE_OK && pPager->dbSize>pPager->dbHintSize ){
+ sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize;
+ sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile);
+ pPager->dbHintSize = pPager->dbSize;
+ }
+
while( rc==SQLITE_OK && pList ){
Pgno pgno = pList->pgno;
@@ -35074,7 +41554,10 @@ static int pager_write_pagelist(PgHdr *pList){
*/
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 */
+ char *pData; /* Data to write */
+
+ assert( (pList->flags&PGHDR_NEED_SYNC)==0 );
+ if( pList->pgno==1 ) pager_write_changecounter(pList);
/* Encode the database */
CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData);
@@ -35083,8 +41566,8 @@ static int pager_write_pagelist(PgHdr *pList){
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.
+ ** 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));
@@ -35104,9 +41587,7 @@ static int pager_write_pagelist(PgHdr *pList){
}else{
PAGERTRACE(("NOSTORE %d page %d\n", PAGERID(pPager), pgno));
}
-#ifdef SQLITE_CHECK_PAGES
- pList->pageHash = pager_pagehash(pList);
-#endif
+ pager_set_pagehash(pList);
pList = pList->pDirty;
}
@@ -35114,33 +41595,66 @@ static int pager_write_pagelist(PgHdr *pList){
}
/*
-** Append a record of the current state of page pPg to the sub-journal.
-** It is the callers responsibility to use subjRequiresPage() to check
+** Ensure that the sub-journal file is open. If it is already open, this
+** function is a no-op.
+**
+** SQLITE_OK is returned if everything goes according to plan. An
+** SQLITE_IOERR_XXX error code is returned if a call to sqlite3OsOpen()
+** fails.
+*/
+static int 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);
+ }
+ }
+ return rc;
+}
+
+/*
+** Append a record of the current state of page pPg to the sub-journal.
+** It is the callers responsibility to use subjRequiresPage() to check
** that it is really required before calling this function.
**
** If successful, set the bit corresponding to pPg->pgno in the bitvecs
** for all open savepoints before returning.
**
** This function returns SQLITE_OK if everything is successful, an IO
-** error code if the attempt to write to the sub-journal fails, or
+** error code if the attempt to write to the sub-journal fails, or
** SQLITE_NOMEM if a malloc fails while setting a bit in a savepoint
** bitvec.
*/
static int subjournalPage(PgHdr *pPg){
int rc = SQLITE_OK;
Pager *pPager = pPg->pPager;
- if( isOpen(pPager->sjfd) ){
- void *pData = pPg->pData;
- i64 offset = pPager->nSubRec*(4+pPager->pageSize);
- char *pData2;
+ if( pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
- CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
- PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
+ /* 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);
- assert( pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize );
- rc = write32bits(pPager->sjfd, offset, pPg->pgno);
+ /* If the sub-journal was opened successfully (or was already open),
+ ** write the journal record into the file. */
if( rc==SQLITE_OK ){
- rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);
+ void *pData = pPg->pData;
+ i64 offset = 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( rc==SQLITE_OK ){
@@ -35151,19 +41665,18 @@ static int subjournalPage(PgHdr *pPg){
return rc;
}
-
/*
** 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
+** 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
+** is always associated with the Pager object passed as the first
** argument.
**
** 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.
+** journal file.
**
** If successful, sqlite3PcacheMakeClean() is called on the page and
** SQLITE_OK returned. If an IO error occurs while trying to make the
@@ -35178,74 +41691,83 @@ static int pagerStress(void *p, PgHdr *pPg){
assert( pPg->pPager==pPager );
assert( pPg->flags&PGHDR_DIRTY );
- /* The doNotSync flag is set by the sqlite3PagerWrite() function while it
- ** is journalling a set of two or more database pages that are stored
- ** on the same disk sector. Syncing the journal is not allowed while
- ** this is happening as it is important that all members of such a
- ** set of pages are synced to disk together. So, if the page this function
- ** is trying to make clean will require a journal sync and the doNotSync
- ** flag is set, return without doing anything. The pcache layer will
- ** just have to go ahead and allocate a new page buffer instead of
- ** reusing pPg.
+ /* 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.
**
- ** Similarly, if the pager has already entered the error state, do not
- ** try to write the contents of pPg to disk.
+ ** 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)
- || (pPager->doNotSync && pPg->flags&PGHDR_NEED_SYNC)
- ){
+ 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;
}
- /* Sync the journal file if required. */
- if( pPg->flags&PGHDR_NEED_SYNC ){
- rc = syncJournal(pPager);
- if( rc==SQLITE_OK && pPager->fullSync &&
- !(pPager->journalMode==PAGER_JOURNALMODE_MEMORY) &&
- !(sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
- ){
- pPager->nRec = 0;
- rc = writeJournalHdr(pPager);
+ 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, 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;
+ **
+ **
+ ** SAVEPOINT sp;
+ **
+ ** pagerStress(page X)
+ ** ROLLBACK TO sp;
+ **
+ ** If (X>Y), then when pagerStress is called page X will not be written
+ ** out to the database file, but will be dropped from the cache. Then,
+ ** following the "ROLLBACK TO sp" statement, reading page X will read
+ ** data from the database file. This will be the copy of page X as it
+ ** was when the transaction started, not as it was when "SAVEPOINT sp"
+ ** was executed.
+ **
+ ** The solution is to write the current data for page X into the
+ ** sub-journal file now (if it is not already there), so that it will
+ ** be restored to its current value when the "ROLLBACK TO sp" is
+ ** executed.
+ */
+ if( NEVER(
+ rc==SQLITE_OK && pPg->pgno>pPager->dbSize && subjRequiresPage(pPg)
+ ) ){
+ rc = subjournalPage(pPg);
+ }
+
+ /* Write the contents of the page out to the database file. */
+ if( rc==SQLITE_OK ){
+ assert( (pPg->flags&PGHDR_NEED_SYNC)==0 );
+ rc = pager_write_pagelist(pPager, pPg);
}
- }
-
- /* If the 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;
- **
- **
- ** SAVEPOINT sp;
- **
- ** 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 ){
- pPg->pDirty = 0;
- rc = pager_write_pagelist(pPg);
}
/* Mark the page as clean. */
@@ -35254,7 +41776,7 @@ static int pagerStress(void *p, PgHdr *pPg){
sqlite3PcacheMakeClean(pPg);
}
- return pager_error(pPager, rc);
+ return pager_error(pPager, rc);
}
@@ -35266,8 +41788,8 @@ static int pagerStress(void *p, PgHdr *pPg){
** 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.
+** 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
@@ -35279,13 +41801,13 @@ static int pagerStress(void *p, PgHdr *pPg){
** of the PAGER_OMIT_JOURNAL and PAGER_NO_READLOCK flags.
**
** The vfsFlags parameter is a bitmask to pass to the flags parameter
-** of the xOpen() method of the supplied VFS when opening files.
+** of the xOpen() method of the supplied VFS when opening files.
**
-** If the pager object is allocated and the specified file opened
+** 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
+** (sqlite3Malloc() is used to allocate memory), SQLITE_CANTOPEN or
** various SQLITE_IO_XXX errors.
*/
SQLITE_PRIVATE int sqlite3PagerOpen(
@@ -35309,14 +41831,16 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; /* False to omit journal */
int noReadlock = (flags & PAGER_NO_READLOCK)!=0; /* True to omit read-lock */
int pcacheSize = sqlite3PcacheSize(); /* Bytes to allocate for PCache */
- u16 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; /* Default page size */
+ u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; /* Default page size */
+ const char *zUri = 0; /* URI args to copy */
+ int nUri = 0; /* Number of bytes of URI args at *zUri */
/* Figure out how much space is required for each journal file-handle
** (there are two of them, the main journal and the sub-journal). This
- ** is the maximum space required for an in-memory journal file handle
+ ** 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
+ ** file in memory to implement the atomic-write optimization (see
** source file journal.c).
*/
if( sqlite3JournalSize(pVfs)>sqlite3MemJournalSize() ){
@@ -35328,28 +41852,33 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
/* Set the output variable to NULL in case an error occurs. */
*ppPager = 0;
+#ifndef SQLITE_OMIT_MEMORYDB
+ if( flags & PAGER_MEMORY ){
+ memDb = 1;
+ zFilename = 0;
+ }
+#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.
*/
if( zFilename && zFilename[0] ){
+ const char *z;
nPathname = pVfs->mxPathname+1;
zPathname = sqlite3Malloc(nPathname*2);
if( zPathname==0 ){
return SQLITE_NOMEM;
}
-#ifndef SQLITE_OMIT_MEMORYDB
- if( strcmp(zFilename,":memory:")==0 ){
- memDb = 1;
- zPathname[0] = 0;
- }else
-#endif
- {
- zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */
- rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
- }
-
+ 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 = &z[1] - zUri;
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
@@ -35366,7 +41895,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
}
/* Allocate memory for the Pager structure, PCache object, the
- ** three file descriptors, the database file name and the journal
+ ** three file descriptors, the database file name and the journal
** file name. The layout in memory is as follows:
**
** Pager object (sizeof(Pager) bytes)
@@ -35381,9 +41910,12 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
ROUND8(sizeof(*pPager)) + /* Pager structure */
ROUND8(pcacheSize) + /* PCache object */
ROUND8(pVfs->szOsFile) + /* The main db file */
- journalFileSize * 2 + /* The two journal files */
- nPathname + 1 + /* zFilename */
+ journalFileSize * 2 + /* The two journal files */
+ nPathname + 1 + nUri + /* zFilename */
nPathname + 8 + 1 /* zJournal */
+#ifndef SQLITE_OMIT_WAL
+ + nPathname + 4 + 1 /* zWal */
+#endif
);
assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) );
if( !pPtr ){
@@ -35400,11 +41932,19 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
/* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */
if( zPathname ){
- pPager->zJournal = (char*)(pPtr += nPathname + 1);
+ assert( nPathname>0 );
+ pPager->zJournal = (char*)(pPtr += nPathname + 1 + nUri);
memcpy(pPager->zFilename, zPathname, nPathname);
+ memcpy(&pPager->zFilename[nPathname+1], zUri, nUri);
memcpy(pPager->zJournal, zPathname, nPathname);
memcpy(&pPager->zJournal[nPathname], "-journal", 8);
- if( pPager->zFilename[0]==0 ) pPager->zJournal[0] = 0;
+ 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", 4);
+ sqlite3FileSuffix3(pPager->zFilename, pPager->zWal);
+#endif
sqlite3_free(zPathname);
}
pPager->pVfs = pVfs;
@@ -35412,9 +41952,10 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
/* Open the pager file.
*/
- if( zFilename && zFilename[0] && !memDb ){
+ 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 the file was successfully opened for read/write access,
@@ -35432,7 +41973,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
if( pPager->sectorSize>SQLITE_MAX_DEFAULT_PAGE_SIZE ){
szPageDflt = SQLITE_MAX_DEFAULT_PAGE_SIZE;
}else{
- szPageDflt = (u16)pPager->sectorSize;
+ szPageDflt = (u32)pPager->sectorSize;
}
}
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
@@ -35458,13 +41999,14 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
** 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->state = PAGER_EXCLUSIVE;
+ pPager->eState = PAGER_READER;
+ pPager->eLock = EXCLUSIVE_LOCK;
readOnly = (vfsFlags&SQLITE_OPEN_READONLY);
}
- /* The following call to PagerSetPagesize() serves to set the value of
+ /* The following call to PagerSetPagesize() serves to set the value of
** Pager.pageSize and to allocate the Pager.pTmpSpace buffer.
*/
if( rc==SQLITE_OK ){
@@ -35473,7 +42015,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
testcase( rc!=SQLITE_OK );
}
- /* If an error occurred in either of the blocks above, free the
+ /* If an error occurred in either of the blocks above, free the
** Pager structure and close the file.
*/
if( rc!=SQLITE_OK ){
@@ -35497,27 +42039,28 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
/* pPager->stmtOpen = 0; */
/* pPager->stmtInUse = 0; */
/* pPager->nRef = 0; */
- pPager->dbSizeValid = (u8)memDb;
/* 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
+ assert( tempFile==PAGER_LOCKINGMODE_NORMAL
|| tempFile==PAGER_LOCKINGMODE_EXCLUSIVE );
assert( PAGER_LOCKINGMODE_EXCLUSIVE==1 );
- pPager->exclusiveMode = (u8)tempFile;
+ pPager->exclusiveMode = (u8)tempFile;
pPager->changeCountDone = pPager->tempFile;
pPager->memDb = (u8)memDb;
pPager->readOnly = (u8)readOnly;
- /* pPager->needSync = 0; */
assert( useJournal || pPager->tempFile );
pPager->noSync = pPager->tempFile;
pPager->fullSync = pPager->noSync ?0:1;
- pPager->sync_flags = SQLITE_SYNC_NORMAL;
+ pPager->syncFlags = pPager->noSync ? 0 : SQLITE_SYNC_NORMAL;
+ pPager->ckptSyncFlags = pPager->syncFlags;
/* pPager->pFirst = 0; */
/* pPager->pFirstSynced = 0; */
/* pPager->pLast = 0; */
@@ -35544,7 +42087,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
/*
** 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
+** 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:
**
@@ -35563,10 +42106,10 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
** 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.
+** 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
+** 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
@@ -35574,22 +42117,27 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
*/
static int hasHotJournal(Pager *pPager, int *pExists){
sqlite3_vfs * const pVfs = pPager->pVfs;
- int rc; /* Return code */
- int exists; /* True if a journal file is present */
+ int rc = SQLITE_OK; /* Return code */
+ int exists = 1; /* True if a journal file is present */
+ int jrnlOpen = !!isOpen(pPager->jfd);
- assert( pPager!=0 );
assert( pPager->useJournal );
assert( isOpen(pPager->fd) );
- assert( !isOpen(pPager->jfd) );
- assert( pPager->state <= PAGER_SHARED );
+ assert( pPager->eState==PAGER_OPEN );
+
+ assert( jrnlOpen==0 || ( sqlite3OsDeviceCharacteristics(pPager->jfd) &
+ SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
+ ));
*pExists = 0;
- rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
+ if( !jrnlOpen ){
+ rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
+ }
if( rc==SQLITE_OK && exists ){
- int locked; /* True if some process holds a RESERVED lock */
+ 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()
+ ** 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
@@ -35598,39 +42146,43 @@ static int hasHotJournal(Pager *pPager, int *pExists){
*/
rc = sqlite3OsCheckReservedLock(pPager->fd, &locked);
if( rc==SQLITE_OK && !locked ){
- int nPage;
+ Pgno nPage; /* Number of pages in database file */
/* Check the size of the database file. If it consists of 0 pages,
- ** then delete the journal file. See the header comment above for
+ ** 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 = sqlite3PagerPagecount(pPager, &nPage);
+ rc = pagerPagecount(pPager, &nPage);
if( rc==SQLITE_OK ){
if( nPage==0 ){
sqlite3BeginBenignMalloc();
- if( sqlite3OsLock(pPager->fd, RESERVED_LOCK)==SQLITE_OK ){
+ if( pagerLockDb(pPager, RESERVED_LOCK)==SQLITE_OK ){
sqlite3OsDelete(pVfs, pPager->zJournal, 0);
- sqlite3OsUnlock(pPager->fd, SHARED_LOCK);
+ 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,
+ ** If there is, then we consider this journal to be hot. If not,
** it can be ignored.
*/
- int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
- rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
+ 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;
}
- sqlite3OsClose(pPager->jfd);
+ 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
@@ -35653,67 +42205,6 @@ static int hasHotJournal(Pager *pPager, int *pExists){
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.
-**
-** If page 1 is read, then the value of Pager.dbFileVers[] is set to
-** the value read from the database file.
-**
-** If an IO error occurs, then the IO error is returned to the caller.
-** Otherwise, SQLITE_OK is returned.
-*/
-static int readDbPage(PgHdr *pPg){
- Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
- Pgno pgno = pPg->pgno; /* Page number to read */
- int rc; /* Return code */
- i64 iOffset; /* Byte offset of file to read from */
-
- assert( pPager->state>=PAGER_SHARED && !MEMDB );
- assert( isOpen(pPager->fd) );
-
- if( NEVER(!isOpen(pPager->fd)) ){
- assert( pPager->tempFile );
- memset(pPg->pData, 0, pPager->pageSize);
- return SQLITE_OK;
- }
- iOffset = (pgno-1)*(i64)pPager->pageSize;
- rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset);
- if( rc==SQLITE_IOERR_SHORT_READ ){
- rc = SQLITE_OK;
- }
- if( pgno==1 ){
- if( rc ){
- /* If the read is unsuccessful, set the dbFileVers[] to something
- ** that will never be a valid file version. dbFileVers[] is a copy
- ** of bytes 24..39 of the database. Bytes 28..31 should always be
- ** zero. 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);
-
- PAGER_INCR(sqlite3_pager_readdb_count);
- PAGER_INCR(pPager->nRead);
- IOTRACE(("PGIN %p %d\n", pPager, pgno));
- PAGERTRACE(("FETCH %d page %d hash(%08x)\n",
- PAGERID(pPager), pgno, pager_pagehash(pPg)));
-
- return rc;
-}
-
/*
** This function is called to obtain a shared lock on the database file.
** It is illegal to call sqlite3PagerAcquire() until after this function
@@ -35722,11 +42213,11 @@ static int readDbPage(PgHdr *pPg){
**
** The following operations are also performed by this function.
**
-** 1) If the pager is currently in PAGER_UNLOCK state (no lock held
+** 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
+** 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.
@@ -35737,143 +42228,147 @@ static int readDbPage(PgHdr *pPg){
** the contents of the page cache and rolling back any open journal
** file.
**
-** If the operation described by (2) above is not attempted, and if the
-** pager is in an error state other than SQLITE_FULL when this is called,
-** the error state error code is returned. It is permitted to read the
-** database when in SQLITE_FULL error state.
-**
-** Otherwise, 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.
+** If everything is successful, SQLITE_OK is returned. If an IO error
+** occurs while locking the database, checking for a hot-journal file or
+** rolling back a journal file, the IO error code is returned.
*/
SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
int rc = SQLITE_OK; /* Return code */
- int isErrorReset = 0; /* True if recovering from error state */
/* This routine is only called from b-tree and only when there are no
- ** outstanding pages */
+ ** outstanding pages. This implies that the pager state should either
+ ** be OPEN or READER. READER is only possible if the pager is or was in
+ ** exclusive access mode.
+ */
assert( sqlite3PcacheRefCount(pPager->pPCache)==0 );
+ assert( assert_pager_state(pPager) );
+ assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER );
if( NEVER(MEMDB && pPager->errCode) ){ return pPager->errCode; }
- /* If this database is in an error-state, now is a chance to clear
- ** the error. Discard the contents of the pager-cache and rollback
- ** any hot journal in the file-system.
- */
- if( pPager->errCode ){
- if( isOpen(pPager->jfd) || pPager->zJournal ){
- isErrorReset = 1;
- }
- pPager->errCode = SQLITE_OK;
- pager_reset(pPager);
- }
+ if( !pagerUseWal(pPager) && pPager->eState==PAGER_OPEN ){
+ int bHotJournal = 1; /* True if there exists a hot journal-file */
- if( pPager->state==PAGER_UNLOCK || isErrorReset ){
- sqlite3_vfs * const pVfs = pPager->pVfs;
- int isHotJournal = 0;
assert( !MEMDB );
- assert( sqlite3PcacheRefCount(pPager->pPCache)==0 );
- if( pPager->noReadlock ){
- assert( pPager->readOnly );
- pPager->state = PAGER_SHARED;
- }else{
+ assert( pPager->noReadlock==0 || pPager->readOnly );
+
+ if( pPager->noReadlock==0 ){
rc = pager_wait_on_lock(pPager, SHARED_LOCK);
if( rc!=SQLITE_OK ){
- assert( pPager->state==PAGER_UNLOCK );
- return pager_error(pPager, rc);
+ assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK );
+ goto failed;
}
}
- assert( pPager->state>=SHARED_LOCK );
/* 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( !isErrorReset ){
- assert( pPager->state <= PAGER_SHARED );
- rc = hasHotJournal(pPager, &isHotJournal);
- if( rc!=SQLITE_OK ){
- goto failed;
- }
+ if( pPager->eLock<=SHARED_LOCK ){
+ rc = hasHotJournal(pPager, &bHotJournal);
}
- if( isErrorReset || isHotJournal ){
+ if( rc!=SQLITE_OK ){
+ goto failed;
+ }
+ if( bHotJournal ){
/* 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
+ ** 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
+ ** 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.
*/
- if( pPager->statefd, EXCLUSIVE_LOCK);
- if( rc!=SQLITE_OK ){
- rc = pager_error(pPager, rc);
- goto failed;
- }
- pPager->state = PAGER_EXCLUSIVE;
- }
-
- /* Open the journal for read/write access. This is because in
- ** exclusive-access mode the file descriptor will be kept open and
- ** possibly used for a transaction later on. On some systems, the
- ** OsTruncate() call used in exclusive-access mode also requires
- ** a read/write file handle.
- */
- if( !isOpen(pPager->jfd) ){
- int res;
- rc = sqlite3OsAccess(pVfs,pPager->zJournal,SQLITE_ACCESS_EXISTS,&res);
- if( rc==SQLITE_OK ){
- if( res ){
- int fout = 0;
- int f = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL;
- assert( !pPager->tempFile );
- rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &fout);
- assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
- if( rc==SQLITE_OK && fout&SQLITE_OPEN_READONLY ){
- rc = SQLITE_CANTOPEN_BKPT;
- sqlite3OsClose(pPager->jfd);
- }
- }else{
- /* 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. */
- rc = pager_end_transaction(pPager, 0);
- }
- }
- }
+ rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
if( rc!=SQLITE_OK ){
goto failed;
}
-
- /* TODO: Why are these cleared here? Is it necessary? */
- pPager->journalStarted = 0;
- pPager->journalOff = 0;
- pPager->setMaster = 0;
- pPager->journalHdr = 0;
-
+
+ /* 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.
+ ** 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) ){
- rc = pager_playback(pPager, 1);
- if( rc!=SQLITE_OK ){
- rc = pager_error(pPager, rc);
- goto failed;
+ 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);
}
- assert( (pPager->state==PAGER_SHARED)
- || (pPager->exclusiveMode && pPager->state>PAGER_SHARED)
+
+ 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( pPager->pBackup || sqlite3PcachePagecount(pPager->pPCache)>0 ){
+ if( !pPager->tempFile
+ && (pPager->pBackup || sqlite3PcachePagecount(pPager->pPCache)>0)
+ ){
/* 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
@@ -35885,21 +42380,18 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
** 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
+ **
+ ** 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)];
- sqlite3PagerPagecount(pPager, 0);
- if( pPager->errCode ){
- rc = pPager->errCode;
- goto failed;
- }
+ rc = pagerPagecount(pPager, &nPage);
+ if( rc ) goto failed;
- assert( pPager->dbSizeValid );
- if( pPager->dbSize>0 ){
+ if( nPage>0 ){
IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
if( rc!=SQLITE_OK ){
@@ -35913,13 +42405,32 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
pager_reset(pPager);
}
}
- assert( pPager->exclusiveMode || pPager->state==PAGER_SHARED );
+
+ /* 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
+ }
+
+ 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 ){
- /* pager_unlock() is a no-op for exclusive mode and in-memory databases. */
+ assert( !MEMDB );
pager_unlock(pPager);
+ assert( pPager->eState==PAGER_OPEN );
+ }else{
+ pPager->eState = PAGER_READER;
}
return rc;
}
@@ -35931,36 +42442,34 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
** 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( (sqlite3PcacheRefCount(pPager->pPCache)==0)
- && (!pPager->exclusiveMode || pPager->journalOff>0)
- ){
+ if( (sqlite3PcacheRefCount(pPager->pPCache)==0) ){
pagerUnlockAndRollback(pPager);
}
}
/*
** Acquire a reference to page number pgno in pager pPager (a page
-** reference has type DbPage*). If the requested reference is
+** 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.
+** 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
+** The extra data appended to a page is always initialized to zeros the
+** first time a page is loaded into memory. If the page requested is
** already in the cache when this function is called, then the extra
** data is left as it was when the page object was last used.
**
-** If the database image is smaller than the requested page or if a
-** non-zero value is passed as the noContent parameter and the
-** requested page is not already stored in the cache, then no
-** actual disk read occurs. In this case the memory image of the
-** page is initialized to all zeros.
+** If the database image is smaller than the requested page or if a
+** non-zero value is passed as the noContent parameter and the
+** requested page is not already stored in the cache, then no
+** actual disk read occurs. In this case the memory image of the
+** page is initialized to all zeros.
**
** If noContent is true, it means that we do not care about the contents
** of the page. This occurs in two seperate scenarios:
@@ -35968,7 +42477,7 @@ static void pagerUnlockIfUnused(Pager *pPager){
** 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 populate with the data read
+** 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
@@ -35999,16 +42508,16 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
int rc;
PgHdr *pPg;
+ assert( pPager->eState>=PAGER_READER );
assert( assert_pager_state(pPager) );
- assert( pPager->state>PAGER_UNLOCK );
if( pgno==0 ){
return SQLITE_CORRUPT_BKPT;
}
- /* If the pager is in the error state, return an error immediately.
+ /* 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 && pPager->errCode!=SQLITE_FULL ){
+ if( pPager->errCode!=SQLITE_OK ){
rc = pPager->errCode;
}else{
rc = sqlite3PcacheFetch(pPager->pPCache, pgno, 1, ppPage);
@@ -36024,7 +42533,7 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
assert( (*ppPage)->pgno==pgno );
assert( (*ppPage)->pPager==pPager || (*ppPage)->pPager==0 );
- if( (*ppPage)->pPager ){
+ 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) );
@@ -36032,9 +42541,8 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
return SQLITE_OK;
}else{
- /* The pager cache has created a new page. Its content needs to
+ /* The pager cache has created a new page. Its content needs to
** be initialized. */
- int nMax;
PAGER_INCR(pPager->nMiss);
pPg = *ppPage;
@@ -36047,21 +42555,16 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
goto pager_acquire_err;
}
- rc = sqlite3PagerPagecount(pPager, &nMax);
- if( rc!=SQLITE_OK ){
- goto pager_acquire_err;
- }
-
- if( MEMDB || nMax<(int)pgno || noContent || !isOpen(pPager->fd) ){
+ if( MEMDB || pPager->dbSizefd) ){
if( pgno>pPager->mxPgno ){
- rc = SQLITE_FULL;
- goto pager_acquire_err;
+ 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
+ ** 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();
@@ -36082,9 +42585,7 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
goto pager_acquire_err;
}
}
-#ifdef SQLITE_CHECK_PAGES
- pPg->pageHash = pager_pagehash(pPg);
-#endif
+ pager_set_pagehash(pPg);
}
return SQLITE_OK;
@@ -36103,14 +42604,12 @@ pager_acquire_err:
/*
** 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. Also, return 0 if the
-** pager is in PAGER_UNLOCK state when this function is called,
-** or if the pager is in an error state other than SQLITE_FULL.
+** 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
+** 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){
@@ -36118,7 +42617,7 @@ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
assert( pPager!=0 );
assert( pgno!=0 );
assert( pPager->pPCache!=0 );
- assert( pPager->state > PAGER_UNLOCK );
+ assert( pPager->eState>=PAGER_READER && pPager->eState!=PAGER_ERROR );
sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg);
return pPg;
}
@@ -36139,205 +42638,181 @@ SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){
}
}
-/*
-** If the main journal file has already been opened, ensure that the
-** sub-journal file is open too. If the main journal is not open,
-** this function is a no-op.
-**
-** SQLITE_OK is returned if everything goes according to plan.
-** An SQLITE_IOERR_XXX error code is returned if a call to
-** sqlite3OsOpen() fails.
-*/
-static int openSubJournal(Pager *pPager){
- int rc = SQLITE_OK;
- if( isOpen(pPager->jfd) && !isOpen(pPager->sjfd) ){
- if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){
- sqlite3MemJournalOpen(pPager->sjfd);
- }else{
- rc = pagerOpentemp(pPager, pPager->sjfd, SQLITE_OPEN_SUBJOURNAL);
- }
- }
- 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
+** 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
+** 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.
+** already open file.
**
** Whether or not the journal file is opened by this function, the
** Pager.pInJournal bitvec structure is allocated.
**
-** Return SQLITE_OK if everything is successful. Otherwise, return
-** SQLITE_NOMEM if the attempt to allocate Pager.pInJournal fails, or
+** Return SQLITE_OK if everything is successful. Otherwise, return
+** SQLITE_NOMEM if the attempt to allocate Pager.pInJournal fails, or
** an IO error code if opening or writing the journal file fails.
*/
static int pager_open_journal(Pager *pPager){
int rc = SQLITE_OK; /* Return code */
sqlite3_vfs * const pVfs = pPager->pVfs; /* Local cache of vfs pointer */
- assert( pPager->state>=PAGER_RESERVED );
- assert( pPager->useJournal );
- assert( 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;
- /* TODO: Is it really possible to get here with dbSizeValid==0? If not,
- ** the call to PagerPagecount() can be removed.
- */
- testcase( pPager->dbSizeValid==0 );
- sqlite3PagerPagecount(pPager, 0);
-
- 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
+ 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);
}
- 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->dbOrigSize = pPager->dbSize;
- pPager->journalStarted = 0;
- pPager->needSync = 0;
- pPager->nRec = 0;
- pPager->journalOff = 0;
- pPager->setMaster = 0;
- pPager->journalHdr = 0;
- rc = writeJournalHdr(pPager);
- }
- if( rc==SQLITE_OK && pPager->nSavepoint ){
- rc = openSubJournal(pPager);
}
if( rc!=SQLITE_OK ){
sqlite3BitvecDestroy(pPager->pInJournal);
pPager->pInJournal = 0;
+ }else{
+ assert( pPager->eState==PAGER_WRITER_LOCKED );
+ pPager->eState = PAGER_WRITER_CACHEMOD;
}
+
return rc;
}
/*
-** Begin a write-transaction on the specified pager object. If a
+** 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
+** an EXCLUSIVE lock. If such a lock is already held, no locking
** functions need be called.
**
-** If this is not a temporary or in-memory file and, the journal file is
-** opened if it has not been already. For a temporary file, the opening
-** of the journal file is deferred until there is an actual need to
-** write to the journal. TODO: Why handle temporary files differently?
-**
-** If the journal file is opened (or if it is already open), then a
-** journal-header is written to the start of it.
-**
** 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,
+** sub-journal is implemented in-memory if pPager is an in-memory database,
** or using a temporary file otherwise.
*/
SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
int rc = SQLITE_OK;
- assert( pPager->state!=PAGER_UNLOCK );
- pPager->subjInMemory = (u8)subjInMemory;
- if( pPager->state==PAGER_SHARED ){
- assert( pPager->pInJournal==0 );
- assert( !MEMDB && !pPager->tempFile );
- /* 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 = sqlite3OsLock(pPager->fd, RESERVED_LOCK);
- if( rc==SQLITE_OK ){
- pPager->state = PAGER_RESERVED;
- if( exFlag ){
+ if( pPager->errCode ) return pPager->errCode;
+ assert( pPager->eState>=PAGER_READER && pPager->eStatesubjInMemory = (u8)subjInMemory;
+
+ if( ALWAYS(pPager->eState==PAGER_READER) ){
+ assert( pPager->pInJournal==0 );
+
+ 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);
+ }
+
+ /* 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 the required locks were successfully obtained, open the journal
- ** file and write the first journal-header to it.
- */
- if( rc==SQLITE_OK && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
- rc = pager_open_journal(pPager);
+ 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;
}
- }else if( isOpen(pPager->jfd) && pPager->journalOff==0 ){
- /* This happens when the pager was in exclusive-access mode the last
- ** time a (read or write) transaction was successfully concluded
- ** by this connection. Instead of deleting the journal file it was
- ** kept open and either was truncated to 0 bytes or its header was
- ** overwritten with zeros.
- */
- assert( pPager->nRec==0 );
- assert( pPager->dbOrigSize==0 );
- assert( pPager->pInJournal==0 );
- rc = pager_open_journal(pPager);
+
+ 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)));
- assert( !isOpen(pPager->jfd) || pPager->journalOff>0 || rc!=SQLITE_OK );
- if( rc!=SQLITE_OK ){
- assert( !pPager->dbModified );
- /* Ignore any IO error that occurs within pager_end_transaction(). The
- ** purpose of this call is to reset the internal state of the pager
- ** sub-system. It doesn't matter if the journal-file is not properly
- ** finalized at this point (since it is not a valid journal file anyway).
- */
- pager_end_transaction(pPager, 0);
- }
return rc;
}
/*
-** Mark a single data page as writeable. The page is written into the
+** 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
+** 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.
*/
@@ -36346,102 +42821,94 @@ static int pager_write(PgHdr *pPg){
Pager *pPager = pPg->pPager;
int rc = SQLITE_OK;
- /* This routine is not called unless a transaction has already been
- ** started.
+ /* 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->state>=PAGER_RESERVED );
+ 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, we should not be
- ** calling this routine. Repeat the error for robustness.
- */
+ /* 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;
/* 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;
- assert( !pPager->setMaster );
-
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) );
+
/* 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) ){
- pPager->dbModified = 1;
+ assert( !pagerUseWal(pPager) );
}else{
-
- /* If we get this far, it means that the page needs to be
- ** written to the transaction journal or the ckeckpoint journal
- ** or both.
- **
- ** Higher level routines should have already started a transaction,
- ** which means they have acquired the necessary locks and opened
- ** a rollback journal. Double-check to makes sure this is the case.
- */
- rc = sqlite3PagerBegin(pPager, 0, pPager->subjInMemory);
- if( NEVER(rc!=SQLITE_OK) ){
- return rc;
- }
- if( !isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
- assert( pPager->useJournal );
- rc = pager_open_journal(pPager);
- if( rc!=SQLITE_OK ) return rc;
- }
- pPager->dbModified = 1;
-
+
/* 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) && isOpen(pPager->jfd) ){
- if( pPg->pgno<=pPager->dbOrigSize ){
+ 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);
- rc = write32bits(pPager->jfd, pPager->journalOff, pPg->pgno);
- if( rc==SQLITE_OK ){
- rc = sqlite3OsWrite(pPager->jfd, pData2, pPager->pageSize,
- pPager->journalOff + 4);
- pPager->journalOff += pPager->pageSize+4;
- }
- if( rc==SQLITE_OK ){
- rc = write32bits(pPager->jfd, pPager->journalOff, cksum);
- pPager->journalOff += 4;
- }
- 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)));
- /* Even if an IO or diskfull error occurred while journalling the
+ /* 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.
*/
- if( !pPager->noSync ){
- pPg->flags |= PGHDR_NEED_SYNC;
- pPager->needSync = 1;
- }
+ pPg->flags |= PGHDR_NEED_SYNC;
- /* An error has occurred writing to the journal file. The
- ** transaction will be rolled back by the layer above.
- */
- if( rc!=SQLITE_OK ){
- return rc;
- }
+ rc = write32bits(pPager->jfd, iOff, pPg->pgno);
+ if( rc!=SQLITE_OK ) return rc;
+ rc = sqlite3OsWrite(pPager->jfd, pData2, pPager->pageSize, iOff+4);
+ if( rc!=SQLITE_OK ) return rc;
+ rc = write32bits(pPager->jfd, iOff+pPager->pageSize+4, cksum);
+ if( rc!=SQLITE_OK ) return rc;
+ 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);
@@ -36453,16 +42920,15 @@ static int pager_write(PgHdr *pPg){
return rc;
}
}else{
- if( !pPager->journalStarted && !pPager->noSync ){
+ if( pPager->eState!=PAGER_WRITER_DBMOD ){
pPg->flags |= PGHDR_NEED_SYNC;
- pPager->needSync = 1;
}
PAGERTRACE(("APPEND %d page %d needSync=%d\n",
PAGERID(pPager), pPg->pgno,
((pPg->flags&PGHDR_NEED_SYNC)?1:0)));
}
}
-
+
/* If the statement journal is open and the page is not in it,
** then write the current page to the statement journal. Note that
** the statement journal format differs from the standard journal format
@@ -36475,7 +42941,6 @@ static int pager_write(PgHdr *pPg){
/* Update the database size and return.
*/
- assert( pPager->state>=PAGER_SHARED );
if( pPager->dbSizepgno ){
pPager->dbSize = pPg->pgno;
}
@@ -36483,9 +42948,9 @@ static int pager_write(PgHdr *pPg){
}
/*
-** Mark a data page as writeable. This routine must be called before
-** making changes to a page. The caller must check the return value
-** of this function and be careful not to change any page data unless
+** Mark a data page as writeable. This routine must be called before
+** making changes to a page. The caller must check the return value
+** of this function and be careful not to change any page data unless
** this routine returns SQLITE_OK.
**
** The difference between this function and pager_write() is that this
@@ -36503,19 +42968,24 @@ SQLITE_PRIVATE int sqlite3PagerWrite(DbPage *pDbPage){
Pager *pPager = pPg->pPager;
Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
+ 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; /* Number of pages starting at pg1 to journal */
+ 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 doNotSync flag to 1. This is because we cannot allow a journal
- ** header to be written between the pages journaled by this function.
+ /* 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->doNotSync==0 );
- pPager->doNotSync = 1;
+ assert( pPager->doNotSyncSpill==0 );
+ pPager->doNotSyncSpill++;
/* This trick assumes that both the page-size and sector-size are
** an integer power of 2. It sets variable pg1 to the identifier
@@ -36523,7 +42993,7 @@ SQLITE_PRIVATE int sqlite3PagerWrite(DbPage *pDbPage){
*/
pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1;
- sqlite3PagerPagecount(pPager, (int *)&nPageCount);
+ nPageCount = pPager->dbSize;
if( pPg->pgno>nPageCount ){
nPage = (pPg->pgno - pg1)+1;
}else if( (pg1+nPagePerSector-1)>nPageCount ){
@@ -36545,7 +43015,6 @@ SQLITE_PRIVATE int sqlite3PagerWrite(DbPage *pDbPage){
rc = pager_write(pPage);
if( pPage->flags&PGHDR_NEED_SYNC ){
needSync = 1;
- assert(pPager->needSync);
}
sqlite3PagerUnref(pPage);
}
@@ -36558,14 +43027,14 @@ SQLITE_PRIVATE int sqlite3PagerWrite(DbPage *pDbPage){
}
}
- /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages
+ /* 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 && pPager->noSync==0 );
+ assert( !MEMDB );
for(ii=0; iineedSync);
}
- assert( pPager->doNotSync==1 );
- pPager->doNotSync = 0;
+ assert( pPager->doNotSyncSpill==1 );
+ pPager->doNotSyncSpill--;
}else{
rc = pager_write(pDbPage);
}
@@ -36606,7 +43074,7 @@ SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage *pPg){
** 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
+** Tests show that this optimization can quadruple the speed of large
** DELETE operations.
*/
SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){
@@ -36615,18 +43083,22 @@ SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){
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;
-#ifdef SQLITE_CHECK_PAGES
- pPg->pageHash = pager_pagehash(pPg);
-#endif
+ 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.
+** 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.
**
-** If the isDirectMode flag is zero, then this is done by calling
+** 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.
@@ -36634,12 +43106,17 @@ SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){
** 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
+** by writing an updated version of page 1 using a call to the
** sqlite3OsWrite() function.
*/
static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
int rc = SQLITE_OK;
+ 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
@@ -36658,10 +43135,8 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
# define DIRECT_MODE isDirectMode
#endif
- assert( pPager->state>=PAGER_RESERVED );
if( !pPager->changeCountDone && pPager->dbSize>0 ){
PgHdr *pPgHdr; /* Reference to page 1 */
- u32 change_counter; /* Initial value of change-counter field */
assert( !pPager->tempFile && isOpen(pPager->fd) );
@@ -36670,7 +43145,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
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
+ ** 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.
*/
@@ -36679,16 +43154,17 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
}
if( rc==SQLITE_OK ){
- /* Increment the value just read and write it back to byte 24. */
- change_counter = sqlite3Get4byte((u8*)pPager->dbFileVers);
- change_counter++;
- put32bits(((char*)pPgHdr->pData)+24, change_counter);
+ /* 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 = pPgHdr->pData;
+ const void *zBuf;
assert( pPager->dbFileSize>0 );
- rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
+ CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM, zBuf);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
+ }
if( rc==SQLITE_OK ){
pPager->changeCountDone = 1;
}
@@ -36704,19 +43180,44 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
}
/*
-** Sync the pager file to disk. This is a no-op for in-memory files
+** 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 called on a pager for which it is a no-op, this
+** 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; /* Return code */
- assert( !MEMDB );
- if( pPager->noSync ){
- rc = SQLITE_OK;
- }else{
- rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
+ int rc = SQLITE_OK;
+ if( !pPager->noSync ){
+ assert( !MEMDB );
+ rc = sqlite3OsSync(pPager->fd, pPager->syncFlags);
+ }else if( isOpen(pPager->fd) ){
+ assert( !MEMDB );
+ sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC_OMITTED, (void *)&rc);
+ }
+ 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 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);
}
return rc;
}
@@ -36731,12 +43232,12 @@ SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager){
**
** * 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,
+** * all dirty pages are written to the database file,
** * the database file is truncated (if required), and
-** * the database file synced.
+** * the database file synced.
**
-** The only thing that remains to commit the transaction is to finalize
-** (delete, truncate or zero the first part of) the journal file (or
+** The only thing that remains to commit the transaction is to finalize
+** (delete, truncate or zero the first part of) the journal file (or
** delete the master journal file if specified).
**
** Note that if zMaster==NULL, this does not overwrite a previous value
@@ -36754,151 +43255,184 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
){
int rc = SQLITE_OK; /* Return code */
- /* The dbOrigSize is never set if journal_mode=OFF */
- assert( pPager->journalMode!=PAGER_JOURNALMODE_OFF || pPager->dbOrigSize==0 );
+ 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) );
- /* If a prior error occurred, this routine should not be called. ROLLBACK
- ** is the appropriate response to an error, not COMMIT. Guard against
- ** coding errors by repeating the prior error. */
+ /* If a prior error occurred, report that error again. */
if( NEVER(pPager->errCode) ) return pPager->errCode;
- PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n",
+ PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n",
pPager->zFilename, zMaster, pPager->dbSize));
- if( MEMDB && pPager->dbModified ){
+ /* If no database changes have been made, return early. */
+ if( pPager->eStatepBackup);
- }else if( pPager->state!=PAGER_SYNCED && pPager->dbModified ){
-
- /* 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 );
- if( !zMaster && isOpen(pPager->jfd)
- && pPager->journalOff==jrnlBufferSize(pPager)
- && pPager->dbSize>=pPager->dbFileSize
- && (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{
+ 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;
}
- }
-#else
- rc = pager_incr_changecounter(pPager, 0);
-#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.
- **
- ** When journal_mode==OFF the dbOrigSize is always zero, so this
- ** block never runs if journal_mode=OFF.
- */
-#ifndef SQLITE_OMIT_AUTOVACUUM
- if( pPager->dbSizedbOrigSize
- && ALWAYS(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;
+ assert( rc==SQLITE_OK );
+ if( ALWAYS(pList) ){
+ rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1,
+ (pPager->fullSync ? pPager->syncFlags : 0)
+ );
+ }
+ 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);
}
}
- 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.
- */
- rc = writeMasterJournal(pPager, zMaster);
- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
-
- /* Sync the journal file. If the atomic-update optimization is being
- ** used, this call will not create the journal file or perform any
- ** real IO.
- */
- rc = syncJournal(pPager);
- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
-
- /* Write all dirty pages to the database file. */
- rc = pager_write_pagelist(sqlite3PcacheDirtyList(pPager->pPCache));
- if( rc!=SQLITE_OK ){
- assert( rc!=SQLITE_IOERR_BLOCKED );
- 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 ){
- Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager));
- assert( pPager->state>=PAGER_EXCLUSIVE );
- rc = pager_truncate(pPager, nNew);
+ #else
+ rc = pager_incr_changecounter(pPager, 0);
+ #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->dbSizedbOrigSize
+ && 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.
+ */
+ 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 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 ){
+ Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager));
+ assert( pPager->eState==PAGER_WRITER_DBMOD );
+ rc = pager_truncate(pPager, nNew);
+ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+ }
+
+ /* Finally, sync the database file. */
+ if( !noSync ){
+ rc = sqlite3PagerSync(pPager);
+ }
+ IOTRACE(("DBSYNC %p\n", pPager))
}
-
- /* Finally, sync the database file. */
- if( !pPager->noSync && !noSync ){
- rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
- }
- IOTRACE(("DBSYNC %p\n", pPager))
-
- pPager->state = PAGER_SYNCED;
}
commit_phase_one_exit:
+ if( rc==SQLITE_OK && !pagerUseWal(pPager) ){
+ pPager->eState = PAGER_WRITER_FINISHED;
+ }
return rc;
}
@@ -36906,12 +43440,12 @@ commit_phase_one_exit:
/*
** 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
+** 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
+** 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.
**
@@ -36926,112 +43460,103 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){
** called, just return the same error code without doing anything. */
if( NEVER(pPager->errCode) ) return pPager->errCode;
- /* This function should not be called if the pager is not in at least
- ** PAGER_RESERVED state. And indeed SQLite never does this. But it is
- ** nice to have this defensive test here anyway.
- */
- if( NEVER(pPager->stateeState==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
+ ** 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
+ ** 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->dbModified==0 && pPager->exclusiveMode
+ if( pPager->eState==PAGER_WRITER_LOCKED
+ && pPager->exclusiveMode
&& pPager->journalMode==PAGER_JOURNALMODE_PERSIST
){
- assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) );
+ assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) || !pPager->journalOff );
+ pPager->eState = PAGER_READER;
return SQLITE_OK;
}
PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
- assert( pPager->state==PAGER_SYNCED || MEMDB || !pPager->dbModified );
rc = pager_end_transaction(pPager, pPager->setMaster);
return pager_error(pPager, rc);
}
/*
-** Rollback all changes. The database falls back to PAGER_SHARED mode.
+** 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.
**
-** This function performs two tasks:
+** 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.
**
-** 1) It rolls back the journal file, restoring all database file and
+** Otherwise, in rollback mode, this function performs two functions:
+**
+** 1) It rolls back the journal file, restoring all database file and
** in-memory cache pages to the state they were in when the transaction
** was opened, and
+**
** 2) It finalizes the journal file, so that it is not used for hot
** rollback at any point in the future.
**
-** subject to the following qualifications:
+** Finalization of the journal file (task 2) is only performed if the
+** rollback is successful.
**
-** * If the journal file is not yet open when this function is called,
-** then only (2) is performed. In this case there is no journal file
-** to roll back.
-**
-** * If in an error state other than SQLITE_FULL, then task (1) is
-** performed. If successful, task (2). Regardless of the outcome
-** of either, the error state error code is returned to the caller
-** (i.e. either SQLITE_IOERR or SQLITE_CORRUPT).
-**
-** * If the pager is in PAGER_RESERVED state, then attempt (1). Whether
-** or not (1) is succussful, also attempt (2). If successful, return
-** SQLITE_OK. Otherwise, enter the error state and return the first
-** error code encountered.
-**
-** In this case there is no chance that the database was written to.
-** So is safe to finalize the journal file even if the playback
-** (operation 1) failed. However the pager must enter the error state
-** as the contents of the in-memory cache are now suspect.
-**
-** * Finally, if in PAGER_EXCLUSIVE state, then attempt (1). Only
-** attempt (2) if (1) is successful. Return SQLITE_OK if successful,
-** otherwise enter the error state and return the error code from the
-** failing operation.
-**
-** In this case the database file may have been written to. So if the
-** playback operation did not succeed it would not be safe to finalize
-** the journal file. It needs to be left in the file-system so that
-** some other process can use it to restore the database state (by
-** hot-journal rollback).
+** 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 sqlite3PagerRollback(Pager *pPager){
int rc = SQLITE_OK; /* Return code */
PAGERTRACE(("ROLLBACK %d\n", PAGERID(pPager)));
- if( !pPager->dbModified || !isOpen(pPager->jfd) ){
- rc = pager_end_transaction(pPager, pPager->setMaster);
- }else if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
- if( pPager->state>=PAGER_EXCLUSIVE ){
- pager_playback(pPager, 0);
+
+ /* PagerRollback() is a no-op if called in READER or OPEN state. If
+ ** the pager is already in the ERROR state, the rollback is not
+ ** attempted here. Instead, the error code is returned to the caller.
+ */
+ assert( assert_pager_state(pPager) );
+ if( pPager->eState==PAGER_ERROR ) return pPager->errCode;
+ if( pPager->eState<=PAGER_READER ) return SQLITE_OK;
+
+ if( pagerUseWal(pPager) ){
+ int rc2;
+ rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1);
+ rc2 = pager_end_transaction(pPager, pPager->setMaster);
+ 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);
+ 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;
}
- rc = pPager->errCode;
}else{
- if( pPager->state==PAGER_RESERVED ){
- int rc2;
- rc = pager_playback(pPager, 0);
- rc2 = pager_end_transaction(pPager, pPager->setMaster);
- if( rc==SQLITE_OK ){
- rc = rc2;
- }
- }else{
- rc = pager_playback(pPager, 0);
- }
-
- if( !MEMDB ){
- pPager->dbSizeValid = 0;
- }
-
- /* 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.
- */
- rc = pager_error(pPager, rc);
+ rc = pager_playback(pPager, 0);
}
- return rc;
+
+ assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK );
+ assert( rc==SQLITE_OK || rc==SQLITE_FULL || (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);
}
/*
@@ -37049,6 +43574,18 @@ SQLITE_PRIVATE int sqlite3PagerRefcount(Pager *pPager){
return sqlite3PcacheRefCount(pPager->pPCache);
}
+/*
+** 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;
+}
+
/*
** Return the number of references to the specified page.
*/
@@ -37065,8 +43602,8 @@ SQLITE_PRIVATE int *sqlite3PagerStats(Pager *pPager){
a[0] = sqlite3PcacheRefCount(pPager->pPCache);
a[1] = sqlite3PcachePagecount(pPager->pPCache);
a[2] = sqlite3PcacheGetCachesize(pPager->pPCache);
- a[3] = pPager->dbSizeValid ? (int) pPager->dbSize : -1;
- a[4] = pPager->state;
+ a[3] = pPager->eState==PAGER_OPEN ? -1 : (int) pPager->dbSize;
+ a[4] = pPager->eState;
a[5] = pPager->errCode;
a[6] = pPager->nHit;
a[7] = pPager->nMiss;
@@ -37090,7 +43627,7 @@ SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){
** 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
+** 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.
*/
@@ -37098,17 +43635,15 @@ SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
int rc = SQLITE_OK; /* Return code */
int nCurrent = pPager->nSavepoint; /* Current number of savepoints */
+ assert( pPager->eState>=PAGER_WRITER_LOCKED );
+ assert( assert_pager_state(pPager) );
+
if( nSavepoint>nCurrent && pPager->useJournal ){
int ii; /* Iterator variable */
PagerSavepoint *aNew; /* New Pager.aSavepoint array */
- /* Either there is no active journal or the sub-journal is open or
- ** the journal is always stored in memory */
- assert( pPager->nSavepoint==0 || isOpen(pPager->sjfd) ||
- pPager->journalMode==PAGER_JOURNALMODE_MEMORY );
-
/* Grow the Pager.aSavepoint array using realloc(). Return SQLITE_NOMEM
- ** if the allocation fails. Otherwise, zero the new portion in case a
+ ** 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(
@@ -37119,13 +43654,11 @@ SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
}
memset(&aNew[nCurrent], 0, (nSavepoint-nCurrent) * sizeof(PagerSavepoint));
pPager->aSavepoint = aNew;
- pPager->nSavepoint = nSavepoint;
/* Populate the PagerSavepoint structures just allocated. */
for(ii=nCurrent; iidbSizeValid );
aNew[ii].nOrig = pPager->dbSize;
- if( isOpen(pPager->jfd) && ALWAYS(pPager->journalOff>0) ){
+ if( isOpen(pPager->jfd) && pPager->journalOff>0 ){
aNew[ii].iOffset = pPager->journalOff;
}else{
aNew[ii].iOffset = JOURNAL_HDR_SZ(pPager);
@@ -37135,10 +43668,12 @@ SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
if( !aNew[ii].pInSavepoint ){
return SQLITE_NOMEM;
}
+ if( pagerUseWal(pPager) ){
+ sqlite3WalSavepoint(pPager->pWal, aNew[ii].aWalData);
+ }
+ pPager->nSavepoint = ii+1;
}
-
- /* Open the sub-journal, if it is not already opened. */
- rc = openSubJournal(pPager);
+ assert( pPager->nSavepoint==nSavepoint );
assertTruncateConstraint(pPager);
}
@@ -37147,7 +43682,7 @@ SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
/*
** This function is called to rollback or release (commit) a savepoint.
-** The savepoint to release or rollback need not be the most recently
+** The savepoint to release or rollback need not be the most recently
** created savepoint.
**
** Parameter op is always either SAVEPOINT_ROLLBACK or SAVEPOINT_RELEASE.
@@ -37155,38 +43690,38 @@ SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
** 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
+** 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
+** 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.
+** the transaction or unlock the database, it just restores the
+** contents of the database to its original state.
**
-** In any case, all savepoints with an index greater than iSavepoint
+** 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
+** 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 = SQLITE_OK;
+ int rc = pPager->errCode; /* Return code */
assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK );
assert( iSavepoint>=0 || op==SAVEPOINT_ROLLBACK );
- if( iSavepointnSavepoint ){
+ if( rc==SQLITE_OK && iSavepointnSavepoint ){
int ii; /* Iterator variable */
int nNew; /* Number of remaining savepoints after this op. */
/* Figure out how many savepoints will still be active after this
- ** operation. Store this value in nNew. Then free resources associated
+ ** 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);
@@ -37195,7 +43730,7 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
}
pPager->nSavepoint = nNew;
- /* If this is a release of the outermost savepoint, truncate
+ /* 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) ){
@@ -37212,13 +43747,13 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
** 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( isOpen(pPager->jfd) ){
+ else if( pagerUseWal(pPager) || isOpen(pPager->jfd) ){
PagerSavepoint *pSavepoint = (nNew==0)?0:&pPager->aSavepoint[nNew-1];
rc = pagerPlaybackSavepoint(pPager, pSavepoint);
assert(rc!=SQLITE_DONE);
}
-
}
+
return rc;
}
@@ -37264,7 +43799,7 @@ SQLITE_PRIVATE int sqlite3PagerNosync(Pager *pPager){
/*
** Set or retrieve the codec for this pager
*/
-static void sqlite3PagerSetCodec(
+SQLITE_PRIVATE void sqlite3PagerSetCodec(
Pager *pPager,
void *(*xCodec)(void*,void*,Pgno,int),
void (*xCodecSizeChng)(void*,int,int),
@@ -37278,7 +43813,7 @@ static void sqlite3PagerSetCodec(
pPager->pCodec = pCodec;
pagerReportSize(pPager);
}
-static void *sqlite3PagerGetCodec(Pager *pPager){
+SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){
return pPager->pCodec;
}
#endif
@@ -37302,8 +43837,8 @@ static void *sqlite3PagerGetCodec(Pager *pPager){
** transaction is active).
**
** If the fourth argument, isCommit, is non-zero, then this page is being
-** moved as part of a database reorganization just before the transaction
-** is being committed. In this case, it is guaranteed that the database page
+** moved as part of a database reorganization just before the transaction
+** is being committed. In this case, it is guaranteed that the database page
** pPg refers to will not be written to again within this transaction.
**
** This function may return SQLITE_NOMEM or an IO error code if an error
@@ -37316,6 +43851,10 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
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.
@@ -37326,7 +43865,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
}
/* 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
+ ** savepoint, then save the current contents of the page into the
** sub-journal now. This is required to handle the following scenario:
**
** BEGIN;
@@ -37350,7 +43889,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
return rc;
}
- PAGERTRACE(("MOVE %d page %d (needSync=%d) moves to %d\n",
+ 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))
@@ -37358,19 +43897,18 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
** 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
+ ** 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( pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize );
assert( pPg->flags&PGHDR_DIRTY );
- assert( pPager->needSync );
}
/* If the cache contains a page with page-number pgno, remove it
- ** from its hash chain. Also, if the PgHdr.needSync was set for
- ** page pgno before the 'move' operation, it needs to be retained
+ ** 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;
@@ -37381,7 +43919,6 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
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. */
- assert( pPager->dbSizeValid );
sqlite3PcacheMove(pPgOld, pPager->dbSize+1);
}else{
sqlite3PcacheDrop(pPgOld);
@@ -37391,14 +43928,23 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
origPgno = pPg->pgno;
sqlite3PcacheMove(pPg, pgno);
sqlite3PcacheMakeDirty(pPg);
- pPager->dbModified = 1;
+
+ /* 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
+ /* 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
+ ** 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.needSync
+ ** 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
@@ -37407,12 +43953,8 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
** 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.
- **
- ** The sqlite3PagerGet() call may cause the journal to sync. So make
- ** sure the Pager.needSync flag is set too.
*/
PgHdr *pPgHdr;
- assert( pPager->needSync );
rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr);
if( rc!=SQLITE_OK ){
if( needSyncPgno<=pPager->dbOrigSize ){
@@ -37421,23 +43963,11 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
}
return rc;
}
- pPager->needSync = 1;
- assert( pPager->noSync==0 && !MEMDB );
pPgHdr->flags |= PGHDR_NEED_SYNC;
sqlite3PcacheMakeDirty(pPgHdr);
sqlite3PagerUnref(pPgHdr);
}
- /*
- ** 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 ){
- sqlite3PcacheMove(pPgOld, origPgno);
- sqlite3PagerUnref(pPgOld);
- }
-
return SQLITE_OK;
}
#endif
@@ -37451,7 +43981,7 @@ SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *pPg){
}
/*
-** Return a pointer to the Pager.nExtra bytes of "extra" space
+** Return a pointer to the Pager.nExtra bytes of "extra" space
** allocated along with the specified page.
*/
SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *pPg){
@@ -37460,7 +43990,7 @@ SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *pPg){
/*
** Get/set the locking-mode for this pager. Parameter eMode must be one
-** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or
+** 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.
**
@@ -37474,55 +44004,145 @@ SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *pPager, int eMode){
|| eMode==PAGER_LOCKINGMODE_EXCLUSIVE );
assert( PAGER_LOCKINGMODE_QUERY<0 );
assert( PAGER_LOCKINGMODE_NORMAL>=0 && PAGER_LOCKINGMODE_EXCLUSIVE>=0 );
- if( eMode>=0 && !pPager->tempFile ){
+ assert( pPager->exclusiveMode || 0==sqlite3WalHeapMemory(pPager->pWal) );
+ if( eMode>=0 && !pPager->tempFile && !sqlite3WalHeapMemory(pPager->pWal) ){
pPager->exclusiveMode = (u8)eMode;
}
return (int)pPager->exclusiveMode;
}
/*
-** Get/set the journal-mode for this pager. Parameter eMode must be one of:
+** Set the journal-mode for this pager. Parameter eMode must be one of:
**
-** PAGER_JOURNALMODE_QUERY
** PAGER_JOURNALMODE_DELETE
** PAGER_JOURNALMODE_TRUNCATE
** PAGER_JOURNALMODE_PERSIST
** PAGER_JOURNALMODE_OFF
** PAGER_JOURNALMODE_MEMORY
+** PAGER_JOURNALMODE_WAL
**
-** If the parameter is not _QUERY, then the journal_mode is set to the
-** value specified if the change is allowed. The change is disallowed
-** for the following reasons:
+** The journalmode is set to the value specified if the change is allowed.
+** The change may be disallowed for the following reasons:
**
** * An in-memory database can only have its journal_mode set to _OFF
** or _MEMORY.
**
-** * The journal mode may not be changed while a transaction is active.
+** * Temporary databases cannot have _WAL journalmode.
**
** The returned indicate the current (possibly updated) journal-mode.
*/
-SQLITE_PRIVATE int sqlite3PagerJournalMode(Pager *pPager, int eMode){
- assert( eMode==PAGER_JOURNALMODE_QUERY
- || eMode==PAGER_JOURNALMODE_DELETE
+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_OFF
+ || eMode==PAGER_JOURNALMODE_WAL
|| eMode==PAGER_JOURNALMODE_MEMORY );
- assert( PAGER_JOURNALMODE_QUERY<0 );
- if( eMode>=0
- && (!MEMDB || eMode==PAGER_JOURNALMODE_MEMORY
- || eMode==PAGER_JOURNALMODE_OFF)
- && !pPager->dbModified
- && (!isOpen(pPager->jfd) || 0==pPager->journalOff)
- ){
- if( isOpen(pPager->jfd) ){
- sqlite3OsClose(pPager->jfd);
+
+ /* This routine is only called from the OP_JournalMode opcode, and
+ ** the logic there will never allow a temporary file to be changed
+ ** to WAL mode.
+ */
+ assert( pPager->tempFile==0 || eMode!=PAGER_JOURNALMODE_WAL );
+
+ /* Do allow the journalmode of an in-memory database to be set to
+ ** anything other than MEMORY or OFF
+ */
+ if( MEMDB ){
+ assert( eOld==PAGER_JOURNALMODE_MEMORY || eOld==PAGER_JOURNALMODE_OFF );
+ if( eMode!=PAGER_JOURNALMODE_MEMORY && eMode!=PAGER_JOURNALMODE_OFF ){
+ eMode = eOld;
}
- pPager->journalMode = (u8)eMode;
}
+
+ 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;
}
+/*
+** Return the current journal mode.
+*/
+SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager *pPager){
+ return (int)pPager->journalMode;
+}
+
+/*
+** Return TRUE if the pager is in a state where it is OK to change the
+** journalmode. Journalmode changes can only happen when the database
+** is unmodified.
+*/
+SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager *pPager){
+ assert( assert_pager_state(pPager) );
+ if( pPager->eState>=PAGER_WRITER_CACHEMOD ) return 0;
+ if( NEVER(isOpen(pPager->jfd) && pPager->journalOff>0) ) return 0;
+ return 1;
+}
+
/*
** Get/set the size-limit used for persistent journal files.
**
@@ -37532,6 +44152,7 @@ SQLITE_PRIVATE int sqlite3PagerJournalMode(Pager *pPager, int eMode){
SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *pPager, i64 iLimit){
if( iLimit>=-1 ){
pPager->journalSizeLimit = iLimit;
+ sqlite3WalLimit(pPager->pWal, iLimit);
}
return pPager->journalSizeLimit;
}
@@ -37546,9 +44167,3156 @@ SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){
return &pPager->pBackup;
}
+#ifndef SQLITE_OMIT_WAL
+/*
+** This function is called when the user invokes "PRAGMA wal_checkpoint",
+** "PRAGMA wal_blocking_checkpoint" or calls the sqlite3_wal_checkpoint()
+** or wal_blocking_checkpoint() API functions.
+**
+** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
+*/
+SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt){
+ int rc = SQLITE_OK;
+ if( pPager->pWal ){
+ rc = sqlite3WalCheckpoint(pPager->pWal, eMode,
+ pPager->xBusyHandler, pPager->pBusyHandlerArg,
+ pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
+ pnLog, pnCkpt
+ );
+ }
+ return rc;
+}
+
+SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
+ return sqlite3WalCallback(pPager->pWal);
+}
+
+/*
+** 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);
+}
+
+/*
+** Attempt to take an exclusive lock on the database file. If a PENDING lock
+** is obtained instead, immediately release it.
+*/
+static int pagerExclusiveLock(Pager *pPager){
+ int rc; /* Return code */
+
+ assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK );
+ rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
+ if( rc!=SQLITE_OK ){
+ /* If the attempt to grab the exclusive lock failed, release the
+ ** pending lock that may have been obtained instead. */
+ pagerUnlockDb(pPager, SHARED_LOCK);
+ }
+
+ return rc;
+}
+
+/*
+** Call sqlite3WalOpen() to open the WAL handle. If the pager is in
+** exclusive-locking mode when this function is called, take an EXCLUSIVE
+** lock on the database file and use heap-memory to store the wal-index
+** in. Otherwise, use the normal shared-memory.
+*/
+static int pagerOpenWal(Pager *pPager){
+ int rc = SQLITE_OK;
+
+ assert( pPager->pWal==0 && pPager->tempFile==0 );
+ assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK || pPager->noReadlock);
+
+ /* 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
+ );
+ }
+
+ return rc;
+}
+
+
+/*
+** The caller must be holding a SHARED lock on the database file to call
+** this function.
+**
+** If the pager passed as the first argument is open on a real database
+** file (not a temp file or an in-memory database), and the WAL file
+** is not already open, make an attempt to open it now. If successful,
+** return SQLITE_OK. If an error occurs or the VFS used by the pager does
+** not support the xShmXXX() methods, return an error code. *pbOpen is
+** not modified in either case.
+**
+** If the pager is 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 */
+
+ assert( assert_pager_state(pPager) );
+ assert( pPager->eState==PAGER_OPEN || pbOpen );
+ assert( pPager->eState==PAGER_READER || !pbOpen );
+ assert( pbOpen==0 || *pbOpen==0 );
+ assert( pbOpen!=0 || (!pPager->tempFile && !pPager->pWal) );
+
+ if( !pPager->tempFile && !pPager->pWal ){
+ if( !sqlite3PagerWalSupported(pPager) ) return SQLITE_CANTOPEN;
+
+ /* Close any rollback journal previously open */
+ sqlite3OsClose(pPager->jfd);
+
+ rc = pagerOpenWal(pPager);
+ if( rc==SQLITE_OK ){
+ pPager->journalMode = PAGER_JOURNALMODE_WAL;
+ pPager->eState = PAGER_OPEN;
+ }
+ }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.
+**
+** 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;
+ }
+ }
+ return rc;
+}
+
+#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.
+*/
+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 */
+
+#endif /* !SQLITE_OMIT_WAL */
+
#endif /* SQLITE_OMIT_DISKIO */
/************** End of pager.c ***********************************************/
+/************** Begin file wal.c *********************************************/
+/*
+** 2010 February 1
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** This file contains the implementation of a write-ahead log (WAL) used in
+** "journal_mode=WAL" mode.
+**
+** WRITE-AHEAD LOG (WAL) FILE FORMAT
+**
+** A WAL file consists of a header followed by zero or more "frames".
+** Each frame records the revised content of a single page from the
+** database file. All changes to the database are recorded by writing
+** frames into the WAL. Transactions commit when a frame is written that
+** contains a commit marker. A single WAL can and usually does record
+** multiple transactions. Periodically, the content of the WAL is
+** transferred back into the database file in an operation called a
+** "checkpoint".
+**
+** A single WAL file can be used multiple times. In other words, the
+** WAL can fill up with frames and then be checkpointed and then new
+** frames can overwrite the old ones. A WAL always grows from beginning
+** toward the end. Checksums and counters attached to each frame are
+** used to determine which frames within the WAL are valid and which
+** are leftovers from prior checkpoints.
+**
+** The WAL header is 32 bytes in size and consists of the following eight
+** big-endian 32-bit unsigned integer values:
+**
+** 0: Magic number. 0x377f0682 or 0x377f0683
+** 4: File format version. Currently 3007000
+** 8: Database page size. Example: 1024
+** 12: Checkpoint sequence number
+** 16: Salt-1, random integer incremented with each checkpoint
+** 20: Salt-2, a different random integer changing with each ckpt
+** 24: Checksum-1 (first part of checksum for first 24 bytes of header).
+** 28: Checksum-2 (second part of checksum for first 24 bytes of header).
+**
+** Immediately following the wal-header are zero or more frames. Each
+** frame consists of a 24-byte frame-header followed by a 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, return the index of the last frame for page P in the WAL,
+** or return NULL if there are no frames for page P in the WAL.
+**
+** 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 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
+
+
+/*
+** Trace output macros
+*/
+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+SQLITE_PRIVATE int sqlite3WalTrace = 0;
+# define WALTRACE(X) if(sqlite3WalTrace) sqlite3DebugPrintf X
+#else
+# define WALTRACE(X)
+#endif
+
+/*
+** The maximum (and only) versions of the wal and wal-index formats
+** that may be interpreted by this version of SQLite.
+**
+** If a client begins recovering a WAL file and finds that (a) the checksum
+** values in the wal-header are correct and (b) the version field is not
+** WAL_MAX_VERSION, recovery fails and SQLite returns SQLITE_CANTOPEN.
+**
+** Similarly, if a client successfully reads a wal-index header (i.e. the
+** checksum test is successful) and finds that the version field is not
+** WALINDEX_MAX_VERSION, then no read-transaction is opened and SQLite
+** returns SQLITE_CANTOPEN.
+*/
+#define WAL_MAX_VERSION 3007000
+#define WALINDEX_MAX_VERSION 3007000
+
+/*
+** Indices of various locking bytes. WAL_NREADER is the number
+** of available reader locks and should be at least 3.
+*/
+#define WAL_WRITE_LOCK 0
+#define WAL_ALL_BUT_WRITE 1
+#define WAL_CKPT_LOCK 1
+#define WAL_RECOVER_LOCK 2
+#define WAL_READ_LOCK(I) (3+(I))
+#define WAL_NREADER (SQLITE_SHM_NLOCK-3)
+
+
+/* Object declarations */
+typedef struct WalIndexHdr WalIndexHdr;
+typedef struct WalIterator WalIterator;
+typedef struct WalCkptInfo WalCkptInfo;
+
+
+/*
+** The following object holds a copy of the wal-index header content.
+**
+** The actual header in the wal-index consists of two copies of this
+** object.
+**
+** The szPage value can be any power of 2 between 512 and 32768, inclusive.
+** Or it can be 1 to represent a 65536-byte page. The latter case was
+** added in 3.7.1 when support for 64K pages was added.
+*/
+struct WalIndexHdr {
+ u32 iVersion; /* Wal-index version */
+ u32 unused; /* Unused (padding) field */
+ u32 iChange; /* Counter incremented each transaction */
+ u8 isInit; /* 1 when initialized */
+ u8 bigEndCksum; /* True if checksums in WAL are big-endian */
+ u16 szPage; /* Database page size in bytes. 1==64K */
+ u32 mxFrame; /* Index of last valid frame in the WAL */
+ u32 nPage; /* Size of database in pages */
+ u32 aFrameCksum[2]; /* Checksum of last frame in log */
+ u32 aSalt[2]; /* Two salt values copied from WAL header */
+ u32 aCksum[2]; /* Checksum over all prior fields */
+};
+
+/*
+** 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.
+**
+** nBackfill is the number of frames in the WAL that have been written
+** back into the database. (We call the act of moving content from WAL to
+** database "backfilling".) The nBackfill number is never greater than
+** WalIndexHdr.mxFrame. nBackfill can only be increased by threads
+** holding the WAL_CKPT_LOCK lock (which includes a recovery thread).
+** However, a WAL_WRITE_LOCK thread can move the value of nBackfill from
+** mxFrame back to zero when the WAL is reset.
+**
+** There is one entry in aReadMark[] for each reader lock. If a reader
+** holds read-lock K, then the value in aReadMark[K] is no greater than
+** the mxFrame for that reader. The value READMARK_NOT_USED (0xffffffff)
+** for any aReadMark[] means that entry is unused. aReadMark[0] is
+** a special case; its value is never used and it exists as a place-holder
+** to avoid having to offset aReadMark[] indexs by one. Readers holding
+** WAL_READ_LOCK(0) always ignore the entire WAL and read all content
+** directly from the database.
+**
+** The value of aReadMark[K] may only be changed by a thread that
+** is holding an exclusive lock on WAL_READ_LOCK(K). Thus, the value of
+** aReadMark[K] cannot changed while there is a reader is using that mark
+** since the reader will be holding a shared lock on WAL_READ_LOCK(K).
+**
+** The checkpointer may only transfer frames from WAL to database where
+** the frame numbers are less than or equal to every aReadMark[] that is
+** in use (that is, every aReadMark[j] for which there is a corresponding
+** WAL_READ_LOCK(j)). New readers (usually) pick the aReadMark[] with the
+** largest value and will increase an unused aReadMark[] to mxFrame if there
+** is not already an aReadMark[] equal to mxFrame. The exception to the
+** previous sentence is when nBackfill equals mxFrame (meaning that everything
+** in the WAL has been backfilled into the database) then new readers
+** will choose aReadMark[0] which has value 0 and hence such reader will
+** get all their all content directly from the database file and ignore
+** the WAL.
+**
+** Writers normally append new frames to the end of the WAL. However,
+** if nBackfill equals mxFrame (meaning that all WAL content has been
+** written back into the database) and if no readers are using the WAL
+** (in other words, if there are no WAL_READ_LOCK(i) where i>0) then
+** the writer will first "reset" the WAL back to the beginning and start
+** writing new content beginning at frame 1.
+**
+** We assume that 32-bit loads are atomic and so no locks are needed in
+** order to read from any aReadMark[] entries.
+*/
+struct WalCkptInfo {
+ u32 nBackfill; /* Number of WAL frames backfilled into DB */
+ u32 aReadMark[WAL_NREADER]; /* Reader marks */
+};
+#define READMARK_NOT_USED 0xffffffff
+
+
+/* A block of WALINDEX_LOCK_RESERVED bytes beginning at
+** WALINDEX_LOCK_OFFSET is reserved for locks. Since some systems
+** only support mandatory file-locks, we do not read or write data
+** from the region of the file on which locks are applied.
+*/
+#define WALINDEX_LOCK_OFFSET (sizeof(WalIndexHdr)*2 + sizeof(WalCkptInfo))
+#define WALINDEX_LOCK_RESERVED 16
+#define WALINDEX_HDR_SIZE (WALINDEX_LOCK_OFFSET+WALINDEX_LOCK_RESERVED)
+
+/* Size of header before each frame in wal */
+#define WAL_FRAME_HDRSIZE 24
+
+/* Size of write ahead log header, including checksum. */
+/* #define WAL_HDRSIZE 24 */
+#define WAL_HDRSIZE 32
+
+/* WAL magic value. Either this value, or the same value with the least
+** significant bit also set (WAL_MAGIC | 0x00000001) is stored in 32-bit
+** big-endian format in the first 4 bytes of a WAL file.
+**
+** If the LSB is set, then the checksums for each frame within the WAL
+** file are calculated by treating all data as an array of 32-bit
+** big-endian words. Otherwise, they are calculated by interpreting
+** all data as 32-bit little-endian words.
+*/
+#define WAL_MAGIC 0x377f0682
+
+/*
+** Return the offset of frame iFrame in the write-ahead log file,
+** assuming a database page size of szPage bytes. The offset returned
+** is to the start of the write-ahead log frame-header.
+*/
+#define walFrameOffset(iFrame, szPage) ( \
+ WAL_HDRSIZE + ((iFrame)-1)*(i64)((szPage)+WAL_FRAME_HDRSIZE) \
+)
+
+/*
+** An open write-ahead log file is represented by an instance of the
+** following object.
+*/
+struct Wal {
+ sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */
+ sqlite3_file *pDbFd; /* File handle for the database file */
+ sqlite3_file *pWalFd; /* File handle for WAL file */
+ u32 iCallback; /* Value to pass to log callback (or 0) */
+ i64 mxWalSize; /* Truncate WAL to this size upon reset */
+ int nWiData; /* Size of array apWiData */
+ volatile u32 **apWiData; /* Pointer to wal-index content in memory */
+ u32 szPage; /* Database page size */
+ i16 readLock; /* Which read lock is being held. -1 for none */
+ u8 exclusiveMode; /* Non-zero if connection is in exclusive mode */
+ u8 writeLock; /* True if in a write transaction */
+ u8 ckptLock; /* True if holding a checkpoint lock */
+ u8 readOnly; /* WAL_RDWR, WAL_RDONLY, or WAL_SHM_RDONLY */
+ WalIndexHdr hdr; /* Wal-index header for current transaction */
+ const char *zWalName; /* Name of WAL file */
+ u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
+#ifdef SQLITE_DEBUG
+ u8 lockError; /* True if a locking error has occurred */
+#endif
+};
+
+/*
+** Candidate values for Wal.exclusiveMode.
+*/
+#define WAL_NORMAL_MODE 0
+#define WAL_EXCLUSIVE_MODE 1
+#define WAL_HEAPMEMORY_MODE 2
+
+/*
+** Possible values for WAL.readOnly
+*/
+#define WAL_RDWR 0 /* Normal read/write connection */
+#define WAL_RDONLY 1 /* The WAL file is readonly */
+#define WAL_SHM_RDONLY 2 /* The SHM file is readonly */
+
+/*
+** Each page of the wal-index mapping contains a hash-table made up of
+** an array of HASHTABLE_NSLOT elements of the following type.
+*/
+typedef u16 ht_slot;
+
+/*
+** This structure is used to implement an iterator that loops through
+** all frames in the WAL in database page order. Where two or more frames
+** correspond to the same database page, the iterator visits only the
+** frame most recently written to the WAL (in other words, the frame with
+** the largest index).
+**
+** The internals of this structure are only accessed by:
+**
+** walIteratorInit() - Create a new iterator,
+** walIteratorNext() - Step an iterator,
+** walIteratorFree() - Free an iterator.
+**
+** This functionality is used by the checkpoint code (see walCheckpoint()).
+*/
+struct WalIterator {
+ int iPrior; /* Last result returned from the iterator */
+ int nSegment; /* Number of entries in aSegment[] */
+ struct WalSegment {
+ int iNext; /* Next slot in aIndex[] not yet returned */
+ ht_slot *aIndex; /* i0, i1, i2... such that aPgno[iN] ascend */
+ u32 *aPgno; /* Array of page numbers. */
+ int nEntry; /* Nr. of entries in aPgno[] and aIndex[] */
+ int iZero; /* Frame number associated with aPgno[0] */
+ } aSegment[1]; /* One for every 32KB page in the wal-index */
+};
+
+/*
+** Define the parameters of the hash tables in the wal-index file. There
+** is a hash-table following every HASHTABLE_NPAGE page numbers in the
+** wal-index.
+**
+** Changing any of these constants will alter the wal-index format and
+** create incompatibilities.
+*/
+#define HASHTABLE_NPAGE 4096 /* Must be power of 2 */
+#define HASHTABLE_HASH_1 383 /* Should be prime */
+#define HASHTABLE_NSLOT (HASHTABLE_NPAGE*2) /* Must be a power of 2 */
+
+/*
+** The block of page numbers associated with the first hash-table in a
+** wal-index is smaller than usual. This is so that there is a complete
+** hash-table on each aligned 32KB page of the wal-index.
+*/
+#define HASHTABLE_NPAGE_ONE (HASHTABLE_NPAGE - (WALINDEX_HDR_SIZE/sizeof(u32)))
+
+/* The wal-index is divided into pages of WALINDEX_PGSZ bytes each. */
+#define WALINDEX_PGSZ ( \
+ sizeof(ht_slot)*HASHTABLE_NSLOT + HASHTABLE_NPAGE*sizeof(u32) \
+)
+
+/*
+** Obtain a pointer to the iPage'th page of the wal-index. The wal-index
+** is broken into pages of WALINDEX_PGSZ bytes. Wal-index pages are
+** numbered from zero.
+**
+** If this call is successful, *ppPage is set to point to the wal-index
+** page and SQLITE_OK is returned. If an error (an OOM or VFS error) occurs,
+** then an SQLite error code is returned and *ppPage is set to 0.
+*/
+static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
+ int rc = SQLITE_OK;
+
+ /* Enlarge the pWal->apWiData[] array if required */
+ if( pWal->nWiData<=iPage ){
+ int nByte = sizeof(u32*)*(iPage+1);
+ volatile u32 **apNew;
+ apNew = (volatile u32 **)sqlite3_realloc((void *)pWal->apWiData, nByte);
+ if( !apNew ){
+ *ppPage = 0;
+ return SQLITE_NOMEM;
+ }
+ memset((void*)&apNew[pWal->nWiData], 0,
+ sizeof(u32*)*(iPage+1-pWal->nWiData));
+ pWal->apWiData = apNew;
+ pWal->nWiData = iPage+1;
+ }
+
+ /* Request a pointer to the required page from the VFS */
+ if( pWal->apWiData[iPage]==0 ){
+ if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
+ pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ);
+ if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
+ pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
+ );
+ if( rc==SQLITE_READONLY ){
+ pWal->readOnly |= WAL_SHM_RDONLY;
+ rc = SQLITE_OK;
+ }
+ }
+ }
+
+ *ppPage = pWal->apWiData[iPage];
+ assert( iPage==0 || *ppPage || rc!=SQLITE_OK );
+ return rc;
+}
+
+/*
+** Return a pointer to the WalCkptInfo structure in the wal-index.
+*/
+static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
+ assert( pWal->nWiData>0 && pWal->apWiData[0] );
+ return (volatile WalCkptInfo*)&(pWal->apWiData[0][sizeof(WalIndexHdr)/2]);
+}
+
+/*
+** Return 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];
+}
+
+/*
+** The argument to this macro must be of type u32. On a little-endian
+** architecture, it returns the u32 value that results from interpreting
+** the 4 bytes as a big-endian value. On a big-endian architecture, it
+** returns the value that would be produced by intepreting the 4 bytes
+** of the input value as a little-endian integer.
+*/
+#define BYTESWAP32(x) ( \
+ (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \
+ + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \
+)
+
+/*
+** Generate or extend an 8 byte checksum based on the data in
+** array aByte[] and the initial values of aIn[0] and aIn[1] (or
+** initial values of 0 and 0 if aIn==NULL).
+**
+** The checksum is written back into aOut[] before returning.
+**
+** nByte must be a positive multiple of 8.
+*/
+static void walChecksumBytes(
+ int nativeCksum, /* True for native byte-order, false for non-native */
+ u8 *a, /* Content to be checksummed */
+ int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */
+ const u32 *aIn, /* Initial checksum value input */
+ u32 *aOut /* OUT: Final checksum value output */
+){
+ u32 s1, s2;
+ u32 *aData = (u32 *)a;
+ u32 *aEnd = (u32 *)&a[nByte];
+
+ if( aIn ){
+ s1 = aIn[0];
+ s2 = aIn[1];
+ }else{
+ s1 = s2 = 0;
+ }
+
+ assert( nByte>=8 );
+ assert( (nByte&0x00000007)==0 );
+
+ if( nativeCksum ){
+ do {
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ }while( aDataexclusiveMode!=WAL_HEAPMEMORY_MODE ){
+ sqlite3OsShmBarrier(pWal->pDbFd);
+ }
+}
+
+/*
+** Write the header information in pWal->hdr into the wal-index.
+**
+** The checksum on pWal->hdr is updated before it is written.
+*/
+static void walIndexWriteHdr(Wal *pWal){
+ volatile WalIndexHdr *aHdr = walIndexHdr(pWal);
+ const int nCksum = offsetof(WalIndexHdr, aCksum);
+
+ assert( pWal->writeLock );
+ pWal->hdr.isInit = 1;
+ pWal->hdr.iVersion = WALINDEX_MAX_VERSION;
+ walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum);
+ memcpy((void *)&aHdr[1], (void *)&pWal->hdr, sizeof(WalIndexHdr));
+ walShmBarrier(pWal);
+ memcpy((void *)&aHdr[0], (void *)&pWal->hdr, sizeof(WalIndexHdr));
+}
+
+/*
+** 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:
+**
+** 0: Page number.
+** 4: For commit records, the size of the database image in pages
+** after the commit. For all other records, zero.
+** 8: Salt-1 (copied from the wal-header)
+** 12: Salt-2 (copied from the wal-header)
+** 16: Checksum-1.
+** 20: Checksum-2.
+*/
+static void walEncodeFrame(
+ Wal *pWal, /* The write-ahead log */
+ u32 iPage, /* Database page number for frame */
+ u32 nTruncate, /* New db size (or 0 for non-commit frames) */
+ u8 *aData, /* Pointer to page data */
+ u8 *aFrame /* OUT: Write encoded frame here */
+){
+ int nativeCksum; /* True for native byte-order checksums */
+ u32 *aCksum = pWal->hdr.aFrameCksum;
+ assert( WAL_FRAME_HDRSIZE==24 );
+ sqlite3Put4byte(&aFrame[0], iPage);
+ sqlite3Put4byte(&aFrame[4], nTruncate);
+ memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
+
+ nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
+ walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
+ walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
+
+ sqlite3Put4byte(&aFrame[16], aCksum[0]);
+ sqlite3Put4byte(&aFrame[20], aCksum[1]);
+}
+
+/*
+** Check to see if the frame with header in aFrame[] and content
+** in aData[] is valid. If it is a valid frame, fill *piPage and
+** *pnTruncate and return true. Return if the frame is not valid.
+*/
+static int walDecodeFrame(
+ Wal *pWal, /* The write-ahead log */
+ u32 *piPage, /* OUT: Database page number for frame */
+ u32 *pnTruncate, /* OUT: New db size (or 0 if not commit) */
+ u8 *aData, /* Pointer to page data (for checksum) */
+ u8 *aFrame /* Frame data */
+){
+ int nativeCksum; /* True for native byte-order checksums */
+ u32 *aCksum = pWal->hdr.aFrameCksum;
+ u32 pgno; /* Page number of the frame */
+ assert( WAL_FRAME_HDRSIZE==24 );
+
+ /* A frame is only valid if the salt values in the frame-header
+ ** match the salt values in the wal-header.
+ */
+ if( memcmp(&pWal->hdr.aSalt, &aFrame[8], 8)!=0 ){
+ return 0;
+ }
+
+ /* A frame is only valid if the page number is creater than zero.
+ */
+ pgno = sqlite3Get4byte(&aFrame[0]);
+ if( pgno==0 ){
+ return 0;
+ }
+
+ /* A frame is only valid if a checksum of the WAL header,
+ ** all prior frams, the first 16 bytes of this frame-header,
+ ** and the frame-data matches the checksum in the last 8
+ ** bytes of this frame-header.
+ */
+ nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
+ walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
+ walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
+ if( aCksum[0]!=sqlite3Get4byte(&aFrame[16])
+ || aCksum[1]!=sqlite3Get4byte(&aFrame[20])
+ ){
+ /* Checksum failed. */
+ return 0;
+ }
+
+ /* 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)
+/*
+** Names of locks. This routine is used to provide debugging output and is not
+** a part of an ordinary build.
+*/
+static const char *walLockName(int lockIdx){
+ if( lockIdx==WAL_WRITE_LOCK ){
+ return "WRITE-LOCK";
+ }else if( lockIdx==WAL_CKPT_LOCK ){
+ return "CKPT-LOCK";
+ }else if( lockIdx==WAL_RECOVER_LOCK ){
+ return "RECOVER-LOCK";
+ }else{
+ static char zName[15];
+ sqlite3_snprintf(sizeof(zName), zName, "READ-LOCK[%d]",
+ lockIdx-WAL_READ_LOCK(0));
+ return zName;
+ }
+}
+#endif /*defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */
+
+
+/*
+** Set or release locks on the WAL. Locks are either shared or exclusive.
+** A lock cannot be moved directly between shared and exclusive - it must go
+** through the unlocked state first.
+**
+** In locking_mode=EXCLUSIVE, all of these routines become no-ops.
+*/
+static int walLockShared(Wal *pWal, int lockIdx){
+ int rc;
+ if( pWal->exclusiveMode ) return SQLITE_OK;
+ rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
+ SQLITE_SHM_LOCK | SQLITE_SHM_SHARED);
+ WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
+ walLockName(lockIdx), rc ? "failed" : "ok"));
+ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
+ return rc;
+}
+static void walUnlockShared(Wal *pWal, int lockIdx){
+ if( pWal->exclusiveMode ) return;
+ (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
+ SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED);
+ WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
+}
+static int walLockExclusive(Wal *pWal, int lockIdx, int n){
+ int rc;
+ if( pWal->exclusiveMode ) return SQLITE_OK;
+ rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
+ SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
+ WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
+ walLockName(lockIdx), n, rc ? "failed" : "ok"));
+ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
+ return rc;
+}
+static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
+ if( pWal->exclusiveMode ) return;
+ (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
+ SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE);
+ WALTRACE(("WAL%p: release EXCLUSIVE-%s cnt=%d\n", pWal,
+ walLockName(lockIdx), n));
+}
+
+/*
+** 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
+** numbered starting from 0.
+**
+** Set output variable *paHash to point to the start of the hash table
+** in the wal-index file. Set *piZero to one less than the frame
+** number of the first frame indexed by this hash table. If a
+** slot in the hash table is set to N, it refers to frame number
+** (*piZero+N) in the log.
+**
+** Finally, set *paPgno so that *paPgno[1] is the page number of the
+** first frame indexed by the hash table, frame (*piZero+1).
+*/
+static int walHashGet(
+ Wal *pWal, /* WAL handle */
+ int iHash, /* Find the iHash'th table */
+ volatile ht_slot **paHash, /* OUT: Pointer to hash index */
+ volatile u32 **paPgno, /* OUT: Pointer to page number array */
+ u32 *piZero /* OUT: Frame associated with *paPgno[0] */
+){
+ int rc; /* Return code */
+ volatile u32 *aPgno;
+
+ rc = walIndexPage(pWal, iHash, &aPgno);
+ assert( rc==SQLITE_OK || iHash>0 );
+
+ if( rc==SQLITE_OK ){
+ u32 iZero;
+ volatile ht_slot *aHash;
+
+ aHash = (volatile ht_slot *)&aPgno[HASHTABLE_NPAGE];
+ if( iHash==0 ){
+ aPgno = &aPgno[WALINDEX_HDR_SIZE/sizeof(u32)];
+ iZero = 0;
+ }else{
+ iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE;
+ }
+
+ *paPgno = &aPgno[-1];
+ *paHash = aHash;
+ *piZero = iZero;
+ }
+ return rc;
+}
+
+/*
+** Return the number of the wal-index page that contains the hash-table
+** and page-number array that contain entries corresponding to WAL frame
+** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages
+** are numbered starting from 0.
+*/
+static int walFramePage(u32 iFrame){
+ int iHash = (iFrame+HASHTABLE_NPAGE-HASHTABLE_NPAGE_ONE-1) / HASHTABLE_NPAGE;
+ assert( (iHash==0 || iFrame>HASHTABLE_NPAGE_ONE)
+ && (iHash>=1 || iFrame<=HASHTABLE_NPAGE_ONE)
+ && (iHash<=1 || iFrame>(HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE))
+ && (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE)
+ && (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE))
+ );
+ return iHash;
+}
+
+/*
+** Return the page number associated with frame iFrame in this WAL.
+*/
+static u32 walFramePgno(Wal *pWal, u32 iFrame){
+ int iHash = walFramePage(iFrame);
+ if( iHash==0 ){
+ return pWal->apWiData[0][WALINDEX_HDR_SIZE/sizeof(u32) + iFrame - 1];
+ }
+ return pWal->apWiData[iHash][(iFrame-1-HASHTABLE_NPAGE_ONE)%HASHTABLE_NPAGE];
+}
+
+/*
+** Remove entries from the hash table that point to WAL slots greater
+** than pWal->hdr.mxFrame.
+**
+** This function is called whenever pWal->hdr.mxFrame is decreased due
+** to a rollback or savepoint.
+**
+** At most only the hash table containing pWal->hdr.mxFrame needs to be
+** updated. Any later hash tables will be automatically cleared when
+** pWal->hdr.mxFrame advances to the point where those hash tables are
+** actually needed.
+*/
+static void walCleanupHash(Wal *pWal){
+ volatile ht_slot *aHash = 0; /* Pointer to hash table to clear */
+ volatile u32 *aPgno = 0; /* Page number array for hash table */
+ u32 iZero = 0; /* frame == (aHash[x]+iZero) */
+ int iLimit = 0; /* Zero values greater than this */
+ int nByte; /* Number of bytes to zero in aPgno[] */
+ int i; /* Used to iterate through aHash[] */
+
+ assert( pWal->writeLock );
+ testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE-1 );
+ testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE );
+ testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE+1 );
+
+ if( pWal->hdr.mxFrame==0 ) return;
+
+ /* Obtain pointers to the hash-table and page-number array containing
+ ** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed
+ ** that the page said hash-table and array reside on is already mapped.
+ */
+ assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) );
+ assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] );
+ walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &aHash, &aPgno, &iZero);
+
+ /* Zero all hash-table entries that correspond to frame numbers greater
+ ** than pWal->hdr.mxFrame.
+ */
+ iLimit = pWal->hdr.mxFrame - iZero;
+ assert( iLimit>0 );
+ for(i=0; iiLimit ){
+ aHash[i] = 0;
+ }
+ }
+
+ /* Zero the entries in the aPgno array that correspond to frames with
+ ** frame numbers greater than pWal->hdr.mxFrame.
+ */
+ nByte = (int)((char *)aHash - (char *)&aPgno[iLimit+1]);
+ memset((void *)&aPgno[iLimit+1], 0, nByte);
+
+#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+ /* Verify that the every entry in the mapping region is still reachable
+ ** via the hash table even after the cleanup.
+ */
+ if( iLimit ){
+ int i; /* Loop counter */
+ int iKey; /* Hash key */
+ for(i=1; i<=iLimit; i++){
+ for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
+ if( aHash[iKey]==i ) break;
+ }
+ assert( aHash[iKey]==i );
+ }
+ }
+#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
+}
+
+
+/*
+** Set an entry in the wal-index that will map database page number
+** pPage into WAL frame iFrame.
+*/
+static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
+ int rc; /* Return code */
+ u32 iZero = 0; /* One less than frame number of aPgno[1] */
+ volatile u32 *aPgno = 0; /* Page number array */
+ volatile ht_slot *aHash = 0; /* Hash table */
+
+ rc = walHashGet(pWal, walFramePage(iFrame), &aHash, &aPgno, &iZero);
+
+ /* Assuming the wal-index file was successfully mapped, populate the
+ ** page number array and hash table entry.
+ */
+ if( rc==SQLITE_OK ){
+ int iKey; /* Hash table key */
+ int idx; /* Value to write to hash-table slot */
+ int nCollide; /* Number of hash collisions */
+
+ idx = iFrame - iZero;
+ assert( idx <= HASHTABLE_NSLOT/2 + 1 );
+
+ /* If this is the first entry to be added to this hash-table, zero the
+ ** entire hash table and aPgno[] array before proceding.
+ */
+ if( idx==1 ){
+ int nByte = (int)((u8 *)&aHash[HASHTABLE_NSLOT] - (u8 *)&aPgno[1]);
+ memset((void*)&aPgno[1], 0, nByte);
+ }
+
+ /* If the entry in aPgno[] is already set, then the previous writer
+ ** must have exited unexpectedly in the middle of a transaction (after
+ ** writing one or more dirty pages to the WAL to free up memory).
+ ** Remove the remnants of that writers uncommitted transaction from
+ ** the hash-table before writing any new entries.
+ */
+ if( aPgno[idx] ){
+ walCleanupHash(pWal);
+ assert( !aPgno[idx] );
+ }
+
+ /* Write the aPgno[] array entry and the hash-table slot. */
+ nCollide = idx;
+ for(iKey=walHash(iPage); aHash[iKey]; iKey=walNextHash(iKey)){
+ if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT;
+ }
+ aPgno[idx] = iPage;
+ aHash[iKey] = (ht_slot)idx;
+
+#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+ /* Verify that the number of entries in the hash table exactly equals
+ ** the number of entries in the mapping region.
+ */
+ {
+ int i; /* Loop counter */
+ int nEntry = 0; /* Number of entries in the hash table */
+ for(i=0; ickptLock==1 || pWal->ckptLock==0 );
+ assert( WAL_ALL_BUT_WRITE==WAL_WRITE_LOCK+1 );
+ assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE );
+ assert( pWal->writeLock );
+ iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
+ nLock = SQLITE_SHM_NLOCK - iLock;
+ rc = walLockExclusive(pWal, iLock, nLock);
+ if( rc ){
+ return rc;
+ }
+ WALTRACE(("WAL%p: recovery begin...\n", pWal));
+
+ memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
+
+ rc = sqlite3OsFileSize(pWal->pWalFd, &nSize);
+ if( rc!=SQLITE_OK ){
+ goto recovery_error;
+ }
+
+ if( nSize>WAL_HDRSIZE ){
+ u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */
+ u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */
+ int szFrame; /* Number of bytes in buffer aFrame[] */
+ u8 *aData; /* Pointer to data part of aFrame buffer */
+ int iFrame; /* Index of last frame read */
+ i64 iOffset; /* Next offset to read from log file */
+ int szPage; /* Page size according to the log */
+ u32 magic; /* Magic value read from WAL header */
+ u32 version; /* Magic value read from WAL header */
+
+ /* Read in the WAL header. */
+ rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
+ if( rc!=SQLITE_OK ){
+ goto recovery_error;
+ }
+
+ /* If the database page size is not a power of two, or is greater than
+ ** SQLITE_MAX_PAGE_SIZE, conclude that the WAL file contains no valid
+ ** data. Similarly, if the 'magic' value is invalid, ignore the whole
+ ** WAL file.
+ */
+ magic = sqlite3Get4byte(&aBuf[0]);
+ szPage = sqlite3Get4byte(&aBuf[8]);
+ if( (magic&0xFFFFFFFE)!=WAL_MAGIC
+ || szPage&(szPage-1)
+ || szPage>SQLITE_MAX_PAGE_SIZE
+ || szPage<512
+ ){
+ goto finished;
+ }
+ pWal->hdr.bigEndCksum = (u8)(magic&0x00000001);
+ pWal->szPage = szPage;
+ pWal->nCkpt = sqlite3Get4byte(&aBuf[12]);
+ memcpy(&pWal->hdr.aSalt, &aBuf[16], 8);
+
+ /* Verify that the WAL header checksum is correct */
+ walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN,
+ aBuf, WAL_HDRSIZE-2*4, 0, pWal->hdr.aFrameCksum
+ );
+ if( pWal->hdr.aFrameCksum[0]!=sqlite3Get4byte(&aBuf[24])
+ || pWal->hdr.aFrameCksum[1]!=sqlite3Get4byte(&aBuf[28])
+ ){
+ goto finished;
+ }
+
+ /* Verify that the version number on the WAL format is one that
+ ** are able to understand */
+ version = sqlite3Get4byte(&aBuf[4]);
+ if( version!=WAL_MAX_VERSION ){
+ rc = SQLITE_CANTOPEN_BKPT;
+ goto finished;
+ }
+
+ /* Malloc a buffer to read frames into. */
+ szFrame = szPage + WAL_FRAME_HDRSIZE;
+ aFrame = (u8 *)sqlite3_malloc(szFrame);
+ if( !aFrame ){
+ rc = SQLITE_NOMEM;
+ goto recovery_error;
+ }
+ aData = &aFrame[WAL_FRAME_HDRSIZE];
+
+ /* Read all frames from the log file. */
+ iFrame = 0;
+ for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){
+ u32 pgno; /* Database page number for frame */
+ u32 nTruncate; /* dbsize field from frame header */
+ int isValid; /* True if this frame is valid */
+
+ /* Read and decode the next log frame. */
+ rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
+ if( rc!=SQLITE_OK ) break;
+ isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
+ if( !isValid ) break;
+ rc = walIndexAppend(pWal, ++iFrame, pgno);
+ if( rc!=SQLITE_OK ) break;
+
+ /* If nTruncate is non-zero, this is a commit record. */
+ if( nTruncate ){
+ pWal->hdr.mxFrame = iFrame;
+ pWal->hdr.nPage = nTruncate;
+ pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
+ testcase( szPage<=32768 );
+ testcase( szPage>=65536 );
+ aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
+ aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
+ }
+ }
+
+ sqlite3_free(aFrame);
+ }
+
+finished:
+ if( rc==SQLITE_OK ){
+ volatile WalCkptInfo *pInfo;
+ int i;
+ pWal->hdr.aFrameCksum[0] = aFrameCksum[0];
+ pWal->hdr.aFrameCksum[1] = aFrameCksum[1];
+ walIndexWriteHdr(pWal);
+
+ /* Reset the checkpoint-header. This is safe because this thread is
+ ** currently holding locks that exclude all other readers, writers and
+ ** checkpointers.
+ */
+ pInfo = walCkptInfo(pWal);
+ pInfo->nBackfill = 0;
+ pInfo->aReadMark[0] = 0;
+ for(i=1; iaReadMark[i] = READMARK_NOT_USED;
+
+ /* If more than one frame was recovered from the log file, report an
+ ** event via sqlite3_log(). This is to help with identifying performance
+ ** problems caused by applications routinely shutting down without
+ ** checkpointing the log file.
+ */
+ if( pWal->hdr.nPage ){
+ sqlite3_log(SQLITE_OK, "Recovered %d frames from WAL file %s",
+ pWal->hdr.nPage, pWal->zWalName
+ );
+ }
+ }
+
+recovery_error:
+ WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
+ walUnlockExclusive(pWal, iLock, nLock);
+ return rc;
+}
+
+/*
+** Close an open wal-index.
+*/
+static void walIndexClose(Wal *pWal, int isDelete){
+ if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
+ int i;
+ for(i=0; inWiData; i++){
+ sqlite3_free((void *)pWal->apWiData[i]);
+ pWal->apWiData[i] = 0;
+ }
+ }else{
+ sqlite3OsShmUnmap(pWal->pDbFd, isDelete);
+ }
+}
+
+/*
+** 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.
+*/
+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() */
+
+ assert( zWalName && zWalName[0] );
+ assert( pDbFd );
+
+ /* 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->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{
+ *ppWal = pRet;
+ WALTRACE(("WAL%d: opened\n", pRet));
+ }
+ return rc;
+}
+
+/*
+** 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;
+}
+
+/*
+** 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 */
+
+ iMin = p->iPrior;
+ assert( iMin<0xffffffff );
+ for(i=p->nSegment-1; i>=0; i--){
+ struct WalSegment *pSegment = &p->aSegment[i];
+ while( pSegment->iNextnEntry ){
+ u32 iPg = pSegment->aPgno[pSegment->aIndex[pSegment->iNext]];
+ if( iPg>iMin ){
+ if( iPgiZero + pSegment->aIndex[pSegment->iNext];
+ }
+ break;
+ }
+ 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 J0 && nRight>0 );
+ while( iRight=nRight || aContent[aLeft[iLeft]]=nLeft || aContent[aLeft[iLeft]]>dbpage );
+ assert( iRight>=nRight || aContent[aRight[iRight]]>dbpage );
+ }
+
+ *paRight = aLeft;
+ *pnRight = iOut;
+ memcpy(aLeft, aTmp, sizeof(aTmp[0])*iOut);
+}
+
+/*
+** Sort the elements in list aList using aContent[] as the sort key.
+** Remove elements with duplicate keys, preferring to keep the
+** larger aList[] values.
+**
+** The aList[] entries are indices into aContent[]. The values in
+** aList[] are to be sorted so that for all J0 );
+ assert( HASHTABLE_NPAGE==(1<<(ArraySize(aSub)-1)) );
+
+ for(iList=0; iListaList && p->nList<=(1<aList==&aList[iList&~((2<aList, p->nList, &aMerge, &nMerge, aBuffer);
+ }
+ aSub[iSub].aList = aMerge;
+ aSub[iSub].nList = nMerge;
+ }
+
+ for(iSub++; iSubnList<=(1<aList==&aList[nList&~((2<aList, p->nList, &aMerge, &nMerge, aBuffer);
+ }
+ }
+ assert( aMerge==aList );
+ *pnList = nMerge;
+
+#ifdef SQLITE_DEBUG
+ {
+ int i;
+ for(i=1; i<*pnList; i++){
+ assert( aContent[aList[i]] > aContent[aList[i-1]] );
+ }
+ }
+#endif
+}
+
+/*
+** Free an iterator allocated by walIteratorInit().
+*/
+static void walIteratorFree(WalIterator *p){
+ sqlite3ScratchFree(p);
+}
+
+/*
+** 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.
+**
+** 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.
+**
+** The calling routine should invoke walIteratorFree() to destroy the
+** WalIterator object when it has finished with it.
+*/
+static int walIteratorInit(Wal *pWal, WalIterator **pp){
+ WalIterator *p; /* Return value */
+ int nSegment; /* Number of segments to merge */
+ u32 iLast; /* Last frame in log */
+ int nByte; /* Number of bytes to allocate */
+ int i; /* Iterator variable */
+ ht_slot *aTmp; /* Temp space used by merge-sort */
+ int rc = SQLITE_OK; /* Return Code */
+
+ /* This routine only runs while holding the checkpoint lock. And
+ ** it only runs if there is actually content in the log (mxFrame>0).
+ */
+ assert( pWal->ckptLock && pWal->hdr.mxFrame>0 );
+ iLast = pWal->hdr.mxFrame;
+
+ /* Allocate space for the WalIterator object. */
+ nSegment = walFramePage(iLast) + 1;
+ nByte = sizeof(WalIterator)
+ + (nSegment-1)*sizeof(struct WalSegment)
+ + iLast*sizeof(ht_slot);
+ p = (WalIterator *)sqlite3ScratchMalloc(nByte);
+ if( !p ){
+ return SQLITE_NOMEM;
+ }
+ memset(p, 0, nByte);
+ p->nSegment = nSegment;
+
+ /* Allocate temporary space used by the merge-sort routine. This block
+ ** of memory will be freed before this function returns.
+ */
+ aTmp = (ht_slot *)sqlite3ScratchMalloc(
+ sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
+ );
+ if( !aTmp ){
+ rc = SQLITE_NOMEM;
+ }
+
+ for(i=0; rc==SQLITE_OK && iaSegment[p->nSegment])[iZero];
+ iZero++;
+
+ for(j=0; jaSegment[i].iZero = iZero;
+ p->aSegment[i].nEntry = nEntry;
+ p->aSegment[i].aIndex = aIndex;
+ p->aSegment[i].aPgno = (u32 *)aPgno;
+ }
+ }
+ sqlite3ScratchFree(aTmp);
+
+ if( rc!=SQLITE_OK ){
+ walIteratorFree(p);
+ }
+ *pp = p;
+ return rc;
+}
+
+/*
+** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
+** n. If the attempt fails and parameter xBusy is not NULL, then it is a
+** busy-handler function. Invoke it and retry the lock until either the
+** lock is successfully obtained or the busy-handler returns 0.
+*/
+static int walBusyLock(
+ Wal *pWal, /* WAL connection */
+ int (*xBusy)(void*), /* Function to call when busy */
+ void *pBusyArg, /* Context argument for xBusyHandler */
+ int lockIdx, /* Offset of first byte to lock */
+ int n /* Number of bytes to lock */
+){
+ int rc;
+ do {
+ rc = walLockExclusive(pWal, lockIdx, n);
+ }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
+ return rc;
+}
+
+/*
+** The cache of the wal-index header must be valid to call this function.
+** Return the page-size in bytes used by the database.
+*/
+static int walPagesize(Wal *pWal){
+ return (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
+}
+
+/*
+** Copy as much content as we can from the WAL back into the database file
+** in response to an sqlite3_wal_checkpoint() request or the equivalent.
+**
+** The amount of information copies from WAL to database might be limited
+** by active readers. This routine will never overwrite a database page
+** that a concurrent reader might be using.
+**
+** All I/O barrier operations (a.k.a fsyncs) occur in this routine when
+** SQLite is in WAL-mode in synchronous=NORMAL. That means that if
+** checkpoints are always run by a background thread or background
+** process, foreground threads will never block on a lengthy fsync call.
+**
+** Fsync is called on the WAL before writing content out of the WAL and
+** into the database. This ensures that if the new content is persistent
+** in the WAL and can be recovered following a power-loss or hard reset.
+**
+** Fsync is also called on the database file if (and only if) the entire
+** WAL content is copied into the database file. This second fsync makes
+** it safe to delete the WAL since the new content will persist in the
+** database file.
+**
+** This routine uses and updates the nBackfill field of the wal-index header.
+** This is the only routine tha will increase the value of nBackfill.
+** (A WAL reset or recovery will revert nBackfill to zero, but not increase
+** its value.)
+**
+** The caller must be holding sufficient locks to ensure that no other
+** checkpoint is running (in any other thread or process) at the same
+** time.
+*/
+static int walCheckpoint(
+ Wal *pWal, /* Wal connection */
+ int eMode, /* One of PASSIVE, FULL or RESTART */
+ int (*xBusyCall)(void*), /* Function to call when busy */
+ void *pBusyArg, /* Context argument for xBusyHandler */
+ int sync_flags, /* Flags for OsSync() (or 0) */
+ u8 *zBuf /* Temporary buffer to use */
+){
+ int rc; /* Return code */
+ int szPage; /* Database page-size */
+ WalIterator *pIter = 0; /* Wal iterator context */
+ u32 iDbpage = 0; /* Next database page to write */
+ u32 iFrame = 0; /* Wal frame containing data for iDbpage */
+ u32 mxSafeFrame; /* Max frame that can be backfilled */
+ u32 mxPage; /* Max database page to write */
+ int i; /* Loop counter */
+ volatile WalCkptInfo *pInfo; /* The checkpoint status information */
+ int (*xBusy)(void*) = 0; /* Function to call when waiting for locks */
+
+ szPage = walPagesize(pWal);
+ testcase( szPage<=32768 );
+ testcase( szPage>=65536 );
+ pInfo = walCkptInfo(pWal);
+ if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
+
+ /* Allocate the iterator */
+ rc = walIteratorInit(pWal, &pIter);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ assert( pIter );
+
+ if( eMode!=SQLITE_CHECKPOINT_PASSIVE ) xBusy = xBusyCall;
+
+ /* Compute in mxSafeFrame the index of the last frame of the WAL that is
+ ** safe to write into the database. Frames beyond mxSafeFrame might
+ ** overwrite database pages that are in use by active readers and thus
+ ** cannot be backfilled from the WAL.
+ */
+ mxSafeFrame = pWal->hdr.mxFrame;
+ mxPage = pWal->hdr.nPage;
+ for(i=1; iaReadMark[i];
+ if( mxSafeFrame>y ){
+ assert( y<=pWal->hdr.mxFrame );
+ rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
+ if( rc==SQLITE_OK ){
+ pInfo->aReadMark[i] = READMARK_NOT_USED;
+ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ }else if( rc==SQLITE_BUSY ){
+ mxSafeFrame = y;
+ xBusy = 0;
+ }else{
+ goto walcheckpoint_out;
+ }
+ }
+ }
+
+ if( pInfo->nBackfillnBackfill;
+
+ /* 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( rc==SQLITE_OK ){
+ i64 nReq = ((i64)mxPage * szPage);
+ rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
+ if( rc==SQLITE_OK && nSizepDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
+ }
+ }
+
+ /* Iterate through the contents of the WAL, copying data to the db file. */
+ while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
+ i64 iOffset;
+ assert( walFramePgno(pWal, iFrame)==iDbpage );
+ if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue;
+ iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
+ /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
+ rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
+ if( rc!=SQLITE_OK ) break;
+ iOffset = (iDbpage-1)*(i64)szPage;
+ testcase( IS_BIG_INT(iOffset) );
+ rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
+ if( rc!=SQLITE_OK ) break;
+ }
+
+ /* If work was actually accomplished... */
+ if( rc==SQLITE_OK ){
+ if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
+ i64 szDb = pWal->hdr.nPage*(i64)szPage;
+ testcase( IS_BIG_INT(szDb) );
+ rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
+ if( rc==SQLITE_OK && sync_flags ){
+ rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
+ }
+ }
+ if( rc==SQLITE_OK ){
+ pInfo->nBackfill = mxSafeFrame;
+ }
+ }
+
+ /* Release the reader lock held while backfilling */
+ walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
+ }
+
+ if( rc==SQLITE_BUSY ){
+ /* Reset the return code so as not to report a checkpoint failure
+ ** just because there are active readers. */
+ rc = SQLITE_OK;
+ }
+
+ /* If 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( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
+ assert( pWal->writeLock );
+ if( pInfo->nBackfillhdr.mxFrame ){
+ rc = SQLITE_BUSY;
+ }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);
+ }
+ }
+ }
+
+ walcheckpoint_out:
+ walIteratorFree(pIter);
+ return rc;
+}
+
+/*
+** Close a connection to a log file.
+*/
+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( pWal ){
+ int isDelete = 0; /* True to unlink wal and wal-index files */
+
+ /* 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
+ ** the database. In this case checkpoint the database and unlink both
+ ** the wal and wal-index files.
+ **
+ ** The EXCLUSIVE lock is not released before returning.
+ */
+ rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
+ if( rc==SQLITE_OK ){
+ int bPersistWal = -1;
+ if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
+ pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
+ }
+ rc = sqlite3WalCheckpoint(
+ pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
+ );
+ sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersistWal);
+ if( rc==SQLITE_OK && bPersistWal!=1 ){
+ isDelete = 1;
+ }
+ }
+
+ walIndexClose(pWal, isDelete);
+ sqlite3OsClose(pWal->pWalFd);
+ if( isDelete ){
+ sqlite3OsDelete(pWal->pVfs, pWal->zWalName, 0);
+ }
+ WALTRACE(("WAL%p: closed\n", pWal));
+ sqlite3_free((void *)pWal->apWiData);
+ sqlite3_free(pWal);
+ }
+ return rc;
+}
+
+/*
+** Try to read the wal-index header. Return 0 on success and 1 if
+** there is a problem.
+**
+** The wal-index is in shared memory. Another thread or process might
+** be writing the header at the same time this procedure is trying to
+** 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.
+**
+** 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.
+**
+** If the checksum cannot be verified return non-zero. If the header
+** is read successfully and the checksum verified, return zero.
+*/
+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 */
+
+ /* The first page of the wal-index must be mapped at this point. */
+ assert( pWal->nWiData>0 && pWal->apWiData[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
+ ** from the file. If this happens, return non-zero.
+ **
+ ** There are two copies of the header at the beginning of the wal-index.
+ ** 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.
+ */
+ aHdr = walIndexHdr(pWal);
+ memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
+ walShmBarrier(pWal);
+ memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
+
+ if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
+ return 1; /* Dirty read */
+ }
+ if( h1.isInit==0 ){
+ return 1; /* Malformed header - probably all zeros */
+ }
+ 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( memcmp(&pWal->hdr, &h1, sizeof(WalIndexHdr)) ){
+ *pChanged = 1;
+ memcpy(&pWal->hdr, &h1, sizeof(WalIndexHdr));
+ pWal->szPage = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
+ testcase( pWal->szPage<=32768 );
+ testcase( pWal->szPage>=65536 );
+ }
+
+ /* The header was successfully read. Return zero. */
+ return 0;
+}
+
+/*
+** Read the wal-index header from the wal-index and into pWal->hdr.
+** If the wal-header appears to be corrupt, try to reconstruct the
+** wal-index from the WAL before returning.
+**
+** Set *pChanged to 1 if the wal-index header value in pWal->hdr is
+** changed by this opertion. If pWal->hdr is unchanged, set *pChanged
+** to 0.
+**
+** If the wal-index header is successfully read, return SQLITE_OK.
+** Otherwise an SQLite error code.
+*/
+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 */
+
+ /* 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.
+ */
+ assert( pChanged );
+ rc = walIndexPage(pWal, 0, &page0);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ };
+ assert( page0 || pWal->writeLock==0 );
+
+ /* 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);
+
+ /* If the first attempt failed, it might have been due to a race
+ ** with a writer. So get a WRITE lock and try again.
+ */
+ assert( badHdr==0 || pWal->writeLock==0 );
+ if( badHdr ){
+ if( pWal->readOnly & WAL_SHM_RDONLY ){
+ if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
+ walUnlockShared(pWal, WAL_WRITE_LOCK);
+ rc = SQLITE_READONLY_RECOVERY;
+ }
+ }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
+ pWal->writeLock = 1;
+ if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
+ badHdr = walIndexTryHdr(pWal, pChanged);
+ if( badHdr ){
+ /* If the wal-index header is still malformed even while holding
+ ** a WRITE lock, it can only mean that the header is corrupted and
+ ** needs to be reconstructed. So run recovery to do exactly that.
+ */
+ rc = walIndexRecover(pWal);
+ *pChanged = 1;
+ }
+ }
+ pWal->writeLock = 0;
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ }
+ }
+
+ /* 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.
+ */
+ if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){
+ rc = SQLITE_CANTOPEN_BKPT;
+ }
+
+ return rc;
+}
+
+/*
+** This is the value that walTryBeginRead returns when it needs to
+** be retried.
+*/
+#define WAL_RETRY (-1)
+
+/*
+** 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.
+**
+** On success return SQLITE_OK. On a permanent failure (such an
+** I/O error or an SQLITE_BUSY because another process is running
+** recovery) return a positive error code.
+**
+** The 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()
+** to make a copy of the wal-index header into pWal->hdr. If the
+** wal-index header has changed, *pChanged is set to 1 (as an indication
+** to the caller that the local paget cache is obsolete and needs to be
+** flushed.) When useWal==1, the wal-index header is assumed to already
+** be loaded and the pChanged parameter is unused.
+**
+** The caller must set the cnt parameter to the number of prior calls to
+** this routine during the current read attempt that returned WAL_RETRY.
+** This routine will start taking more aggressive measures to clear the
+** race conditions after multiple WAL_RETRY returns, and after an excessive
+** number of errors will ultimately return SQLITE_PROTOCOL. The
+** SQLITE_PROTOCOL return indicates that some other process has gone rogue
+** and is not honoring the locking protocol. There is a vanishingly small
+** chance that SQLITE_PROTOCOL could be returned because of a run of really
+** bad luck when there is lots of contention for the wal-index, but that
+** possibility is so small that it can be safely neglected, we believe.
+**
+** On success, this routine obtains a read lock on
+** WAL_READ_LOCK(pWal->readLock). The pWal->readLock integer is
+** in the range 0 <= pWal->readLock < WAL_NREADER. If pWal->readLock==(-1)
+** that means the Wal does not hold any read lock. The reader must not
+** access any database page that is modified by a WAL frame up to and
+** including frame number aReadMark[pWal->readLock]. The reader will
+** use WAL frames up to and including pWal->hdr.mxFrame if pWal->readLock>0
+** Or if pWal->readLock==0, then the reader will ignore the WAL
+** completely and get all content directly from the database file.
+** If the useWal parameter is 1 then the WAL will never be ignored and
+** this routine will always set pWal->readLock>0 on success.
+** When the read transaction is completed, the caller must release the
+** lock on WAL_READ_LOCK(pWal->readLock) and set pWal->readLock to -1.
+**
+** This routine uses the nBackfill and aReadMark[] fields of the header
+** to select a particular WAL_READ_LOCK() that strives to let the
+** checkpoint process do as much work as possible. This routine might
+** update values of the aReadMark[] array in the header, but if it does
+** so it takes care to hold an exclusive lock on the corresponding
+** WAL_READ_LOCK() while changing values.
+*/
+static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
+ volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */
+ u32 mxReadMark; /* Largest aReadMark[] value */
+ int mxI; /* Index of largest aReadMark[] value */
+ int i; /* Loop counter */
+ int rc = SQLITE_OK; /* Return code */
+
+ assert( pWal->readLock<0 ); /* Not currently locked */
+
+ /* Take steps to avoid spinning forever if there is a protocol error.
+ **
+ ** 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
+ ** if we are unlucky, another process that is holding a lock might get
+ ** paged out or take a page-fault that is time-consuming to resolve,
+ ** during the few nanoseconds that it is holding the lock. In that case,
+ ** it might take longer than normal for the lock to free.
+ **
+ ** After 5 RETRYs, we begin calling sqlite3OsSleep(). The first few
+ ** calls to sqlite3OsSleep() have a delay of 1 microsecond. Really this
+ ** is more of a scheduler yield than an actual delay. But on the 10th
+ ** an subsequent retries, the delays start becoming longer and longer,
+ ** 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( cnt>5 ){
+ int nDelay = 1; /* Pause time in microseconds */
+ if( cnt>100 ){
+ VVA_ONLY( pWal->lockError = 1; )
+ return SQLITE_PROTOCOL;
+ }
+ if( cnt>=10 ) nDelay = (cnt-9)*238; /* Max delay 21ms. Total delay 996ms */
+ sqlite3OsSleep(pWal->pVfs, nDelay);
+ }
+
+ if( !useWal ){
+ rc = walIndexReadHdr(pWal, pChanged);
+ if( rc==SQLITE_BUSY ){
+ /* If there is not a recovery running in another thread or process
+ ** then convert BUSY errors to WAL_RETRY. If recovery is known to
+ ** be running, convert BUSY to BUSY_RECOVERY. There is a race here
+ ** which might cause WAL_RETRY to be returned even if BUSY_RECOVERY
+ ** would be technically correct. But the race is benign since with
+ ** WAL_RETRY this routine will be called again and will probably be
+ ** right on the second iteration.
+ */
+ if( pWal->apWiData[0]==0 ){
+ /* This branch is taken when the xShmMap() method returns SQLITE_BUSY.
+ ** We assume this is a transient condition, so return WAL_RETRY. The
+ ** xShmMap() implementation used by the default unix and win32 VFS
+ ** modules may return SQLITE_BUSY due to a race condition in the
+ ** code that determines whether or not the shared-memory region
+ ** must be zeroed before the requested page is returned.
+ */
+ rc = WAL_RETRY;
+ }else if( SQLITE_OK==(rc = walLockShared(pWal, WAL_RECOVER_LOCK)) ){
+ walUnlockShared(pWal, WAL_RECOVER_LOCK);
+ rc = WAL_RETRY;
+ }else if( rc==SQLITE_BUSY ){
+ rc = SQLITE_BUSY_RECOVERY;
+ }
+ }
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ }
+
+ 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.
+ */
+ rc = walLockShared(pWal, WAL_READ_LOCK(0));
+ walShmBarrier(pWal);
+ if( rc==SQLITE_OK ){
+ if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){
+ /* It is not safe to allow the reader to continue here if frames
+ ** may have been appended to the log before READ_LOCK(0) was obtained.
+ ** When holding READ_LOCK(0), the reader ignores the entire log file,
+ ** which implies that the database file contains a trustworthy
+ ** snapshoT. Since holding READ_LOCK(0) prevents a checkpoint from
+ ** happening, this is usually correct.
+ **
+ ** However, if frames have been appended to the log (or if the log
+ ** is wrapped and written for that matter) before the READ_LOCK(0)
+ ** is obtained, that is not necessarily true. A checkpointer may
+ ** have started to backfill the appended frames but crashed before
+ ** it finished. Leaving a corrupt image in the database file.
+ */
+ walUnlockShared(pWal, WAL_READ_LOCK(0));
+ return WAL_RETRY;
+ }
+ pWal->readLock = 0;
+ return SQLITE_OK;
+ }else if( rc!=SQLITE_BUSY ){
+ return rc;
+ }
+ }
+
+ /* 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.
+ */
+ mxReadMark = 0;
+ mxI = 0;
+ for(i=1; iaReadMark[i];
+ if( mxReadMark<=thisMark && thisMark<=pWal->hdr.mxFrame ){
+ assert( thisMark!=READMARK_NOT_USED );
+ mxReadMark = thisMark;
+ mxI = i;
+ }
+ }
+ /* There was once an "if" here. The extra "{" is to preserve indentation. */
+ {
+ if( (pWal->readOnly & WAL_SHM_RDONLY)==0
+ && (mxReadMarkhdr.mxFrame || mxI==0)
+ ){
+ for(i=1; iaReadMark[i] = pWal->hdr.mxFrame;
+ mxI = i;
+ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ break;
+ }else if( rc!=SQLITE_BUSY ){
+ return rc;
+ }
+ }
+ }
+ if( mxI==0 ){
+ assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 );
+ return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTLOCK;
+ }
+
+ rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
+ if( rc ){
+ return rc==SQLITE_BUSY ? WAL_RETRY : rc;
+ }
+ /* Now that the read-lock has been obtained, check that neither the
+ ** value in the aReadMark[] array or the contents of the wal-index
+ ** header have changed.
+ **
+ ** It is necessary to check that the wal-index header did not change
+ ** between the time it was read and when the shared-lock was obtained
+ ** on WAL_READ_LOCK(mxI) was obtained to account for the possibility
+ ** that the log file may have been wrapped by a writer, or that frames
+ ** that occur later in the log than pWal->hdr.mxFrame may have been
+ ** copied into the database by a checkpointer. If either of these things
+ ** happened, then reading the database with the current value of
+ ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry
+ ** instead.
+ **
+ ** This does not guarantee that the copy of the wal-index header is up to
+ ** date before proceeding. That would not be possible without somehow
+ ** blocking writers. It only guarantees that a dangerous checkpoint or
+ ** log-wrap (either of which would require an exclusive lock on
+ ** WAL_READ_LOCK(mxI)) has not occurred since the snapshot was valid.
+ */
+ walShmBarrier(pWal);
+ if( pInfo->aReadMark[mxI]!=mxReadMark
+ || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
+ ){
+ walUnlockShared(pWal, WAL_READ_LOCK(mxI));
+ return WAL_RETRY;
+ }else{
+ assert( mxReadMark<=pWal->hdr.mxFrame );
+ pWal->readLock = (i16)mxI;
+ }
+ }
+ return rc;
+}
+
+/*
+** Begin a read transaction on the database.
+**
+** This routine used to be called sqlite3OpenSnapshot() and with good reason:
+** it takes a snapshot of the state of the WAL and wal-index for the current
+** instant in time. The current thread will continue to use this snapshot.
+** Other threads might append new content to the WAL and wal-index but
+** that extra content is ignored by the current thread.
+**
+** If the database contents have changes since the previous read
+** transaction, then *pChanged is set to 1 before returning. The
+** Pager layer will use this to know that is cache is stale and
+** needs to be flushed.
+*/
+SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
+ int rc; /* Return code */
+ int cnt = 0; /* Number of TryBeginRead attempts */
+
+ do{
+ rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
+ }while( rc==WAL_RETRY );
+ testcase( (rc&0xff)==SQLITE_BUSY );
+ testcase( (rc&0xff)==SQLITE_IOERR );
+ testcase( rc==SQLITE_PROTOCOL );
+ testcase( rc==SQLITE_OK );
+ return rc;
+}
+
+/*
+** Finish with a read transaction. All this does is release the
+** read-lock.
+*/
+SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){
+ sqlite3WalEndWriteTransaction(pWal);
+ if( pWal->readLock>=0 ){
+ walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
+ pWal->readLock = -1;
+ }
+}
+
+/*
+** 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.
+**
+** 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.
+*/
+SQLITE_PRIVATE int sqlite3WalRead(
+ 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 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 */
+
+ /* This routine is only be called from within a read transaction. */
+ assert( pWal->readLock>=0 || pWal->lockError );
+
+ /* If the "last page" field of the wal-index header snapshot is 0, then
+ ** no data will be read from the wal under any circumstances. Return early
+ ** in this case as an optimization. Likewise, if pWal->readLock==0,
+ ** then the WAL is ignored by the reader so return early, as if the
+ ** WAL were empty.
+ */
+ if( iLast==0 || pWal->readLock==0 ){
+ *pInWal = 0;
+ return SQLITE_OK;
+ }
+
+ /* 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).
+ **
+ ** 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
+ ** slot (aHash[iKey]) may have been added before or after the
+ ** current read transaction was opened. Values added after the
+ ** read transaction was opened may have been written incorrectly -
+ ** i.e. these slots may contain garbage data. However, we assume
+ ** that any slots written before the current read transaction was
+ ** opened remain unmodified.
+ **
+ ** For the reasons above, the if(...) condition featured in the inner
+ ** loop of the following block is more stringent that would be required
+ ** if we had exclusive access to the hash-table:
+ **
+ ** (aPgno[iFrame]==pgno):
+ ** This condition filters out normal hash-table collisions.
+ **
+ ** (iFrame<=iLast):
+ ** This condition filters out entries that were added to the hash
+ ** table after the current read-transaction had started.
+ */
+ 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 */
+ u32 iZero; /* Frame number corresponding to aPgno[0] */
+ int iKey; /* Hash slot index */
+ int nCollide; /* Number of hash collisions remaining */
+ int rc; /* Error code */
+
+ rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ nCollide = HASHTABLE_NSLOT;
+ for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
+ u32 iFrame = aHash[iKey] + iZero;
+ if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
+ assert( iFrame>iRead );
+ iRead = iFrame;
+ }
+ if( (nCollide--)==0 ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+ }
+ }
+
+#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 );
+ }
+#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 = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&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, iOffset);
+ }
+
+ *pInWal = 0;
+ return SQLITE_OK;
+}
+
+
+/*
+** Return the size of the database in pages (or zero, if unknown).
+*/
+SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal){
+ if( pWal && ALWAYS(pWal->readLock>=0) ){
+ return pWal->hdr.nPage;
+ }
+ return 0;
+}
+
+
+/*
+** This function starts a write transaction on the WAL.
+**
+** 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.
+**
+** There can only be a single writer active at a time.
+*/
+SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
+ int rc;
+
+ /* Cannot start a write transaction without first holding a read
+ ** transaction. */
+ assert( pWal->readLock>=0 );
+
+ if( pWal->readOnly ){
+ return SQLITE_READONLY;
+ }
+
+ /* Only one writer allowed at a time. Get the write lock. Return
+ ** SQLITE_BUSY if unable.
+ */
+ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ if( rc ){
+ return rc;
+ }
+ pWal->writeLock = 1;
+
+ /* If another connection has written to the database file since the
+ ** time the read transaction on this connection was started, then
+ ** the write is disallowed.
+ */
+ if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ pWal->writeLock = 0;
+ rc = SQLITE_BUSY;
+ }
+
+ return rc;
+}
+
+/*
+** End a write transaction. The commit has already been done. This
+** routine merely releases the lock.
+*/
+SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){
+ if( pWal->writeLock ){
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ pWal->writeLock = 0;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** 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.
+ */
+ 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));
+ }
+ 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;
+
+ assert( pWal->writeLock );
+ assert( aWalData[3]!=pWal->nCkpt || aWalData[0]<=pWal->hdr.mxFrame );
+
+ 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( aWalData[0]hdr.mxFrame ){
+ pWal->hdr.mxFrame = aWalData[0];
+ pWal->hdr.aFrameCksum[0] = aWalData[1];
+ pWal->hdr.aFrameCksum[1] = aWalData[2];
+ walCleanupHash(pWal);
+ }
+
+ 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( 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 */
+
+ /* Limit the size of WAL file if the journal_size_limit PRAGMA is
+ ** set to a non-negative value. Log errors encountered
+ ** during the truncation attempt. */
+ if( pWal->mxWalSize>=0 ){
+ i64 sz;
+ int rx;
+ sqlite3BeginBenignMalloc();
+ rx = sqlite3OsFileSize(pWal->pWalFd, &sz);
+ if( rx==SQLITE_OK && (sz > pWal->mxWalSize) ){
+ rx = sqlite3OsTruncate(pWal->pWalFd, pWal->mxWalSize);
+ }
+ sqlite3EndBenignMalloc();
+ if( rx ){
+ sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName);
+ }
+ }
+
+ pWal->nCkpt++;
+ pWal->hdr.mxFrame = 0;
+ sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
+ aSalt[1] = salt1;
+ walIndexWriteHdr(pWal);
+ pInfo->nBackfill = 0;
+ for(i=1; iaReadMark[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 );
+ }
+ return rc;
+}
+
+/*
+** Write a set of frames to the log. The caller must hold the write-lock
+** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
+*/
+SQLITE_PRIVATE int sqlite3WalFrames(
+ Wal *pWal, /* Wal handle to write to */
+ int szPage, /* Database page-size in bytes */
+ PgHdr *pList, /* List of dirty pages to write */
+ Pgno nTruncate, /* Database size after this commit */
+ int isCommit, /* True if this is a commit */
+ int sync_flags /* Flags to pass to OsSync() (or 0) */
+){
+ int rc; /* Used to catch return codes */
+ u32 iFrame; /* Next frame address */
+ u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */
+ PgHdr *p; /* Iterator to run through pList with. */
+ PgHdr *pLast = 0; /* Last frame in list */
+ int nLast = 0; /* Number of extra copies of last page */
+
+ assert( pList );
+ assert( pWal->writeLock );
+
+#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"));
+ }
+#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;
+ }
+
+ /* 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);
+ 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];
+
+ 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;
+ }
+ }
+ assert( (int)pWal->szPage==szPage );
+
+ /* Write the log file. */
+ for(p=pList; p; p=p->pDirty){
+ u32 nDbsize; /* Db-size field for frame header */
+ i64 iOffset; /* Write offset in log file */
+ void *pData;
+
+ iOffset = walFrameOffset(++iFrame, szPage);
+ /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
+
+ /* Populate and write the frame header */
+ nDbsize = (isCommit && p->pDirty==0) ? nTruncate : 0;
+#if defined(SQLITE_HAS_CODEC)
+ if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM;
+#else
+ pData = p->pData;
+#endif
+ walEncodeFrame(pWal, p->pgno, nDbsize, pData, aFrame);
+ rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+
+ /* Write the page data */
+ rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOffset+sizeof(aFrame));
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ pLast = p;
+ }
+
+ /* Sync the log file if the 'isSync' flag was specified. */
+ if( sync_flags ){
+ i64 iSegment = sqlite3OsSectorSize(pWal->pWalFd);
+ i64 iOffset = walFrameOffset(iFrame+1, szPage);
+
+ assert( isCommit );
+ assert( iSegment>0 );
+
+ iSegment = (((iOffset+iSegment-1)/iSegment) * iSegment);
+ while( iOffsetpData;
+#endif
+ walEncodeFrame(pWal, pLast->pgno, nTruncate, pData, aFrame);
+ /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
+ rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ iOffset += WAL_FRAME_HDRSIZE;
+ rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOffset);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ nLast++;
+ iOffset += szPage;
+ }
+
+ rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
+ }
+
+ /* 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( nLast>0 && rc==SQLITE_OK ){
+ iFrame++;
+ nLast--;
+ rc = walIndexAppend(pWal, iFrame, pLast->pgno);
+ }
+
+ 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;
+ }
+ }
+
+ 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.
+**
+** Obtain a CHECKPOINT lock and then backfill as much information as
+** we can from WAL into the database.
+**
+** If parameter xBusy is not NULL, it is a pointer to a busy-handler
+** callback. In this case this function runs a blocking checkpoint.
+*/
+SQLITE_PRIVATE int sqlite3WalCheckpoint(
+ Wal *pWal, /* Wal connection */
+ int eMode, /* PASSIVE, FULL or RESTART */
+ int (*xBusy)(void*), /* Function to call when busy */
+ void *pBusyArg, /* Context argument for xBusyHandler */
+ int sync_flags, /* Flags to sync db file with (or 0) */
+ int nBuf, /* Size of temporary buffer */
+ u8 *zBuf, /* Temporary buffer to use */
+ int *pnLog, /* OUT: Number of frames in WAL */
+ int *pnCkpt /* OUT: Number of backfilled frames in WAL */
+){
+ int rc; /* Return code */
+ int isChanged = 0; /* True if a new wal-index header is loaded */
+ int eMode2 = eMode; /* Mode to pass to walCheckpoint() */
+
+ assert( pWal->ckptLock==0 );
+ assert( pWal->writeLock==0 );
+
+ 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;
+
+ /* 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;
+ }
+ }
+
+ /* Read the wal-index header. */
+ if( rc==SQLITE_OK ){
+ rc = walIndexReadHdr(pWal, &isChanged);
+ }
+
+ /* 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 no error occurred, set the output variables. */
+ if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
+ if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
+ if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
+ }
+ }
+
+ if( isChanged ){
+ /* If a new wal-index header was loaded before the checkpoint was
+ ** performed, then the pager-cache associated with pWal is now
+ ** out of date. So zero the cached wal-index header to ensure that
+ ** next time the pager opens a snapshot on this database it knows that
+ ** the cache needs to be reset.
+ */
+ memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
+ }
+
+ /* Release the locks. */
+ sqlite3WalEndWriteTransaction(pWal);
+ walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
+ 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
+** the last call, then return 0.
+*/
+SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){
+ u32 ret = 0;
+ if( pWal ){
+ ret = pWal->iCallback;
+ pWal->iCallback = 0;
+ }
+ return (int)ret;
+}
+
+/*
+** This function is called to change the WAL subsystem into or out
+** of locking_mode=EXCLUSIVE.
+**
+** If op is zero, then attempt to change from locking_mode=EXCLUSIVE
+** into locking_mode=NORMAL. This means that we must acquire a lock
+** on the pWal->readLock byte. If the WAL is already in locking_mode=NORMAL
+** or if the acquisition of the lock fails, then return 0. If the
+** transition out of exclusive-mode is successful, return 1. This
+** operation must occur while the pager is still holding the exclusive
+** lock on the main database file.
+**
+** If op is one, then change from locking_mode=NORMAL into
+** locking_mode=EXCLUSIVE. This means that the pWal->readLock must
+** be released. Return 1 if the transition is made and 0 if the
+** WAL is already in exclusive-locking mode - meaning that this
+** routine is a no-op. The pager must already hold the exclusive lock
+** on the main database file before invoking this operation.
+**
+** 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.
+*/
+SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
+ 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) );
+
+ 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;
+ }
+ return rc;
+}
+
+/*
+** Return true if the argument is non-NULL and the WAL module is using
+** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
+** WAL module is using shared-memory, return false.
+*/
+SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
+ return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
+}
+
+#endif /* #ifndef SQLITE_OMIT_WAL */
+
+/************** End of wal.c *************************************************/
/************** Begin file btmutex.c *****************************************/
/*
** 2007 August 27
@@ -37600,16 +47368,16 @@ SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){
** on Ptr(N) and its subpages have values greater than Key(N-1). And
** so forth.
**
-** Finding a particular key requires reading O(log(M)) pages from the
+** Finding a particular key requires reading O(log(M)) pages from the
** disk where M is the number of entries in the tree.
**
-** In this implementation, a single file can hold one or more separate
+** In this implementation, a single file can hold one or more separate
** BTrees. Each BTree is identified by the index of its root page. The
** key and data for any entry are combined to form the "payload". A
** fixed amount of payload can be carried directly on the database
** page. If the payload is larger than the preset amount then surplus
** bytes are stored on overflow pages. The payload for an entry
-** and the preceding pointer are combined to form a "Cell". Each
+** and the preceding pointer are combined to form a "Cell". Each
** page has a small header which contains the Ptr(N) pointer and other
** information such as the size of key and data.
**
@@ -37617,7 +47385,7 @@ SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){
**
** The file is divided into pages. The first page is called page 1,
** the second is page 2, and so forth. A page number of zero indicates
-** "no such page". The page size can be any power of 2 between 512 and 32768.
+** "no such page". The page size can be any power of 2 between 512 and 65536.
** Each page can be either a btree page, a freelist page, an overflow
** page, or a pointer-map page.
**
@@ -37627,7 +47395,7 @@ SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){
**
** OFFSET SIZE DESCRIPTION
** 0 16 Header string: "SQLite format 3\000"
-** 16 2 Page size in bytes.
+** 16 2 Page size in bytes.
** 18 1 File format write version
** 19 1 File format read version
** 20 1 Bytes of unused space at the end of each page
@@ -37738,7 +47506,7 @@ SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){
** contiguous or in order, but cell pointers are contiguous and in order.
**
** Cell content makes use of variable length integers. A variable
-** length integer is 1 to 9 bytes where the lower 7 bits of each
+** length integer is 1 to 9 bytes where the lower 7 bits of each
** byte are used. The integer consists of all bytes that have bit 8 set and
** the first byte with bit 8 clear. The most significant byte of the integer
** appears first. A variable-length integer may not be more than 9 bytes long.
@@ -37788,7 +47556,7 @@ SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){
/* The following value is the maximum cell size assuming a maximum page
** size give above.
*/
-#define MX_CELL_SIZE(pBt) (pBt->pageSize-8)
+#define MX_CELL_SIZE(pBt) ((int)(pBt->pageSize-8))
/* 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
@@ -37809,7 +47577,7 @@ typedef struct BtLock BtLock;
** -DSQLITE_FILE_HEADER="..." on the compiler command-line. The
** header must be exactly 16 bytes including the zero-terminator so
** the string itself should be 15 characters long. If you change
-** the header, then your custom library will not be able to read
+** 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.
*/
@@ -37872,7 +47640,7 @@ struct MemPage {
/*
** 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
+** 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.
@@ -37896,7 +47664,7 @@ struct BtLock {
** 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
+** 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
@@ -37904,9 +47672,9 @@ struct BtLock {
** 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
+** 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 do go through this Btree to find their BtShared and
+** cursors have to go through this Btree to find their BtShared and
** they often do so without holding sqlite3.mutex.
*/
struct Btree {
@@ -37937,7 +47705,7 @@ struct Btree {
/*
** An instance of this object represents a single database file.
-**
+**
** A single database file can be in use as the same time by two
** or more database connections. When two or more connections are
** sharing the same database file, each connection has it own
@@ -37978,21 +47746,25 @@ struct BtShared {
u8 readOnly; /* True if the underlying file is readonly */
u8 pageSizeFixed; /* True if the page size can no longer be changed */
u8 secureDelete; /* True if secure_delete is enabled */
+ u8 initiallyEmpty; /* Database is empty at start of transaction */
+ u8 openFlags; /* Flags to sqlite3BtreeOpen() */
#ifndef SQLITE_OMIT_AUTOVACUUM
u8 autoVacuum; /* True if auto-vacuum is enabled */
u8 incrVacuum; /* True if incr-vacuum is enabled */
#endif
- u16 pageSize; /* Total number of bytes on a page */
- u16 usableSize; /* Number of usable bytes on each page */
+ u8 inTransaction; /* Transaction state */
+ u8 doNotUseWAL; /* If true, do not open write-ahead-log file */
u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */
u16 minLeaf; /* Minimum local payload in a LEAFDATA table */
- u8 inTransaction; /* Transaction state */
+ u32 pageSize; /* Total number of bytes on a page */
+ u32 usableSize; /* Number of usable bytes on each page */
int nTransaction; /* Number of open transactions (read + write) */
+ u32 nPage; /* Number of pages in the database */
void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */
void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */
- sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */
+ sqlite3_mutex *mutex; /* Non-recursive mutex required to access this object */
Bitvec *pHasContent; /* Set of pages moved to free-list this transaction */
#ifndef SQLITE_OMIT_SHARED_CACHE
int nRef; /* Number of references to this structure */
@@ -38012,8 +47784,8 @@ struct BtShared {
*/
typedef struct CellInfo CellInfo;
struct CellInfo {
- u8 *pCell; /* Pointer to the start of cell content */
i64 nKey; /* The key for INTKEY tables, or number of bytes in key */
+ u8 *pCell; /* Pointer to the start of cell content */
u32 nData; /* Number of bytes of data */
u32 nPayload; /* Total amount of payload */
u16 nHeader; /* Size of the cell content header in bytes */
@@ -38045,7 +47817,7 @@ struct CellInfo {
** particular database connection identified BtCursor.pBtree.db.
**
** Fields in this structure are accessed under the BtShared.mutex
-** found at self->pBt->mutex.
+** found at self->pBt->mutex.
*/
struct BtCursor {
Btree *pBtree; /* The Btree to which this cursor belongs */
@@ -38055,20 +47827,20 @@ struct BtCursor {
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 */
+ i64 nKey; /* Size of pKey, or last integer key */
+ void *pKey; /* Saved key that was cursor's last known position */
+ int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
u8 wrFlag; /* True if writable */
u8 atLast; /* Cursor pointing to the last entry */
u8 validNKey; /* True if info.nKey is valid */
u8 eState; /* One of the CURSOR_XXX constants (see below) */
- void *pKey; /* Saved key that was cursor's last known position */
- i64 nKey; /* Size of pKey, or last integer key */
- int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
#ifndef SQLITE_OMIT_INCRBLOB
- u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
Pgno *aOverflow; /* Cache of overflow page locations */
+ u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
#endif
i16 iPage; /* Index of current page in apPage */
- MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
+ MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
};
/*
@@ -38078,14 +47850,14 @@ struct BtCursor {
** Cursor points to a valid entry. getPayload() etc. may be called.
**
** CURSOR_INVALID:
-** Cursor does not point to a valid entry. This can happen (for example)
+** Cursor does not point to a valid entry. This can happen (for example)
** because the table is empty or because BtreeCursorFirst() has not been
** called.
**
** CURSOR_REQUIRESEEK:
-** The table that this cursor was opened on still exists, but has been
+** The table that this cursor was opened on still exists, but has been
** modified since the cursor was last used. The cursor position is saved
-** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in
+** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in
** this state, restoreCursorPosition() can be called to attempt to
** seek the cursor to the saved position.
**
@@ -38101,13 +47873,13 @@ struct BtCursor {
#define CURSOR_REQUIRESEEK 2
#define CURSOR_FAULT 3
-/*
+/*
** The database page the PENDING_BYTE occupies. This page is never used.
*/
# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt)
/*
-** These macros define the location of the pointer-map entry for a
+** These macros define the location of the pointer-map entry for a
** database page. The first argument to each is the number of usable
** bytes on each page of the database (often 1024). The second is the
** page number to look up in the pointer map.
@@ -38142,10 +47914,10 @@ struct BtCursor {
** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not
** used in this case.
**
-** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number
+** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number
** is not used in this case.
**
-** PTRMAP_OVERFLOW1: The database page is the first page in a list of
+** PTRMAP_OVERFLOW1: The database page is the first page in a list of
** overflow pages. The page number identifies the page that
** contains the cell with a pointer to this overflow page.
**
@@ -38167,13 +47939,13 @@ struct BtCursor {
*/
#define btreeIntegrity(p) \
assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \
- assert( p->pBt->inTransaction>=p->inTrans );
+ assert( p->pBt->inTransaction>=p->inTrans );
/*
** The ISAUTOVACUUM macro is used within balance_nonroot() to determine
** if the database supports auto-vacuum or not. Because it is used
-** within an expression that is an argument to another macro
+** within an expression that is an argument to another macro
** (sqliteMallocRaw), it is not possible to use conditional compilation.
** So, this macro is defined instead.
*/
@@ -38233,12 +48005,13 @@ static void lockBtreeMutex(Btree *p){
** clear the p->locked boolean.
*/
static void unlockBtreeMutex(Btree *p){
+ BtShared *pBt = p->pBt;
assert( p->locked==1 );
- assert( sqlite3_mutex_held(p->pBt->mutex) );
+ assert( sqlite3_mutex_held(pBt->mutex) );
assert( sqlite3_mutex_held(p->db->mutex) );
- assert( p->db==p->pBt->db );
+ assert( p->db==pBt->db );
- sqlite3_mutex_leave(p->pBt->mutex);
+ sqlite3_mutex_leave(pBt->mutex);
p->locked = 0;
}
@@ -38379,30 +48152,11 @@ SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){
*/
SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){
int i;
- Btree *p, *pLater;
+ Btree *p;
assert( sqlite3_mutex_held(db->mutex) );
for(i=0; inDb; i++){
p = db->aDb[i].pBt;
- assert( !p || (p->locked==0 && p->sharable) || p->pBt->db==p->db );
- if( p && p->sharable ){
- p->wantToLock++;
- if( !p->locked ){
- assert( p->wantToLock==1 );
- while( p->pPrev ) p = p->pPrev;
- /* Reason for ALWAYS: There must be at least on unlocked Btree in
- ** the chain. Otherwise the !p->locked test above would have failed */
- while( p->locked && ALWAYS(p->pNext) ) p = p->pNext;
- for(pLater = p->pNext; pLater; pLater=pLater->pNext){
- if( pLater->locked ){
- unlockBtreeMutex(pLater);
- }
- }
- while( p ){
- lockBtreeMutex(p);
- p = p->pNext;
- }
- }
- }
+ if( p ) sqlite3BtreeEnter(p);
}
}
SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){
@@ -38411,16 +48165,18 @@ SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){
assert( sqlite3_mutex_held(db->mutex) );
for(i=0; inDb; i++){
p = db->aDb[i].pBt;
- if( p && p->sharable ){
- assert( p->wantToLock>0 );
- p->wantToLock--;
- if( p->wantToLock==0 ){
- unlockBtreeMutex(p);
- }
- }
+ if( p ) sqlite3BtreeLeave(p);
}
}
+/*
+** Return true if a particular Btree requires a lock. Return FALSE if
+** no lock is ever required since it is not sharable.
+*/
+SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){
+ return p->sharable;
+}
+
#ifndef NDEBUG
/*
** Return true if the current thread holds the database connection
@@ -38445,97 +48201,42 @@ SQLITE_PRIVATE int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){
}
#endif /* NDEBUG */
-/*
-** Add a new Btree pointer to a BtreeMutexArray.
-** if the pointer can possibly be shared with
-** another database connection.
-**
-** The pointers are kept in sorted order by pBtree->pBt. That
-** way when we go to enter all the mutexes, we can enter them
-** in order without every having to backup and retry and without
-** worrying about deadlock.
-**
-** The number of shared btrees will always be small (usually 0 or 1)
-** so an insertion sort is an adequate algorithm here.
-*/
-SQLITE_PRIVATE void sqlite3BtreeMutexArrayInsert(BtreeMutexArray *pArray, Btree *pBtree){
- int i, j;
- BtShared *pBt;
- if( pBtree==0 || pBtree->sharable==0 ) return;
#ifndef NDEBUG
- {
- for(i=0; inMutex; i++){
- assert( pArray->aBtree[i]!=pBtree );
- }
- }
-#endif
- assert( pArray->nMutex>=0 );
- assert( pArray->nMutexaBtree)-1 );
- pBt = pBtree->pBt;
- for(i=0; inMutex; i++){
- assert( pArray->aBtree[i]!=pBtree );
- if( pArray->aBtree[i]->pBt>pBt ){
- for(j=pArray->nMutex; j>i; j--){
- pArray->aBtree[j] = pArray->aBtree[j-1];
- }
- pArray->aBtree[i] = pBtree;
- pArray->nMutex++;
- return;
- }
- }
- pArray->aBtree[pArray->nMutex++] = pBtree;
-}
-
/*
-** Enter the mutex of every btree in the array. This routine is
-** called at the beginning of sqlite3VdbeExec(). The mutexes are
-** exited at the end of the same function.
+** Return true if the correct mutexes are held for accessing the
+** db->aDb[iDb].pSchema structure. The mutexes required for schema
+** access are:
+**
+** (1) The mutex on db
+** (2) if iDb!=1, then the mutex on db->aDb[iDb].pBt.
+**
+** If pSchema is not NULL, then iDb is computed from pSchema and
+** db using sqlite3SchemaToIndex().
*/
-SQLITE_PRIVATE void sqlite3BtreeMutexArrayEnter(BtreeMutexArray *pArray){
- int i;
- for(i=0; inMutex; i++){
- Btree *p = pArray->aBtree[i];
- /* Some basic sanity checking */
- assert( i==0 || pArray->aBtree[i-1]->pBtpBt );
- assert( !p->locked || p->wantToLock>0 );
-
- /* We should already hold a lock on the database connection */
- assert( sqlite3_mutex_held(p->db->mutex) );
-
- /* The Btree is sharable because only sharable Btrees are entered
- ** into the array in the first place. */
- assert( p->sharable );
-
- p->wantToLock++;
- if( !p->locked ){
- lockBtreeMutex(p);
- }
- }
+SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3 *db, int iDb, Schema *pSchema){
+ Btree *p;
+ assert( db!=0 );
+ if( pSchema ) iDb = sqlite3SchemaToIndex(db, pSchema);
+ assert( iDb>=0 && iDbnDb );
+ if( !sqlite3_mutex_held(db->mutex) ) return 0;
+ if( iDb==1 ) return 1;
+ p = db->aDb[iDb].pBt;
+ assert( p!=0 );
+ return p->sharable==0 || p->locked==1;
}
+#endif /* NDEBUG */
+#else /* SQLITE_THREADSAFE>0 above. SQLITE_THREADSAFE==0 below */
/*
-** Leave the mutex of every btree in the group.
+** The following are special cases for mutex enter routines for use
+** in single threaded applications that use shared cache. Except for
+** these two routines, all mutex operations are no-ops in that case and
+** are null #defines in btree.h.
+**
+** If shared cache is disabled, then all btree mutex routines, including
+** the ones below, are no-ops and are null #defines in btree.h.
*/
-SQLITE_PRIVATE void sqlite3BtreeMutexArrayLeave(BtreeMutexArray *pArray){
- int i;
- for(i=0; inMutex; i++){
- Btree *p = pArray->aBtree[i];
- /* Some basic sanity checking */
- assert( i==0 || pArray->aBtree[i-1]->pBtpBt );
- assert( p->locked );
- assert( p->wantToLock>0 );
- /* We should already hold a lock on the database connection */
- assert( sqlite3_mutex_held(p->db->mutex) );
-
- p->wantToLock--;
- if( p->wantToLock==0 ){
- unlockBtreeMutex(p);
- }
- }
-}
-
-#else
SQLITE_PRIVATE void sqlite3BtreeEnter(Btree *p){
p->pBt->db = p->db;
}
@@ -38586,13 +48287,22 @@ int sqlite3BtreeTrace=1; /* True to enable tracing */
# define TRACE(X)
#endif
-
+/*
+** Extract a 2-byte big-endian integer from an array of unsigned bytes.
+** But if the value is zero, make it 65536.
+**
+** This routine is used to extract the "offset to cell content area" value
+** from the header of a btree page. If the page size is 65536 and the page
+** is empty, the offset should be 65536, but the 2-byte value stores zero.
+** This routine makes the necessary adjustment to 65536.
+*/
+#define get2byteNotZero(X) (((((int)get2byte(X))-1)&0xffff)+1)
#ifndef SQLITE_OMIT_SHARED_CACHE
/*
** A list of BtShared objects that are eligible for participation
** in shared cache. This variable has file scope during normal builds,
-** but the test harness needs to access it so we make it global for
+** but the test harness needs to access it so we make it global for
** test builds.
**
** Access to this variable is protected by SQLITE_MUTEX_STATIC_MASTER.
@@ -38627,7 +48337,7 @@ SQLITE_API int sqlite3_enable_shared_cache(int enable){
** manipulate entries in the BtShared.pLock linked list used to store
** shared-cache table level locks. If the library is compiled with the
** shared-cache feature disabled, then there is only ever one user
- ** of each BtShared structure and so this locking is not necessary.
+ ** of each BtShared structure and so this locking is not necessary.
** So define the lock related functions as no-ops.
*/
#define querySharedCacheTableLock(a,b,c) SQLITE_OK
@@ -38644,15 +48354,15 @@ SQLITE_API int sqlite3_enable_shared_cache(int enable){
/*
**** This function is only used as part of an assert() statement. ***
**
-** Check to see if pBtree holds the required locks to read or write to the
+** Check to see if pBtree holds the required locks to read or write to the
** table with root page iRoot. Return 1 if it does and 0 if not.
**
-** For example, when writing to a table with root-page iRoot via
+** For example, when writing to a table with root-page iRoot via
** Btree connection pBtree:
**
** assert( hasSharedCacheTableLock(pBtree, iRoot, 0, WRITE_LOCK) );
**
-** When writing to an index that resides in a sharable database, the
+** When writing to an index that resides in a sharable database, the
** caller should have first obtained a lock specifying the root page of
** the corresponding table. This makes things a bit more complicated,
** as this module treats each table as a separate structure. To determine
@@ -38674,7 +48384,7 @@ static int hasSharedCacheTableLock(
BtLock *pLock;
/* If this database is not shareable, or if the client is reading
- ** and has the read-uncommitted flag set, then no lock is required.
+ ** and has the read-uncommitted flag set, then no lock is required.
** Return true immediately.
*/
if( (pBtree->sharable==0)
@@ -38708,13 +48418,13 @@ static int hasSharedCacheTableLock(
iTab = iRoot;
}
- /* Search for the required lock. Either a write-lock on root-page iTab, a
+ /* Search for the required lock. Either a write-lock on root-page iTab, a
** write-lock on the schema table, or (if the client is reading) a
** read-lock on iTab will suffice. Return 1 if any of these are found. */
for(pLock=pBtree->pBt->pLock; pLock; pLock=pLock->pNext){
- if( pLock->pBtree==pBtree
+ if( pLock->pBtree==pBtree
&& (pLock->iTable==iTab || (pLock->eLock==WRITE_LOCK && pLock->iTable==1))
- && pLock->eLock>=eLockType
+ && pLock->eLock>=eLockType
){
return 1;
}
@@ -38747,7 +48457,7 @@ static int hasSharedCacheTableLock(
static int hasReadConflicts(Btree *pBtree, Pgno iRoot){
BtCursor *p;
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
- if( p->pgnoRoot==iRoot
+ if( p->pgnoRoot==iRoot
&& p->pBtree!=pBtree
&& 0==(p->pBtree->db->flags & SQLITE_ReadUncommitted)
){
@@ -38759,7 +48469,7 @@ static int hasReadConflicts(Btree *pBtree, Pgno iRoot){
#endif /* #ifdef SQLITE_DEBUG */
/*
-** Query to see if Btree handle p may obtain a lock of type eLock
+** Query to see if Btree handle p may obtain a lock of type eLock
** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return
** SQLITE_OK if the lock may be obtained (by calling
** setSharedCacheTableLock()), or SQLITE_LOCKED if not.
@@ -38772,14 +48482,14 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
assert( eLock==READ_LOCK || eLock==WRITE_LOCK );
assert( p->db!=0 );
assert( !(p->db->flags&SQLITE_ReadUncommitted)||eLock==WRITE_LOCK||iTab==1 );
-
+
/* If requesting a write-lock, then the Btree must have an open write
- ** transaction on this file. And, obviously, for this to be so there
+ ** transaction on this file. And, obviously, for this to be so there
** must be an open write transaction on the file itself.
*/
assert( eLock==READ_LOCK || (p==pBt->pWriter && p->inTrans==TRANS_WRITE) );
assert( eLock==READ_LOCK || pBt->inTransaction==TRANS_WRITE );
-
+
/* This routine is a no-op if the shared-cache is not enabled */
if( !p->sharable ){
return SQLITE_OK;
@@ -38794,7 +48504,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
}
for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
- /* The condition (pIter->eLock!=eLock) in the following if(...)
+ /* The condition (pIter->eLock!=eLock) in the following if(...)
** statement is a simplification of:
**
** (eLock==WRITE_LOCK || pIter->eLock==WRITE_LOCK)
@@ -38821,7 +48531,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
#ifndef SQLITE_OMIT_SHARED_CACHE
/*
** Add a lock on the table with root-page iTable to the shared-btree used
-** by Btree handle p. Parameter eLock must be either READ_LOCK or
+** by Btree handle p. Parameter eLock must be either READ_LOCK or
** WRITE_LOCK.
**
** This function assumes the following:
@@ -38833,7 +48543,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
** with the requested lock (i.e. querySharedCacheTableLock() has
** already been called and returned SQLITE_OK).
**
-** SQLITE_OK is returned if the lock is added successfully. SQLITE_NOMEM
+** SQLITE_OK is returned if the lock is added successfully. SQLITE_NOMEM
** is returned if a malloc attempt fails.
*/
static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
@@ -38847,11 +48557,11 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
/* A connection with the read-uncommitted flag set will never try to
** obtain a read-lock using this function. The only read-lock obtained
- ** by a connection in read-uncommitted mode is on the sqlite_master
+ ** by a connection in read-uncommitted mode is on the sqlite_master
** table, and that lock is obtained in BtreeBeginTrans(). */
assert( 0==(p->db->flags&SQLITE_ReadUncommitted) || eLock==WRITE_LOCK );
- /* This function should only be called on a sharable b-tree after it
+ /* This function should only be called on a sharable b-tree after it
** has been determined that no other b-tree holds a conflicting lock. */
assert( p->sharable );
assert( SQLITE_OK==querySharedCacheTableLock(p, iTable, eLock) );
@@ -38896,7 +48606,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
** Release all the table locks (locks obtained via calls to
** the setSharedCacheTableLock() procedure) held by Btree object p.
**
-** This function assumes that Btree p has an open read or write
+** This function assumes that Btree p has an open read or write
** transaction. If it does not, then the BtShared.isPending variable
** may be incorrectly cleared.
*/
@@ -38929,7 +48639,7 @@ static void clearAllSharedCacheTableLocks(Btree *p){
pBt->isExclusive = 0;
pBt->isPending = 0;
}else if( pBt->nTransaction==2 ){
- /* This function is called when Btree p is concluding its
+ /* This function is called when Btree p is concluding its
** transaction. If there currently exists a writer, and p is not
** that writer, then the number of locks held by connections other
** than the writer must be about to drop to zero. In this case
@@ -39033,8 +48743,8 @@ static void invalidateIncrblobCursors(
#endif /* SQLITE_OMIT_INCRBLOB */
/*
-** Set bit pgno of the BtShared.pHasContent bitvec. This is called
-** when a page that previously contained data becomes a free-list leaf
+** Set bit pgno of the BtShared.pHasContent bitvec. This is called
+** when a page that previously contained data becomes a free-list leaf
** page.
**
** The BtShared.pHasContent bitvec exists to work around an obscure
@@ -39060,7 +48770,7 @@ static void invalidateIncrblobCursors(
** may be lost. In the event of a rollback, it may not be possible
** to restore the database to its original configuration.
**
-** The solution is the BtShared.pHasContent bitvec. Whenever a page is
+** The solution is the BtShared.pHasContent bitvec. Whenever a page is
** moved to become a free-list leaf page, the corresponding bit is
** set in the bitvec. Whenever a leaf page is extracted from the free-list,
** optimization 2 above is omitted if the corresponding bit is already
@@ -39070,11 +48780,8 @@ static void invalidateIncrblobCursors(
static int btreeSetHasContent(BtShared *pBt, Pgno pgno){
int rc = SQLITE_OK;
if( !pBt->pHasContent ){
- int nPage = 100;
- sqlite3PagerPagecount(pBt->pPager, &nPage);
- /* If sqlite3PagerPagecount() fails there is no harm because the
- ** nPage variable is unchanged from its default value of 100 */
- pBt->pHasContent = sqlite3BitvecCreate((u32)nPage);
+ assert( pgno<=pBt->nPage );
+ pBt->pHasContent = sqlite3BitvecCreate(pBt->nPage);
if( !pBt->pHasContent ){
rc = SQLITE_NOMEM;
}
@@ -39107,11 +48814,11 @@ static void btreeClearHasContent(BtShared *pBt){
}
/*
-** Save the current cursor position in the variables BtCursor.nKey
+** Save the current cursor position in the variables BtCursor.nKey
** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
**
** The caller must ensure that the cursor is valid (has eState==CURSOR_VALID)
-** prior to calling this routine.
+** prior to calling this routine.
*/
static int saveCursorPosition(BtCursor *pCur){
int rc;
@@ -39126,7 +48833,7 @@ static int saveCursorPosition(BtCursor *pCur){
/* If this is an intKey table, then the above call to BtreeKeySize()
** stores the integer key in pCur->nKey. In this case this value is
** all that is required. Otherwise, if pCur is not open on an intKey
- ** table, then malloc space for and store the pCur->nKey bytes of key
+ ** table, then malloc space for and store the pCur->nKey bytes of key
** data.
*/
if( 0==pCur->apPage[0]->intKey ){
@@ -39168,7 +48875,7 @@ 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) &&
+ if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) &&
p->eState==CURSOR_VALID ){
int rc = saveCursorPosition(p);
if( SQLITE_OK!=rc ){
@@ -39204,27 +48911,30 @@ static int btreeMoveto(
int rc; /* Status code */
UnpackedRecord *pIdxKey; /* Unpacked index key */
char aSpace[150]; /* Temp space for pIdxKey - to avoid a malloc */
+ char *pFree = 0;
if( pKey ){
assert( nKey==(i64)(int)nKey );
- pIdxKey = sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey,
- aSpace, sizeof(aSpace));
+ pIdxKey = sqlite3VdbeAllocUnpackedRecord(
+ pCur->pKeyInfo, aSpace, sizeof(aSpace), &pFree
+ );
if( pIdxKey==0 ) return SQLITE_NOMEM;
+ sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey);
}else{
pIdxKey = 0;
}
rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes);
- if( pKey ){
- sqlite3VdbeDeleteUnpackedRecord(pIdxKey);
+ if( pFree ){
+ sqlite3DbFree(pCur->pKeyInfo->db, pFree);
}
return rc;
}
/*
** Restore the cursor to the position it was in (or as close to as possible)
-** when saveCursorPosition() was called. Note that this call deletes the
+** when saveCursorPosition() was called. Note that this call deletes the
** saved position info stored by saveCursorPosition(), so there can be
-** at most one effective restoreCursorPosition() call after each
+** at most one effective restoreCursorPosition() call after each
** saveCursorPosition().
*/
static int btreeRestoreCursorPosition(BtCursor *pCur){
@@ -39278,14 +48988,19 @@ SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){
** Given a page number of a regular database page, return the page
** number for the pointer-map page that contains the entry for the
** input page number.
+**
+** Return 0 (not a valid page) for pgno==1 since there is
+** no pointer map associated with page 1. The integrity_check logic
+** requires that ptrmapPageno(*,1)!=1.
*/
static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){
int nPagesPerMapPage;
Pgno iPtrMap, ret;
assert( sqlite3_mutex_held(pBt->mutex) );
+ if( pgno<2 ) return 0;
nPagesPerMapPage = (pBt->usableSize/5)+1;
iPtrMap = (pgno-2)/nPagesPerMapPage;
- ret = (iPtrMap*nPagesPerMapPage) + 2;
+ ret = (iPtrMap*nPagesPerMapPage) + 2;
if( ret==PENDING_BYTE_PAGE(pBt) ){
ret++;
}
@@ -39331,6 +49046,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
*pRC = SQLITE_CORRUPT_BKPT;
goto ptrmap_exit;
}
+ assert( offset <= (int)pBt->usableSize-5 );
pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage);
if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
@@ -39370,6 +49086,11 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage);
offset = PTRMAP_PTROFFSET(iPtrmap, key);
+ if( offset<0 ){
+ sqlite3PagerUnref(pDbPage);
+ return SQLITE_CORRUPT_BKPT;
+ }
+ assert( offset <= (int)pBt->usableSize-5 );
assert( pEType!=0 );
*pEType = pPtrmap[offset];
if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
@@ -39394,6 +49115,8 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
*/
#define findCell(P,I) \
((P)->aData + ((P)->maskPage & get2byte(&(P)->aData[(P)->cellOffset+2*(I)])))
+#define findCellv2(D,M,O,I) (D+(M&get2byte(D+(O+2*(I)))))
+
/*
** This a more complex version of findCell() that works for
@@ -39419,8 +49142,8 @@ static u8 *findOverflowCell(MemPage *pPage, int iCell){
/*
** Parse a cell content block and fill in the CellInfo structure. There
-** are two versions of this function. btreeParseCell() takes a
-** cell index as the second argument and btreeParseCellPtr()
+** are two versions of this function. btreeParseCell() takes a
+** cell index as the second argument and btreeParseCellPtr()
** takes a pointer to the body of the cell as its second argument.
**
** Within this file, the parseCell() macro can be called instead of
@@ -39461,14 +49184,9 @@ static void btreeParseCellPtr(
/* This is the (easy) common case where the entire payload fits
** on the local page. No overflow is required.
*/
- int nSize; /* Total size of cell content in bytes */
- nSize = nPayload + n;
+ if( (pInfo->nSize = (u16)(n+nPayload))<4 ) pInfo->nSize = 4;
pInfo->nLocal = (u16)nPayload;
pInfo->iOverflow = 0;
- if( (nSize & ~3)==0 ){
- nSize = 4; /* Minimum cell size is 4 */
- }
- pInfo->nSize = (u16)nSize;
}else{
/* If the payload will not fit completely on the local page, we have
** to decide how much to store locally and how much to spill onto
@@ -39534,7 +49252,7 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
nSize = 0;
}
- /* pIter now points at the 64-bit integer key value, a variable length
+ /* pIter now points at the 64-bit integer key value, a variable length
** integer. The following block moves pIter to point at the first byte
** past the end of the key value. */
pEnd = &pIter[9];
@@ -39640,7 +49358,7 @@ static int defragmentPage(MemPage *pPage){
testcase( pc==iCellLast );
#if !defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK)
/* These conditions have already been verified in btreeInitPage()
- ** if SQLITE_ENABLE_OVERSIZE_CELL_CHECK is defined
+ ** if SQLITE_ENABLE_OVERSIZE_CELL_CHECK is defined
*/
if( pciCellLast ){
return SQLITE_CORRUPT_BKPT;
@@ -39698,7 +49416,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
int gap; /* First byte of gap between cell pointers and cell content */
int rc; /* Integer return code */
int usableSize; /* Usable size of the page */
-
+
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( pPage->pBt );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
@@ -39711,7 +49429,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
nFrag = data[hdr+7];
assert( pPage->cellOffset == hdr + 12 - 4*pPage->leaf );
gap = pPage->cellOffset + 2*pPage->nCell;
- top = get2byte(&data[hdr+5]);
+ top = get2byteNotZero(&data[hdr+5]);
if( gap>top ) return SQLITE_CORRUPT_BKPT;
testcase( gap+2==top );
testcase( gap+1==top );
@@ -39721,10 +49439,10 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
/* Always defragment highly fragmented pages */
rc = defragmentPage(pPage);
if( rc ) return rc;
- top = get2byte(&data[hdr+5]);
+ top = get2byteNotZero(&data[hdr+5]);
}else if( gap+2<=top ){
- /* Search the freelist looking for a free slot big enough to satisfy
- ** the request. The allocation is made from the first free slot in
+ /* Search the freelist looking for a free slot big enough to satisfy
+ ** the request. The allocation is made from the first free slot in
** the list that is large enough to accomadate it.
*/
int pc, addr;
@@ -39763,7 +49481,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
if( gap+2+nByte>top ){
rc = defragmentPage(pPage);
if( rc ) return rc;
- top = get2byte(&data[hdr+5]);
+ top = get2byteNotZero(&data[hdr+5]);
assert( gap+nByte<=top );
}
@@ -39776,7 +49494,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
*/
top -= nByte;
put2byte(&data[hdr+5], top);
- assert( top+nByte <= pPage->pBt->usableSize );
+ assert( top+nByte <= (int)pPage->pBt->usableSize );
*pIdx = top;
return SQLITE_OK;
}
@@ -39797,7 +49515,7 @@ static int freeSpace(MemPage *pPage, int start, int size){
assert( pPage->pBt!=0 );
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( start>=pPage->hdrOffset+6+pPage->childPtrSize );
- assert( (start + size)<=pPage->pBt->usableSize );
+ assert( (start + size) <= (int)pPage->pBt->usableSize );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( size>=0 ); /* Minimum cell size is 4 */
@@ -39840,7 +49558,7 @@ static int freeSpace(MemPage *pPage, int start, int size){
while( (pbegin = get2byte(&data[addr]))>0 ){
int pnext, psize, x;
assert( pbegin>addr );
- assert( pbegin<=pPage->pBt->usableSize-4 );
+ assert( pbegin <= (int)pPage->pBt->usableSize-4 );
pnext = get2byte(&data[pbegin]);
psize = get2byte(&data[pbegin+2]);
if( pbegin + psize + 3 >= pnext && pnext>0 ){
@@ -39911,7 +49629,7 @@ static int decodeFlags(MemPage *pPage, int flagByte){
** Initialize the auxiliary information for a disk block.
**
** Return SQLITE_OK on success. If we see that the page does
-** not contain a well-formed database page, then return
+** not contain a well-formed database page, then return
** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not
** guarantee that the page is well-formed. It only shows that
** we failed to detect any corruption.
@@ -39929,10 +49647,10 @@ static int btreeInitPage(MemPage *pPage){
u8 hdr; /* Offset to beginning of page header */
u8 *data; /* Equal to pPage->aData */
BtShared *pBt; /* The main btree structure */
- u16 usableSize; /* Amount of usable space on each page */
+ int usableSize; /* Amount of usable space on each page */
u16 cellOffset; /* Offset from start of page to first cell pointer */
- u16 nFree; /* Number of unused bytes on the page */
- u16 top; /* First byte of the cell content area */
+ int nFree; /* Number of unused bytes on the page */
+ int top; /* First byte of the cell content area */
int iCellFirst; /* First allowable cell or freeblock offset */
int iCellLast; /* Last possible cell or freeblock offset */
@@ -39941,12 +49659,12 @@ static int btreeInitPage(MemPage *pPage){
hdr = pPage->hdrOffset;
data = pPage->aData;
if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT;
- assert( pBt->pageSize>=512 && pBt->pageSize<=32768 );
- pPage->maskPage = pBt->pageSize - 1;
+ assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
+ pPage->maskPage = (u16)(pBt->pageSize - 1);
pPage->nOverflow = 0;
usableSize = pBt->usableSize;
pPage->cellOffset = cellOffset = hdr + 12 - 4*pPage->leaf;
- top = get2byte(&data[hdr+5]);
+ top = get2byteNotZero(&data[hdr+5]);
pPage->nCell = get2byte(&data[hdr+3]);
if( pPage->nCell>MX_CELL(pBt) ){
/* To many cells for a single page. The page must be corrupt */
@@ -39955,10 +49673,10 @@ static int btreeInitPage(MemPage *pPage){
testcase( pPage->nCell==MX_CELL(pBt) );
/* A malformed database page might cause us to read past the end
- ** of page when parsing a cell.
+ ** of page when parsing a cell.
**
** The following block of code checks early to see if a cell extends
- ** past the end of a page boundary and causes SQLITE_CORRUPT to be
+ ** past the end of a page boundary and causes SQLITE_CORRUPT to be
** returned if it does.
*/
iCellFirst = cellOffset + 2*pPage->nCell;
@@ -39983,7 +49701,7 @@ static int btreeInitPage(MemPage *pPage){
}
}
if( !pPage->leaf ) iCellLast++;
- }
+ }
#endif
/* Compute the total free space on the page */
@@ -39993,14 +49711,14 @@ static int btreeInitPage(MemPage *pPage){
u16 next, size;
if( pciCellLast ){
/* Start of free block is off the page */
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_BKPT;
}
next = get2byte(&data[pc]);
size = get2byte(&data[pc+2]);
if( (next>0 && next<=pc+size+3) || pc+size>usableSize ){
/* Free blocks must be in ascending order. And the last byte of
** the free-block must lie on the database page. */
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_BKPT;
}
nFree = nFree + size;
pc = next;
@@ -40014,7 +49732,7 @@ static int btreeInitPage(MemPage *pPage){
** area, according to the page header, lies within the page.
*/
if( nFree>usableSize ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_BKPT;
}
pPage->nFree = (u16)(nFree - iCellFirst);
pPage->isInit = 1;
@@ -40045,13 +49763,13 @@ static void zeroPage(MemPage *pPage, int flags){
memset(&data[hdr+1], 0, 4);
data[hdr+7] = 0;
put2byte(&data[hdr+5], pBt->usableSize);
- pPage->nFree = pBt->usableSize - first;
+ pPage->nFree = (u16)(pBt->usableSize - first);
decodeFlags(pPage, flags);
pPage->hdrOffset = hdr;
pPage->cellOffset = first;
pPage->nOverflow = 0;
- assert( pBt->pageSize>=512 && pBt->pageSize<=32768 );
- pPage->maskPage = pBt->pageSize - 1;
+ assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
+ pPage->maskPage = (u16)(pBt->pageSize - 1);
pPage->nCell = 0;
pPage->isInit = 1;
}
@@ -40068,7 +49786,7 @@ static MemPage *btreePageFromDbPage(DbPage *pDbPage, Pgno pgno, BtShared *pBt){
pPage->pBt = pBt;
pPage->pgno = pgno;
pPage->hdrOffset = pPage->pgno==1 ? 100 : 0;
- return pPage;
+ return pPage;
}
/*
@@ -40117,18 +49835,18 @@ static MemPage *btreePageLookup(BtShared *pBt, Pgno pgno){
** Return the size of the database file in pages. If there is any kind of
** error, return ((unsigned int)-1).
*/
-static Pgno pagerPagecount(BtShared *pBt){
- int nPage = -1;
- int rc;
- assert( pBt->pPage1 );
- rc = sqlite3PagerPagecount(pBt->pPager, &nPage);
- assert( rc==SQLITE_OK || nPage==-1 );
- return (Pgno)nPage;
+static Pgno btreePagecount(BtShared *pBt){
+ return pBt->nPage;
+}
+SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){
+ assert( sqlite3BtreeHoldsMutex(p) );
+ assert( ((p->pBt->nPage)&0x8000000)==0 );
+ return (int)btreePagecount(p->pBt);
}
/*
** Get a page from the pager and initialize it. This routine is just a
-** convenience wrapper around separate calls to btreeGetPage() and
+** convenience wrapper around separate calls to btreeGetPage() and
** btreeInitPage().
**
** If an error occurs, then the value *ppPage is set to is undefined. It
@@ -40140,25 +49858,22 @@ static int getAndInitPage(
MemPage **ppPage /* Write the page pointer here */
){
int rc;
- TESTONLY( Pgno iLastPg = pagerPagecount(pBt); )
assert( sqlite3_mutex_held(pBt->mutex) );
- rc = btreeGetPage(pBt, pgno, ppPage, 0);
- if( rc==SQLITE_OK ){
- rc = btreeInitPage(*ppPage);
- if( rc!=SQLITE_OK ){
- releasePage(*ppPage);
+ if( pgno>btreePagecount(pBt) ){
+ rc = SQLITE_CORRUPT_BKPT;
+ }else{
+ rc = btreeGetPage(pBt, pgno, ppPage, 0);
+ if( rc==SQLITE_OK ){
+ rc = btreeInitPage(*ppPage);
+ if( rc!=SQLITE_OK ){
+ releasePage(*ppPage);
+ }
}
}
- /* If the requested page number was either 0 or greater than the page
- ** number of the last page in the database, this function should return
- ** SQLITE_CORRUPT or some other error (i.e. SQLITE_FULL). Check that this
- ** is the case. */
- assert( (pgno>0 && pgno<=iLastPg) || rc!=SQLITE_OK );
testcase( pgno==0 );
- testcase( pgno==iLastPg );
-
+ assert( pgno!=0 || rc==SQLITE_CORRUPT );
return rc;
}
@@ -40216,13 +49931,22 @@ static int btreeInvokeBusyHandler(void *pArg){
/*
** Open a database file.
-**
+**
** zFilename is the name of the database file. If zFilename is NULL
-** a new database with a random name is created. This randomly named
-** database file will be deleted when sqlite3BtreeClose() is called.
+** then an ephemeral database is created. The ephemeral database might
+** be exclusively in memory, or it might use a disk-based memory cache.
+** Either way, the ephemeral database will be automatically deleted
+** when sqlite3BtreeClose() is called.
+**
** If zFilename is ":memory:" then an in-memory database is created
** that is automatically destroyed when it is closed.
**
+** The "flags" parameter is a bitmask that might contain bits
+** BTREE_OMIT_JOURNAL and/or BTREE_NO_READLOCK. The BTREE_NO_READLOCK
+** bit is also set if the SQLITE_NoReadlock flags is set in db->flags.
+** These flags are passed through into sqlite3PagerOpen() and must
+** be the same values as PAGER_OMIT_JOURNAL and PAGER_NO_READLOCK.
+**
** If the database is already opened in the same database connection
** and we are in shared cache mode, then the open will fail with an
** SQLITE_CONSTRAINT error. We cannot allow two or more BtShared
@@ -40230,13 +49954,13 @@ static int btreeInvokeBusyHandler(void *pArg){
** to problems with locking.
*/
SQLITE_PRIVATE int sqlite3BtreeOpen(
+ sqlite3_vfs *pVfs, /* VFS to use for this b-tree */
const char *zFilename, /* Name of the file containing the BTree database */
sqlite3 *db, /* Associated database handle */
Btree **ppBtree, /* Pointer to new Btree object written here */
int flags, /* Options */
int vfsFlags /* Flags passed through to sqlite3_vfs.xOpen() */
){
- sqlite3_vfs *pVfs; /* The VFS to use for this btree */
BtShared *pBt = 0; /* Shared part of btree structure */
Btree *p; /* Handle to return */
sqlite3_mutex *mutexOpen = 0; /* Prevents a race condition. Ticket #3537 */
@@ -40244,23 +49968,39 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
u8 nReserve; /* Byte of unused space on each page */
unsigned char zDbHeader[100]; /* Database header content */
- /* Set the variable isMemdb to true for an in-memory database, or
- ** false for a file-based database. This symbol is only required if
- ** either of the shared-data or autovacuum features are compiled
- ** into the library.
+ /* True if opening an ephemeral, temporary database */
+ const int isTempDb = zFilename==0 || zFilename[0]==0;
+
+ /* Set the variable isMemdb to true for an in-memory database, or
+ ** false for a file-based database.
*/
-#if !defined(SQLITE_OMIT_SHARED_CACHE) || !defined(SQLITE_OMIT_AUTOVACUUM)
- #ifdef SQLITE_OMIT_MEMORYDB
- const int isMemdb = 0;
- #else
- const int isMemdb = zFilename && !strcmp(zFilename, ":memory:");
- #endif
+#ifdef SQLITE_OMIT_MEMORYDB
+ const int isMemdb = 0;
+#else
+ const int isMemdb = (zFilename && strcmp(zFilename, ":memory:")==0)
+ || (isTempDb && sqlite3TempInMemory(db));
#endif
assert( db!=0 );
+ assert( pVfs!=0 );
assert( sqlite3_mutex_held(db->mutex) );
+ assert( (flags&0xff)==flags ); /* flags fit in 8 bits */
- pVfs = db->pVfs;
+ /* Only a BTREE_SINGLE database can be BTREE_UNORDERED */
+ assert( (flags & BTREE_UNORDERED)==0 || (flags & BTREE_SINGLE)!=0 );
+
+ /* A BTREE_SINGLE database is always a temporary and/or ephemeral */
+ assert( (flags & BTREE_SINGLE)==0 || isTempDb );
+
+ if( db->flags & SQLITE_NoReadlock ){
+ flags |= BTREE_NO_READLOCK;
+ }
+ if( isMemdb ){
+ flags |= BTREE_MEMORY;
+ }
+ if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (isMemdb || isTempDb) ){
+ vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB;
+ }
p = sqlite3MallocZero(sizeof(Btree));
if( !p ){
return SQLITE_NOMEM;
@@ -40277,7 +50017,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
** If this Btree is a candidate for shared cache, try to find an
** existing BtShared object that we can share with
*/
- if( isMemdb==0 && zFilename && zFilename[0] ){
+ if( isMemdb==0 && isTempDb==0 ){
if( vfsFlags & SQLITE_OPEN_SHAREDCACHE ){
int nFullPathname = pVfs->mxPathname+1;
char *zFullPathname = sqlite3Malloc(nFullPathname);
@@ -40338,7 +50078,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
assert( sizeof(u32)==4 );
assert( sizeof(u16)==2 );
assert( sizeof(Pgno)==4 );
-
+
pBt = sqlite3MallocZero( sizeof(*pBt) );
if( pBt==0 ){
rc = SQLITE_NOMEM;
@@ -40352,17 +50092,18 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
if( rc!=SQLITE_OK ){
goto btree_open_out;
}
+ pBt->openFlags = (u8)flags;
pBt->db = db;
sqlite3PagerSetBusyhandler(pBt->pPager, btreeInvokeBusyHandler, pBt);
p->pBt = pBt;
-
+
pBt->pCursor = 0;
pBt->pPage1 = 0;
pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager);
#ifdef SQLITE_SECURE_DELETE
pBt->secureDelete = 1;
#endif
- pBt->pageSize = get2byte(&zDbHeader[16]);
+ pBt->pageSize = (zDbHeader[16]<<8) | (zDbHeader[17]<<16);
if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
|| ((pBt->pageSize-1)&pBt->pageSize)!=0 ){
pBt->pageSize = 0;
@@ -40391,7 +50132,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
if( rc ) goto btree_open_out;
pBt->usableSize = pBt->pageSize - nReserve;
assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */
-
+
#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
/* Add the new BtShared object to the linked list sharable BtShareds.
*/
@@ -40456,6 +50197,14 @@ btree_open_out:
sqlite3_free(pBt);
sqlite3_free(p);
*ppBtree = 0;
+ }else{
+ /* If the B-Tree was successfully opened, set the pager-cache size to the
+ ** default value. Except, when opening on an existing shared pager-cache,
+ ** do not change the pager-cache size.
+ */
+ if( sqlite3BtreeSchema(p, 0, 0)==0 ){
+ sqlite3PagerSetCachesize(p->pBt->pPager, SQLITE_DEFAULT_CACHE_SIZE);
+ }
}
if( mutexOpen ){
assert( sqlite3_mutex_held(mutexOpen) );
@@ -40505,7 +50254,7 @@ static int removeFromSharingList(BtShared *pBt){
}
/*
-** Make sure pBt->pTmpSpace points to an allocation of
+** Make sure pBt->pTmpSpace points to an allocation of
** MX_CELL_SIZE(pBt) bytes.
*/
static void allocateTempSpace(BtShared *pBt){
@@ -40549,7 +50298,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
sqlite3BtreeLeave(p);
/* If there are still other outstanding references to the shared-btree
- ** structure, return now. The remainder of this procedure cleans
+ ** structure, return now. The remainder of this procedure cleans
** up the shared-btree.
*/
assert( p->wantToLock==0 && p->locked==0 );
@@ -40564,7 +50313,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
if( pBt->xFreeSchema && pBt->pSchema ){
pBt->xFreeSchema(pBt->pSchema);
}
- sqlite3_free(pBt->pSchema);
+ sqlite3DbFree(0, pBt->pSchema);
freeTempSpace(pBt);
sqlite3_free(pBt);
}
@@ -40613,11 +50362,17 @@ SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
** probability of damage to near zero but with a write performance reduction.
*/
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
-SQLITE_PRIVATE int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync){
+SQLITE_PRIVATE int sqlite3BtreeSetSafetyLevel(
+ Btree *p, /* The btree to set the safety level on */
+ int level, /* PRAGMA synchronous. 1=OFF, 2=NORMAL, 3=FULL */
+ int fullSync, /* PRAGMA fullfsync. */
+ int ckptFullSync /* PRAGMA checkpoint_fullfync */
+){
BtShared *pBt = p->pBt;
assert( sqlite3_mutex_held(p->db->mutex) );
+ assert( level>=1 && level<=3 );
sqlite3BtreeEnter(p);
- sqlite3PagerSetSafetyLevel(pBt->pPager, level, fullSync);
+ sqlite3PagerSetSafetyLevel(pBt->pPager, level, fullSync, ckptFullSync);
sqlite3BtreeLeave(p);
return SQLITE_OK;
}
@@ -40630,7 +50385,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync)
SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree *p){
BtShared *pBt = p->pBt;
int rc;
- assert( sqlite3_mutex_held(p->db->mutex) );
+ assert( sqlite3_mutex_held(p->db->mutex) );
sqlite3BtreeEnter(p);
assert( pBt && pBt->pPager );
rc = sqlite3PagerNosync(pBt->pPager);
@@ -40638,10 +50393,9 @@ SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree *p){
return rc;
}
-#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM)
/*
** Change the default pages size and the number of reserved bytes per page.
-** Or, if the page size has already been fixed, return SQLITE_READONLY
+** Or, if the page size has already been fixed, return SQLITE_READONLY
** without changing anything.
**
** The page size must be a power of 2 between 512 and 65536. If the page
@@ -40676,7 +50430,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve,
((pageSize-1)&pageSize)==0 ){
assert( (pageSize & 7)==0 );
assert( !pBt->pPage1 && !pBt->pCursor );
- pBt->pageSize = (u16)pageSize;
+ pBt->pageSize = (u32)pageSize;
freeTempSpace(pBt);
}
rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, nReserve);
@@ -40693,6 +50447,7 @@ SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree *p){
return p->pBt->pageSize;
}
+#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM)
/*
** Return the number of bytes of space at the end of every page that
** are intentually left unused. This is the "reserved" space that is
@@ -40730,7 +50485,7 @@ SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){
sqlite3BtreeEnter(p);
if( newFlag>=0 ){
p->pBt->secureDelete = (newFlag!=0) ? 1 : 0;
- }
+ }
b = p->pBt->secureDelete;
sqlite3BtreeLeave(p);
return b;
@@ -40740,7 +50495,7 @@ SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){
/*
** Change the 'auto-vacuum' property of the database. If the 'autoVacuum'
** parameter is non-zero, then auto-vacuum mode is enabled. If zero, it
-** is disabled. The default value for the auto-vacuum property is
+** is disabled. The default value for the auto-vacuum property is
** determined by the SQLITE_DEFAULT_AUTOVACUUM macro.
*/
SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){
@@ -40764,7 +50519,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){
}
/*
-** Return the value of the 'auto-vacuum' property. If auto-vacuum is
+** Return the value of the 'auto-vacuum' property. If auto-vacuum is
** enabled 1 is returned. Otherwise 0.
*/
SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){
@@ -40791,12 +50546,14 @@ SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){
** SQLITE_OK is returned on success. If the file is not a
** well-formed database file, then SQLITE_CORRUPT is returned.
** SQLITE_BUSY is returned if the database is locked. SQLITE_NOMEM
-** is returned if we run out of memory.
+** is returned if we run out of memory.
*/
static int lockBtree(BtShared *pBt){
- int rc;
- MemPage *pPage1;
- int nPage;
+ int rc; /* Result code from subfunctions */
+ MemPage *pPage1; /* Page 1 of the database file */
+ int nPage; /* Number of pages in the database */
+ int nPageFile = 0; /* Number of pages in the database file */
+ int nPageHeader; /* Number of pages in the database according to hdr */
assert( sqlite3_mutex_held(pBt->mutex) );
assert( pBt->pPage1==0 );
@@ -40806,25 +50563,57 @@ static int lockBtree(BtShared *pBt){
if( rc!=SQLITE_OK ) return rc;
/* Do some checking to help insure the file we opened really is
- ** a valid database file.
+ ** a valid database file.
*/
- rc = sqlite3PagerPagecount(pBt->pPager, &nPage);
- if( rc!=SQLITE_OK ){
- goto page1_init_failed;
- }else if( nPage>0 ){
- int pageSize;
- int usableSize;
+ nPage = nPageHeader = get4byte(28+(u8*)pPage1->aData);
+ sqlite3PagerPagecount(pBt->pPager, &nPageFile);
+ if( nPage==0 || memcmp(24+(u8*)pPage1->aData, 92+(u8*)pPage1->aData,4)!=0 ){
+ nPage = nPageFile;
+ }
+ if( nPage>0 ){
+ u32 pageSize;
+ u32 usableSize;
u8 *page1 = pPage1->aData;
rc = SQLITE_NOTADB;
if( memcmp(page1, zMagicHeader, 16)!=0 ){
goto page1_init_failed;
}
+
+#ifdef SQLITE_OMIT_WAL
if( page1[18]>1 ){
pBt->readOnly = 1;
}
if( page1[19]>1 ){
goto page1_init_failed;
}
+#else
+ if( page1[18]>2 ){
+ pBt->readOnly = 1;
+ }
+ if( page1[19]>2 ){
+ goto page1_init_failed;
+ }
+
+ /* If the write version is set to 2, this database should be accessed
+ ** in WAL mode. If the log is not already open, open it now. Then
+ ** return SQLITE_OK and return without populating BtShared.pPage1.
+ ** The caller detects this and calls this function again. This is
+ ** required as the version of page 1 currently in the page1 buffer
+ ** may not be the latest version - there may be a newer one in the log
+ ** file.
+ */
+ if( page1[19]==2 && pBt->doNotUseWAL==0 ){
+ int isOpen = 0;
+ rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen);
+ if( rc!=SQLITE_OK ){
+ goto page1_init_failed;
+ }else if( isOpen==0 ){
+ releasePage(pPage1);
+ return SQLITE_OK;
+ }
+ rc = SQLITE_NOTADB;
+ }
+#endif
/* The maximum embedded fraction must be exactly 25%. And the minimum
** embedded fraction must be 12.5% for both leaf-data and non-leaf-data.
@@ -40834,15 +50623,16 @@ static int lockBtree(BtShared *pBt){
if( memcmp(&page1[21], "\100\040\040",3)!=0 ){
goto page1_init_failed;
}
- pageSize = get2byte(&page1[16]);
- if( ((pageSize-1)&pageSize)!=0 || pageSize<512 ||
- (SQLITE_MAX_PAGE_SIZE<32768 && pageSize>SQLITE_MAX_PAGE_SIZE)
+ pageSize = (page1[16]<<8) | (page1[17]<<16);
+ if( ((pageSize-1)&pageSize)!=0
+ || pageSize>SQLITE_MAX_PAGE_SIZE
+ || pageSize<=256
){
goto page1_init_failed;
}
assert( (pageSize & 7)==0 );
usableSize = pageSize - page1[20];
- if( pageSize!=pBt->pageSize ){
+ if( (u32)pageSize!=pBt->pageSize ){
/* After reading the first page of the database assuming a page size
** of BtShared.pageSize, we have discovered that the page-size is
** actually pageSize. Unlock the database, leave pBt->pPage1 at
@@ -40850,18 +50640,22 @@ static int lockBtree(BtShared *pBt){
** again with the correct page-size.
*/
releasePage(pPage1);
- pBt->usableSize = (u16)usableSize;
- pBt->pageSize = (u16)pageSize;
+ pBt->usableSize = usableSize;
+ pBt->pageSize = pageSize;
freeTempSpace(pBt);
rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize,
pageSize-usableSize);
return rc;
}
+ if( (pBt->db->flags & SQLITE_RecoveryMode)==0 && nPage>nPageFile ){
+ rc = SQLITE_CORRUPT_BKPT;
+ goto page1_init_failed;
+ }
if( usableSize<480 ){
goto page1_init_failed;
}
- pBt->pageSize = (u16)pageSize;
- pBt->usableSize = (u16)usableSize;
+ pBt->pageSize = pageSize;
+ pBt->usableSize = usableSize;
#ifndef SQLITE_OMIT_AUTOVACUUM
pBt->autoVacuum = (get4byte(&page1[36 + 4*4])?1:0);
pBt->incrVacuum = (get4byte(&page1[36 + 7*4])?1:0);
@@ -40877,16 +50671,17 @@ static int lockBtree(BtShared *pBt){
** 9-byte nKey value
** 4-byte nData value
** 4-byte overflow page pointer
- ** So a cell consists of a 2-byte poiner, a header which is as much as
+ ** So a cell consists of a 2-byte pointer, a header which is as much as
** 17 bytes long, 0 to N bytes of payload, and an optional 4 byte overflow
** page pointer.
*/
- pBt->maxLocal = (pBt->usableSize-12)*64/255 - 23;
- pBt->minLocal = (pBt->usableSize-12)*32/255 - 23;
- pBt->maxLeaf = pBt->usableSize - 35;
- pBt->minLeaf = (pBt->usableSize-12)*32/255 - 23;
+ pBt->maxLocal = (u16)((pBt->usableSize-12)*64/255 - 23);
+ pBt->minLocal = (u16)((pBt->usableSize-12)*32/255 - 23);
+ pBt->maxLeaf = (u16)(pBt->usableSize - 35);
+ pBt->minLeaf = (u16)((pBt->usableSize-12)*32/255 - 23);
assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) );
pBt->pPage1 = pPage1;
+ pBt->nPage = nPage;
return SQLITE_OK;
page1_init_failed:
@@ -40898,7 +50693,7 @@ page1_init_failed:
/*
** 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
-** this routine unrefs the first page of the database file which
+** this routine unrefs the first page of the database file which
** has the effect of releasing the read lock.
**
** If there is a transaction in progress, this routine is a no-op.
@@ -40924,12 +50719,10 @@ static int newDatabase(BtShared *pBt){
MemPage *pP1;
unsigned char *data;
int rc;
- int nPage;
assert( sqlite3_mutex_held(pBt->mutex) );
- rc = sqlite3PagerPagecount(pBt->pPager, &nPage);
- if( rc!=SQLITE_OK || nPage>0 ){
- return rc;
+ if( pBt->nPage>0 ){
+ return SQLITE_OK;
}
pP1 = pBt->pPage1;
assert( pP1!=0 );
@@ -40938,7 +50731,8 @@ static int newDatabase(BtShared *pBt){
if( rc ) return rc;
memcpy(data, zMagicHeader, sizeof(zMagicHeader));
assert( sizeof(zMagicHeader)==16 );
- put2byte(&data[16], pBt->pageSize);
+ data[16] = (u8)((pBt->pageSize>>8)&0xff);
+ data[17] = (u8)((pBt->pageSize>>16)&0xff);
data[18] = 1;
data[19] = 1;
assert( pBt->usableSize<=pBt->pageSize && pBt->usableSize+255>=pBt->pageSize);
@@ -40955,6 +50749,8 @@ static int newDatabase(BtShared *pBt){
put4byte(&data[36 + 4*4], pBt->autoVacuum);
put4byte(&data[36 + 7*4], pBt->incrVacuum);
#endif
+ pBt->nPage = 1;
+ data[31] = 1;
return SQLITE_OK;
}
@@ -40967,8 +50763,8 @@ static int newDatabase(BtShared *pBt){
** upgraded to exclusive by calling this routine a second time - the
** exclusivity flag only works for a new transaction.
**
-** A write-transaction must be started before attempting any
-** changes to the database. None of the following routines
+** A write-transaction must be started before attempting any
+** changes to the database. None of the following routines
** will work unless a transaction is started first:
**
** sqlite3BtreeCreateTable()
@@ -40982,7 +50778,7 @@ static int newDatabase(BtShared *pBt){
** If an initial attempt to acquire the lock fails because of lock contention
** and the database was previously unlocked, then invoke the busy handler
** if there is one. But if there was previously a read-lock, do not
-** invoke the busy handler - just return SQLITE_BUSY. SQLITE_BUSY is
+** invoke the busy handler - just return SQLITE_BUSY. SQLITE_BUSY is
** returned when there is already a read-lock in order to avoid a deadlock.
**
** Suppose there are two processes A and B. A has a read lock and B has
@@ -41016,7 +50812,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
}
#ifndef SQLITE_OMIT_SHARED_CACHE
- /* If another database handle has already opened a write transaction
+ /* If another database handle has already opened a write transaction
** on this shared-btree structure and a second write transaction is
** requested, return SQLITE_LOCKED.
*/
@@ -41038,17 +50834,18 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
}
#endif
- /* Any read-only or read-write transaction implies a read-lock on
- ** page 1. So if some other shared-cache client already has a write-lock
+ /* Any read-only or read-write transaction implies a read-lock on
+ ** page 1. So if some other shared-cache client already has a write-lock
** on page 1, the transaction cannot be opened. */
rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK);
if( SQLITE_OK!=rc ) goto trans_begun;
+ pBt->initiallyEmpty = (u8)(pBt->nPage==0);
do {
/* Call lockBtree() until either pBt->pPage1 is populated or
** lockBtree() returns something other than SQLITE_OK. lockBtree()
** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after
- ** reading page 1 it discovers that the page-size of the database
+ ** reading page 1 it discovers that the page-size of the database
** file is not pBt->pageSize. In this case lockBtree() will update
** pBt->pageSize to the page-size of the file on disk.
*/
@@ -41064,11 +50861,11 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
}
}
}
-
+
if( rc!=SQLITE_OK ){
unlockBtreeIfUnused(pBt);
}
- }while( rc==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
+ }while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
btreeInvokeBusyHandler(pBt) );
if( rc==SQLITE_OK ){
@@ -41087,13 +50884,27 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
if( p->inTrans>pBt->inTransaction ){
pBt->inTransaction = p->inTrans;
}
-#ifndef SQLITE_OMIT_SHARED_CACHE
if( wrflag ){
+ MemPage *pPage1 = pBt->pPage1;
+#ifndef SQLITE_OMIT_SHARED_CACHE
assert( !pBt->pWriter );
pBt->pWriter = p;
pBt->isExclusive = (u8)(wrflag>1);
- }
#endif
+
+ /* If the db-size header field is incorrect (as it may be if an old
+ ** client has been writing the database file), update it now. Doing
+ ** this sooner rather than later means the database size can safely
+ ** re-read the database size from page 1 if a savepoint or transaction
+ ** rollback occurs within the transaction.
+ */
+ if( pBt->nPage!=get4byte(&pPage1->aData[28]) ){
+ rc = sqlite3PagerWrite(pPage1->pDbPage);
+ if( rc==SQLITE_OK ){
+ put4byte(&pPage1->aData[28], pBt->nPage);
+ }
+ }
+ }
}
@@ -41159,7 +50970,7 @@ set_child_ptrmaps_out:
** that it points to iTo. Parameter eType describes the type of pointer to
** be modified, as follows:
**
-** PTRMAP_BTREE: pPage is a btree-page. The pointer points at a child
+** PTRMAP_BTREE: pPage is a btree-page. The pointer points at a child
** page of pPage.
**
** PTRMAP_OVERFLOW1: pPage is a btree-page. The pointer points at an overflow
@@ -41190,11 +51001,12 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
if( eType==PTRMAP_OVERFLOW1 ){
CellInfo info;
btreeParseCellPtr(pPage, pCell, &info);
- if( info.iOverflow ){
- if( iFrom==get4byte(&pCell[info.iOverflow]) ){
- put4byte(&pCell[info.iOverflow], iTo);
- break;
- }
+ if( info.iOverflow
+ && pCell+info.iOverflow+3<=pPage->aData+pPage->maskPage
+ && iFrom==get4byte(&pCell[info.iOverflow])
+ ){
+ put4byte(&pCell[info.iOverflow], iTo);
+ break;
}
}else{
if( get4byte(pCell)==iFrom ){
@@ -41203,9 +51015,9 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
}
}
}
-
+
if( i==nCell ){
- if( eType!=PTRMAP_BTREE ||
+ if( eType!=PTRMAP_BTREE ||
get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){
return SQLITE_CORRUPT_BKPT;
}
@@ -41219,11 +51031,11 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
/*
-** Move the open database page pDbPage to location iFreePage in the
+** Move the open database page pDbPage to location iFreePage in the
** database. The pDbPage reference remains valid.
**
** The isCommit flag indicates that there is no need to remember that
-** the journal needs to be sync()ed before database page pDbPage->pgno
+** the journal needs to be sync()ed before database page pDbPage->pgno
** can be written to. The caller has already promised not to write to that
** page.
*/
@@ -41240,13 +51052,13 @@ static int relocatePage(
Pager *pPager = pBt->pPager;
int rc;
- assert( eType==PTRMAP_OVERFLOW2 || eType==PTRMAP_OVERFLOW1 ||
+ assert( eType==PTRMAP_OVERFLOW2 || eType==PTRMAP_OVERFLOW1 ||
eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE );
assert( sqlite3_mutex_held(pBt->mutex) );
assert( pDbPage->pBt==pBt );
/* Move page iDbPage from its current location to page number iFreePage */
- TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n",
+ TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n",
iDbPage, iFreePage, iPtrPage, eType));
rc = sqlite3PagerMovepage(pPager, pDbPage->pDbPage, iFreePage, isCommit);
if( rc!=SQLITE_OK ){
@@ -41308,14 +51120,14 @@ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
** return SQLITE_OK. If there is no work to do (and therefore no
** point in calling this function again), return SQLITE_DONE.
**
-** More specificly, this function attempts to re-organize the
+** 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.
**
** 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
+** 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
@@ -41323,12 +51135,12 @@ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
*/
static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
Pgno nFreeList; /* Number of pages still on the free-list */
+ int rc;
assert( sqlite3_mutex_held(pBt->mutex) );
assert( iLastPg>nFin );
if( !PTRMAP_ISPAGE(pBt, iLastPg) && iLastPg!=PENDING_BYTE_PAGE(pBt) ){
- int rc;
u8 eType;
Pgno iPtrPage;
@@ -41349,7 +51161,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
if( nFin==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
- ** truncated to zero after this function returns, so it doesn't
+ ** truncated to zero after this function returns, so it doesn't
** matter if it still contains some garbage entries.
*/
Pgno iFreePg;
@@ -41387,7 +51199,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
releasePage(pFreePg);
}while( nFin!=0 && iFreePg>nFin );
assert( iFreePgpDbPage);
if( rc==SQLITE_OK ){
rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg, nFin!=0);
@@ -41404,7 +51216,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
while( iLastPg==PENDING_BYTE_PAGE(pBt)||PTRMAP_ISPAGE(pBt, iLastPg) ){
if( PTRMAP_ISPAGE(pBt, iLastPg) ){
MemPage *pPg;
- int rc = btreeGetPage(pBt, iLastPg, &pPg, 0);
+ rc = btreeGetPage(pBt, iLastPg, &pPg, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -41417,6 +51229,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
iLastPg--;
}
sqlite3PagerTruncateImage(pBt->pPager, iLastPg);
+ pBt->nPage = iLastPg;
}
return SQLITE_OK;
}
@@ -41427,7 +51240,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
**
** If the incremental vacuum is finished after this function has run,
** SQLITE_DONE is returned. If it is not finished, but no error occurred,
-** SQLITE_OK is returned. Otherwise an SQLite error code.
+** SQLITE_OK is returned. Otherwise an SQLite error code.
*/
SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){
int rc;
@@ -41439,7 +51252,11 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){
rc = SQLITE_DONE;
}else{
invalidateAllOverflowCache(pBt);
- rc = incrVacuumStep(pBt, 0, pagerPagecount(pBt));
+ rc = incrVacuumStep(pBt, 0, btreePagecount(pBt));
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
+ put4byte(&pBt->pPage1->aData[28], pBt->nPage);
+ }
}
sqlite3BtreeLeave(p);
return rc;
@@ -41450,7 +51267,7 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){
** is commited for an auto-vacuum database.
**
** If SQLITE_OK is returned, then *pnTrunc is set to the number of pages
-** the database file should be truncated to during the commit process.
+** the database file should be truncated to during the commit process.
** i.e. the database has been reorganized so that only the first *pnTrunc
** pages are in use.
*/
@@ -41470,7 +51287,7 @@ static int autoVacuumCommit(BtShared *pBt){
int nEntry; /* Number of entries on one ptrmap page */
Pgno nOrig; /* Database size before freeing */
- nOrig = pagerPagecount(pBt);
+ nOrig = btreePagecount(pBt);
if( PTRMAP_ISPAGE(pBt, nOrig) || nOrig==PENDING_BYTE_PAGE(pBt) ){
/* It is not possible to create a database for which the final page
** is either a pointer-map page or the pending-byte page. If one
@@ -41495,11 +51312,12 @@ static int autoVacuumCommit(BtShared *pBt){
rc = incrVacuumStep(pBt, nFin, iFree);
}
if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){
- rc = SQLITE_OK;
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->nPage = nFin;
}
if( rc!=SQLITE_OK ){
sqlite3PagerRollback(pPager);
@@ -41531,7 +51349,7 @@ static int autoVacuumCommit(BtShared *pBt){
**
** Otherwise, sync the database file for the btree pBt. zMaster points to
** the name of a master journal file that should be written into the
-** individual journal file, or is NULL, indicating no master journal file
+** individual journal file, or is NULL, indicating no master journal file
** (single database transaction).
**
** When this is called, the master journal should already have been
@@ -41576,8 +51394,8 @@ static void btreeEndTransaction(Btree *p){
downgradeAllSharedCacheTableLocks(p);
p->inTrans = TRANS_READ;
}else{
- /* If the handle had any kind of transaction open, decrement the
- ** transaction count of the shared btree. If the transaction count
+ /* If the handle had any kind of transaction open, decrement the
+ ** transaction count of the shared btree. If the transaction count
** reaches 0, set the shared state to TRANS_NONE. The unlockBtreeIfUnused()
** call below will unlock the pager. */
if( p->inTrans!=TRANS_NONE ){
@@ -41588,7 +51406,7 @@ static void btreeEndTransaction(Btree *p){
}
}
- /* Set the current transaction state to TRANS_NONE and unlock the
+ /* Set the current transaction state to TRANS_NONE and unlock the
** pager if this call closed the only read or write transaction. */
p->inTrans = TRANS_NONE;
unlockBtreeIfUnused(pBt);
@@ -41609,24 +51427,36 @@ static void btreeEndTransaction(Btree *p){
** the rollback journal (which causes the transaction to commit) and
** drop locks.
**
+** Normally, if an error occurs while the pager layer is attempting to
+** finalize the underlying journal file, this function returns an error and
+** the upper layer will attempt a rollback. However, if the second argument
+** is non-zero then this b-tree transaction is part of a multi-file
+** transaction. In this case, the transaction has already been committed
+** (by deleting a master journal file) and the caller will ignore this
+** functions return code. So, even if an error occurs in the pager layer,
+** reset the b-tree objects internal state to indicate that the write
+** transaction has been closed. This is quite safe, as the pager will have
+** transitioned to the error state.
+**
** This will release the write lock on the database file. If there
** are no active cursors, it also releases the read lock.
*/
-SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p){
- BtShared *pBt = p->pBt;
+SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){
+ if( p->inTrans==TRANS_NONE ) return SQLITE_OK;
sqlite3BtreeEnter(p);
btreeIntegrity(p);
- /* If the handle has a write-transaction open, commit the shared-btrees
+ /* If the handle has a write-transaction open, commit the shared-btrees
** transaction and set the shared state to TRANS_READ.
*/
if( p->inTrans==TRANS_WRITE ){
int rc;
+ BtShared *pBt = p->pBt;
assert( pBt->inTransaction==TRANS_WRITE );
assert( pBt->nTransaction>0 );
rc = sqlite3PagerCommitPhaseTwo(pBt->pPager);
- if( rc!=SQLITE_OK ){
+ if( rc!=SQLITE_OK && bCleanup==0 ){
sqlite3BtreeLeave(p);
return rc;
}
@@ -41646,7 +51476,7 @@ SQLITE_PRIVATE int sqlite3BtreeCommit(Btree *p){
sqlite3BtreeEnter(p);
rc = sqlite3BtreeCommitPhaseOne(p, 0);
if( rc==SQLITE_OK ){
- rc = sqlite3BtreeCommitPhaseTwo(p);
+ rc = sqlite3BtreeCommitPhaseTwo(p, 0);
}
sqlite3BtreeLeave(p);
return rc;
@@ -41667,7 +51497,7 @@ 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++;
+ if( pCur->wrFlag && pCur->eState!=CURSOR_FAULT ) r++;
}
return r;
}
@@ -41726,9 +51556,9 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p){
if( rc!=SQLITE_OK ){
/* This is a horrible situation. An IO or malloc() error occurred whilst
** trying to save cursor positions. If this is an automatic rollback (as
- ** the result of a constraint, malloc() failure or IO error) then
+ ** the result of a constraint, malloc() failure or IO error) then
** the cache may be internally inconsistent (not contain valid trees) so
- ** we cannot simply return the error to the caller. Instead, abort
+ ** we cannot simply return the error to the caller. Instead, abort
** all queries that may be using any of the cursors that failed to save.
*/
sqlite3BtreeTripAllCursors(p, rc);
@@ -41749,6 +51579,11 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p){
** call btreeGetPage() on page 1 again to make
** sure pPage1->aData is set correctly. */
if( btreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){
+ int nPage = get4byte(28+(u8*)pPage1->aData);
+ testcase( nPage==0 );
+ if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
+ testcase( pBt->nPage!=nPage );
+ pBt->nPage = nPage;
releasePage(pPage1);
}
assert( countWriteCursors(pBt)==0 );
@@ -41762,8 +51597,8 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p){
/*
** Start a statement subtransaction. The subtransaction can can be rolled
-** back independently of the main transaction. You must start a transaction
-** before starting a subtransaction. The subtransaction is ended automatically
+** back independently of the main transaction. You must start a transaction
+** before starting a subtransaction. The subtransaction is ended automatically
** if the main transaction commits or rolls back.
**
** Statement subtransactions are used around individual SQL statements
@@ -41786,17 +51621,13 @@ SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree *p, int iStatement){
assert( pBt->readOnly==0 );
assert( iStatement>0 );
assert( iStatement>p->db->nSavepoint );
- if( NEVER(p->inTrans!=TRANS_WRITE || pBt->readOnly) ){
- rc = SQLITE_INTERNAL;
- }else{
- assert( pBt->inTransaction==TRANS_WRITE );
- /* At the pager level, a statement transaction is a savepoint with
- ** an index greater than all savepoints created explicitly using
- ** SQL statements. It is illegal to open, release or rollback any
- ** such savepoints while the statement transaction savepoint is active.
- */
- rc = sqlite3PagerOpenSavepoint(pBt->pPager, iStatement);
- }
+ assert( pBt->inTransaction==TRANS_WRITE );
+ /* At the pager level, a statement transaction is a savepoint with
+ ** an index greater than all savepoints created explicitly using
+ ** SQL statements. It is illegal to open, release or rollback any
+ ** such savepoints while the statement transaction savepoint is active.
+ */
+ rc = sqlite3PagerOpenSavepoint(pBt->pPager, iStatement);
sqlite3BtreeLeave(p);
return rc;
}
@@ -41804,11 +51635,11 @@ SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree *p, int iStatement){
/*
** The second argument to this function, op, is always SAVEPOINT_ROLLBACK
** or SAVEPOINT_RELEASE. This function either releases or rolls back the
-** savepoint identified by parameter iSavepoint, depending on the value
+** savepoint identified by parameter iSavepoint, depending on the value
** of op.
**
** Normally, iSavepoint is greater than or equal to zero. However, if op is
-** SAVEPOINT_ROLLBACK, then iSavepoint may also be -1. In this case the
+** SAVEPOINT_ROLLBACK, then iSavepoint may also be -1. In this case the
** contents of the entire transaction are rolled back. This is different
** from a normal transaction rollback, as no locks are released and the
** transaction remains open.
@@ -41822,7 +51653,14 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
sqlite3BtreeEnter(p);
rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint);
if( rc==SQLITE_OK ){
+ if( iSavepoint<0 && pBt->initiallyEmpty ) pBt->nPage = 0;
rc = newDatabase(pBt);
+ pBt->nPage = get4byte(28 + pBt->pPage1->aData);
+
+ /* The database size was written into the offset 28 of the header
+ ** when the transaction started, so we know that the value at offset
+ ** 28 is nonzero. */
+ assert( pBt->nPage>0 );
}
sqlite3BtreeLeave(p);
}
@@ -41873,9 +51711,9 @@ static int btreeCursor(
assert( sqlite3BtreeHoldsMutex(p) );
assert( wrFlag==0 || wrFlag==1 );
- /* The following assert statements verify that if this is a sharable
- ** b-tree database, the connection is holding the required table locks,
- ** and that no other connection has any open cursor that conflicts with
+ /* The following assert statements verify that if this is a sharable
+ ** b-tree database, the connection is holding the required table locks,
+ ** and that no other connection has any open cursor that conflicts with
** this lock. */
assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, wrFlag+1) );
assert( wrFlag==0 || !hasReadConflicts(p, iTable) );
@@ -41888,8 +51726,9 @@ static int btreeCursor(
if( NEVER(wrFlag && pBt->readOnly) ){
return SQLITE_READONLY;
}
- if( iTable==1 && pagerPagecount(pBt)==0 ){
- return SQLITE_EMPTY;
+ if( iTable==1 && btreePagecount(pBt)==0 ){
+ assert( wrFlag==0 );
+ iTable = 0;
}
/* Now that no other errors can occur, finish filling in the BtCursor
@@ -42070,14 +51909,14 @@ SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor *pCur){
/*
** Set *pSize to the size of the buffer needed to hold the value of
** the key for the current entry. If the cursor is not pointing
-** to a valid entry, *pSize is set to 0.
+** to a valid entry, *pSize is set to 0.
**
** For a table with the INTKEY flag set, this routine returns the key
** itself, not the number of bytes in the key.
**
** The caller must position the cursor prior to invoking this routine.
-**
-** This routine cannot fail. It always returns SQLITE_OK.
+**
+** This routine cannot fail. It always returns SQLITE_OK.
*/
SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
assert( cursorHoldsMutex(pCur) );
@@ -42113,15 +51952,15 @@ SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
/*
** Given the page number of an overflow page in the database (parameter
-** ovfl), this function finds the page number of the next page in the
+** ovfl), this function finds the page number of the next page in the
** linked list of overflow pages. If possible, it uses the auto-vacuum
-** pointer-map data instead of reading the content of page ovfl to do so.
+** pointer-map data instead of reading the content of page ovfl to do so.
**
** If an error occurs an SQLite error code is returned. Otherwise:
**
-** The page number of the next overflow page in the linked list is
-** written to *pPgnoNext. If page ovfl is the last page in its linked
-** list, *pPgnoNext is set to zero.
+** The page number of the next overflow page in the linked list is
+** written to *pPgnoNext. If page ovfl is the last page in its linked
+** list, *pPgnoNext is set to zero.
**
** If ppPage is not NULL, and a reference to the MemPage object corresponding
** to page number pOvfl was obtained, then *ppPage is set to point to that
@@ -42145,9 +51984,9 @@ static int getOverflowPage(
#ifndef SQLITE_OMIT_AUTOVACUUM
/* Try to find the next page in the overflow list using the
- ** autovacuum pointer-map pages. Guess that the next page in
- ** the overflow list is page number (ovfl+1). If that guess turns
- ** out to be wrong, fall back to loading the data of page
+ ** autovacuum pointer-map pages. Guess that the next page in
+ ** the overflow list is page number (ovfl+1). If that guess turns
+ ** out to be wrong, fall back to loading the data of page
** number ovfl to determine the next page number.
*/
if( pBt->autoVacuum ){
@@ -42159,7 +51998,7 @@ static int getOverflowPage(
iGuess++;
}
- if( iGuess<=pagerPagecount(pBt) ){
+ if( iGuess<=btreePagecount(pBt) ){
rc = ptrmapGet(pBt, iGuess, &eType, &pgno);
if( rc==SQLITE_OK && eType==PTRMAP_OVERFLOW2 && pgno==ovfl ){
next = iGuess;
@@ -42234,7 +52073,7 @@ static int copyPayload(
**
** If the BtCursor.isIncrblobHandle flag is set, and the current
** cursor entry uses one or more overflow pages, this function
-** allocates space for and lazily popluates the overflow page-list
+** allocates space for and lazily popluates the overflow page-list
** cache array (BtCursor.aOverflow). Subsequent calls use this
** cache to make seeking to the supplied offset more efficient.
**
@@ -42251,7 +52090,7 @@ static int accessPayload(
BtCursor *pCur, /* Cursor pointing to entry to read from */
u32 offset, /* Begin reading this far into payload */
u32 amt, /* Read this many bytes */
- unsigned char *pBuf, /* Write the bytes into this buffer */
+ unsigned char *pBuf, /* Write the bytes into this buffer */
int eOp /* zero to read. non-zero to write. */
){
unsigned char *aPayload;
@@ -42270,7 +52109,7 @@ static int accessPayload(
aPayload = pCur->info.pCell + pCur->info.nHeader;
nKey = (pPage->intKey ? 0 : (int)pCur->info.nKey);
- if( NEVER(offset+amt > nKey+pCur->info.nData)
+ if( NEVER(offset+amt > nKey+pCur->info.nData)
|| &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
){
/* Trying to read or write past the end of the data is an error */
@@ -42346,7 +52185,7 @@ static int accessPayload(
#ifndef SQLITE_OMIT_INCRBLOB
if( pCur->aOverflow && pCur->aOverflow[iIdx+1] ){
nextPage = pCur->aOverflow[iIdx+1];
- } else
+ } else
#endif
rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
offset -= ovflSize;
@@ -42429,7 +52268,7 @@ SQLITE_PRIVATE int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *p
}
/*
-** Return a pointer to payload information from the entry that the
+** Return a pointer to payload information from the entry that the
** pCur cursor is pointing to. The pointer is to the beginning of
** the key if skipKey==0 and it points to the beginning of data if
** skipKey==1. The number of bytes of available key/data is written
@@ -42556,7 +52395,7 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
#ifndef NDEBUG
/*
-** Page pParent is an internal (non-leaf) tree page. This function
+** Page pParent is an internal (non-leaf) tree page. This function
** asserts that page number iChild is the left-child if the iIdx'th
** cell in page pParent. Or, if iIdx is equal to the total number of
** cells in pParent, that page number iChild is the right-child of
@@ -42571,7 +52410,7 @@ static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){
}
}
#else
-# define assertParentIndex(x,y,z)
+# define assertParentIndex(x,y,z)
#endif
/*
@@ -42588,8 +52427,8 @@ static void moveToParent(BtCursor *pCur){
assert( pCur->iPage>0 );
assert( pCur->apPage[pCur->iPage] );
assertParentIndex(
- pCur->apPage[pCur->iPage-1],
- pCur->aiIdx[pCur->iPage-1],
+ pCur->apPage[pCur->iPage-1],
+ pCur->aiIdx[pCur->iPage-1],
pCur->apPage[pCur->iPage]->pgno
);
releasePage(pCur->apPage[pCur->iPage]);
@@ -42603,19 +52442,19 @@ static void moveToParent(BtCursor *pCur){
**
** If the table has a virtual root page, then the cursor is moved to point
** to the virtual root page instead of the actual root page. A table has a
-** virtual root page when the actual root page contains no cells and a
+** virtual root page when the actual root page contains no cells and a
** single child page. This can only happen with the table rooted at page 1.
**
-** If the b-tree structure is empty, the cursor state is set to
+** If the b-tree structure is empty, the cursor state is set to
** CURSOR_INVALID. Otherwise, the cursor is set to point to the first
** cell located on the root (or virtual root) page and the cursor state
** is set to CURSOR_VALID.
**
** If this function returns successfully, it may be assumed that the
-** page-header flags indicate that the [virtual] root-page is the expected
+** page-header flags indicate that the [virtual] root-page is the expected
** kind of b-tree page (i.e. if when opening the cursor the caller did not
** specify a KeyInfo structure the flags byte is set to 0x05 or 0x0D,
-** indicating a table b-tree, or if the caller did specify a KeyInfo
+** indicating a table b-tree, or if the caller did specify a KeyInfo
** structure the flags byte is set to 0x02 or 0x0A, indicating an index
** b-tree).
*/
@@ -42643,6 +52482,9 @@ static int moveToRoot(BtCursor *pCur){
releasePage(pCur->apPage[i]);
}
pCur->iPage = 0;
+ }else if( pCur->pgnoRoot==0 ){
+ pCur->eState = CURSOR_INVALID;
+ return SQLITE_OK;
}else{
rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0]);
if( rc!=SQLITE_OK ){
@@ -42663,8 +52505,8 @@ static int moveToRoot(BtCursor *pCur){
/* Assert that the root page is of the correct type. This must be the
** case as the call to this function that loaded the root-page (either
- ** this call or a previous invocation) would have detected corruption
- ** if the assumption were not true, and it is not possible for the flags
+ ** this call or a previous invocation) would have detected corruption
+ ** if the assumption were not true, and it is not possible for the flags
** byte to have been modified while this cursor is holding a reference
** to the page. */
pRoot = pCur->apPage[0];
@@ -42752,9 +52594,8 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
rc = moveToRoot(pCur);
if( rc==SQLITE_OK ){
if( pCur->eState==CURSOR_INVALID ){
- assert( pCur->apPage[pCur->iPage]->nCell==0 );
+ assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
*pRes = 1;
- rc = SQLITE_OK;
}else{
assert( pCur->apPage[pCur->iPage]->nCell>0 );
*pRes = 0;
@@ -42770,14 +52611,14 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
*/
SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
int rc;
-
+
assert( cursorHoldsMutex(pCur) );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
/* If the cursor already points to the last entry, this is a no-op. */
if( CURSOR_VALID==pCur->eState && pCur->atLast ){
#ifdef SQLITE_DEBUG
- /* This block serves to assert() that the cursor really does point
+ /* This block serves to assert() that the cursor really does point
** to the last entry in the b-tree. */
int ii;
for(ii=0; iiiPage; ii++){
@@ -42792,7 +52633,7 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
rc = moveToRoot(pCur);
if( rc==SQLITE_OK ){
if( CURSOR_INVALID==pCur->eState ){
- assert( pCur->apPage[pCur->iPage]->nCell==0 );
+ assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
*pRes = 1;
}else{
assert( pCur->eState==CURSOR_VALID );
@@ -42804,10 +52645,10 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
return rc;
}
-/* Move the cursor so that it points to an entry near the key
+/* Move the cursor so that it points to an entry near the key
** specified by pIdxKey or intKey. Return a success code.
**
-** For INTKEY tables, the intKey parameter is used. pIdxKey
+** For INTKEY tables, the intKey parameter is used. pIdxKey
** must be NULL. For index tables, pIdxKey is used and intKey
** is ignored.
**
@@ -42817,7 +52658,7 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
** before or after the key.
**
** An integer is written into *pRes which is the result of
-** comparing the key with the entry to which the cursor is
+** comparing the key with the entry to which the cursor is
** pointing. The meaning of the integer written into
** *pRes is as follows:
**
@@ -42848,8 +52689,8 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
/* If the cursor is already positioned at the point we are trying
** to move to, then just return without doing any work */
- if( pCur->eState==CURSOR_VALID && pCur->validNKey
- && pCur->apPage[0]->intKey
+ if( pCur->eState==CURSOR_VALID && pCur->validNKey
+ && pCur->apPage[0]->intKey
){
if( pCur->info.nKey==intKey ){
*pRes = 0;
@@ -42865,17 +52706,17 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
if( rc ){
return rc;
}
- assert( pCur->apPage[pCur->iPage] );
- assert( pCur->apPage[pCur->iPage]->isInit );
- assert( pCur->apPage[pCur->iPage]->nCell>0 || pCur->eState==CURSOR_INVALID );
+ assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage] );
+ assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->isInit );
+ assert( pCur->eState==CURSOR_INVALID || pCur->apPage[pCur->iPage]->nCell>0 );
if( pCur->eState==CURSOR_INVALID ){
*pRes = -1;
- assert( pCur->apPage[pCur->iPage]->nCell==0 );
+ assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
return SQLITE_OK;
}
assert( pCur->apPage[0]->intKey || pIdxKey );
for(;;){
- int lwr, upr;
+ int lwr, upr, idx;
Pgno chldPg;
MemPage *pPage = pCur->apPage[pCur->iPage];
int c;
@@ -42891,14 +52732,14 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
lwr = 0;
upr = pPage->nCell-1;
if( biasRight ){
- pCur->aiIdx[pCur->iPage] = (u16)upr;
+ pCur->aiIdx[pCur->iPage] = (u16)(idx = upr);
}else{
- pCur->aiIdx[pCur->iPage] = (u16)((upr+lwr)/2);
+ pCur->aiIdx[pCur->iPage] = (u16)(idx = (upr+lwr)/2);
}
for(;;){
- int idx = pCur->aiIdx[pCur->iPage]; /* Index of current cell in pPage */
u8 *pCell; /* Pointer to current cell in pPage */
+ assert( idx==pCur->aiIdx[pCur->iPage] );
pCur->info.nSize = 0;
pCell = findCell(pPage, idx) + pPage->childPtrSize;
if( pPage->intKey ){
@@ -42919,12 +52760,12 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
pCur->validNKey = 1;
pCur->info.nKey = nCellKey;
}else{
- /* The maximum supported page-size is 32768 bytes. This means that
+ /* The maximum supported page-size is 65536 bytes. This means that
** the maximum number of record bytes stored on an index B-Tree
- ** page is at most 8198 bytes, which may be stored as a 2-byte
- ** varint. This information is used to attempt to avoid parsing
- ** the entire cell by checking for the cases where the record is
- ** stored entirely within the b-tree page by inspecting the first
+ ** page is less than 16384 bytes and may be stored as a 2-byte
+ ** varint. This information is used to attempt to avoid parsing
+ ** the entire cell by checking for the cases where the record is
+ ** stored entirely within the b-tree page by inspecting the first
** 2 bytes of the cell.
*/
int nCell = pCell[0];
@@ -42933,10 +52774,10 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
** single byte varint and the record fits entirely on the main
** b-tree page. */
c = sqlite3VdbeRecordCompare(nCell, (void*)&pCell[1], pIdxKey);
- }else if( !(pCell[1] & 0x80)
+ }else if( !(pCell[1] & 0x80)
&& (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal
){
- /* The record-size field is a 2 byte varint and the record
+ /* The record-size field is a 2 byte varint and the record
** fits entirely on the main b-tree page. */
c = sqlite3VdbeRecordCompare(nCell, (void*)&pCell[2], pIdxKey);
}else{
@@ -42981,7 +52822,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
if( lwr>upr ){
break;
}
- pCur->aiIdx[pCur->iPage] = (u16)((lwr+upr)/2);
+ pCur->aiIdx[pCur->iPage] = (u16)(idx = (lwr+upr)/2);
}
assert( lwr==upr+1 );
assert( pPage->isInit );
@@ -43165,19 +53006,19 @@ 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 a (feeble) 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
+** 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.
*/
static int allocateBtreePage(
- BtShared *pBt,
- MemPage **ppPage,
- Pgno *pPgno,
+ BtShared *pBt,
+ MemPage **ppPage,
+ Pgno *pPgno,
Pgno nearby,
u8 exact
){
@@ -43191,7 +53032,7 @@ static int allocateBtreePage(
assert( sqlite3_mutex_held(pBt->mutex) );
pPage1 = pBt->pPage1;
- mxPage = pagerPagecount(pBt);
+ mxPage = btreePagecount(pBt);
n = get4byte(&pPage1->aData[36]);
testcase( n==mxPage-1 );
if( n>=mxPage ){
@@ -43201,7 +53042,7 @@ static int allocateBtreePage(
/* There are pages on the freelist. Reuse one of those pages. */
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
** shows that the page 'nearby' is somewhere on the free-list, then
** the entire-list will be searched for that page.
@@ -43249,10 +53090,10 @@ static int allocateBtreePage(
goto end_allocate_page;
}
- k = get4byte(&pTrunk->aData[4]);
+ k = get4byte(&pTrunk->aData[4]); /* # of leaves on this trunk page */
if( k==0 && !searchList ){
- /* The trunk has no leaves and the list is not being searched.
- ** So extract the trunk page itself and use it as the newly
+ /* The trunk has no leaves and the list is not being searched.
+ ** So extract the trunk page itself and use it as the newly
** allocated page */
assert( pPrevTrunk==0 );
rc = sqlite3PagerWrite(pTrunk->pDbPage);
@@ -43284,16 +53125,20 @@ static int allocateBtreePage(
if( !pPrevTrunk ){
memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4);
}else{
+ rc = sqlite3PagerWrite(pPrevTrunk->pDbPage);
+ if( rc!=SQLITE_OK ){
+ goto end_allocate_page;
+ }
memcpy(&pPrevTrunk->aData[0], &pTrunk->aData[0], 4);
}
}else{
- /* The trunk page is required by the caller but it contains
+ /* The trunk page is required by the caller but it contains
** pointers to free-list leaves. The first leaf becomes a trunk
** page in this case.
*/
MemPage *pNewTrunk;
Pgno iNewTrunk = get4byte(&pTrunk->aData[8]);
- if( iNewTrunk>mxPage ){
+ if( iNewTrunk>mxPage ){
rc = SQLITE_CORRUPT_BKPT;
goto end_allocate_page;
}
@@ -43330,19 +53175,13 @@ static int allocateBtreePage(
u32 closest;
Pgno iPage;
unsigned char *aData = pTrunk->aData;
- rc = sqlite3PagerWrite(pTrunk->pDbPage);
- if( rc ){
- goto end_allocate_page;
- }
if( nearby>0 ){
u32 i;
int dist;
closest = 0;
- dist = get4byte(&aData[8]) - nearby;
- if( dist<0 ) dist = -dist;
+ dist = sqlite3AbsInt32(get4byte(&aData[8]) - nearby);
for(i=1; ipgno, n-1));
+ rc = sqlite3PagerWrite(pTrunk->pDbPage);
+ if( rc ) goto end_allocate_page;
if( closestpDbPage) );
noContent = !btreeGetHasContent(pBt, *pPgno);
rc = btreeGetPage(pBt, *pPgno, ppPage, noContent);
if( rc==SQLITE_OK ){
@@ -43387,35 +53227,35 @@ static int allocateBtreePage(
}else{
/* There are no pages on the freelist, so create a new page at the
** end of the file */
- int nPage = pagerPagecount(pBt);
- *pPgno = nPage + 1;
-
- if( *pPgno==PENDING_BYTE_PAGE(pBt) ){
- (*pPgno)++;
- }
+ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
+ if( rc ) return rc;
+ pBt->nPage++;
+ if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ) pBt->nPage++;
#ifndef SQLITE_OMIT_AUTOVACUUM
- if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, *pPgno) ){
+ if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, pBt->nPage) ){
/* If *pPgno refers to a pointer-map page, allocate two new pages
** at the end of the file instead of one. The first allocated page
** becomes a new pointer-map page, the second is used by the caller.
*/
MemPage *pPg = 0;
- TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", *pPgno));
- assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
- rc = btreeGetPage(pBt, *pPgno, &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);
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pPg->pDbPage);
releasePage(pPg);
}
if( rc ) return rc;
- (*pPgno)++;
- if( *pPgno==PENDING_BYTE_PAGE(pBt) ){ (*pPgno)++; }
+ pBt->nPage++;
+ if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ){ pBt->nPage++; }
}
#endif
+ put4byte(28 + (u8*)pBt->pPage1->aData, pBt->nPage);
+ *pPgno = pBt->nPage;
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
- rc = btreeGetPage(pBt, *pPgno, ppPage, 0);
+ rc = btreeGetPage(pBt, *pPgno, ppPage, 1);
if( rc ) return rc;
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){
@@ -43438,16 +53278,17 @@ end_allocate_page:
}else{
*ppPage = 0;
}
+ assert( rc!=SQLITE_OK || sqlite3PagerIswriteable((*ppPage)->pDbPage) );
return rc;
}
/*
-** This function is used to add page iPage to the database file free-list.
+** This function is used to add page iPage to the database file free-list.
** It is assumed that the page is not already a part of the free-list.
**
** The value passed as the second argument to this function is optional.
-** If the caller happens to have a pointer to the MemPage object
-** corresponding to page iPage handy, it may pass it as the second value.
+** If the caller happens to have a pointer to the MemPage object
+** corresponding to page iPage handy, it may pass it as the second value.
** Otherwise, it may pass NULL.
**
** If a pointer to a MemPage object is passed as the second argument,
@@ -43455,7 +53296,7 @@ end_allocate_page:
*/
static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
MemPage *pTrunk = 0; /* Free-list trunk page */
- Pgno iTrunk = 0; /* Page number of free-list trunk page */
+ Pgno iTrunk = 0; /* Page number of free-list trunk page */
MemPage *pPage1 = pBt->pPage1; /* Local reference to page 1 */
MemPage *pPage; /* Page being freed. May be NULL. */
int rc; /* Return Code */
@@ -43551,7 +53392,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
/* If control flows to this point, then it was not possible to add the
** the page being freed as a leaf page of the first trunk in the free-list.
- ** Possibly because the free-list is empty, or possibly because the
+ ** Possibly because the free-list is empty, or possibly because the
** 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.
*/
@@ -43590,13 +53431,16 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){
Pgno ovflPgno;
int rc;
int nOvfl;
- u16 ovflPageSize;
+ u32 ovflPageSize;
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
btreeParseCellPtr(pPage, pCell, &info);
if( info.iOverflow==0 ){
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 */
+ }
ovflPgno = get4byte(&pCell[info.iOverflow]);
assert( pBt->usableSize > 4 );
ovflPageSize = pBt->usableSize - 4;
@@ -43605,9 +53449,9 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){
while( nOvfl-- ){
Pgno iNext = 0;
MemPage *pOvfl = 0;
- if( ovflPgno<2 || ovflPgno>pagerPagecount(pBt) ){
- /* 0 is not a legal page number and page 1 cannot be an
- ** overflow page. Therefore if ovflPgno<2 or past the end of the
+ if( ovflPgno<2 || ovflPgno>btreePagecount(pBt) ){
+ /* 0 is not a legal page number and page 1 cannot be an
+ ** overflow page. Therefore if ovflPgno<2 or past the end of the
** file the database must be corrupt. */
return SQLITE_CORRUPT_BKPT;
}
@@ -43619,11 +53463,11 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){
if( ( pOvfl || ((pOvfl = btreePageLookup(pBt, ovflPgno))!=0) )
&& sqlite3PagerPageRefcount(pOvfl->pDbPage)!=1
){
- /* There is no reason any cursor should have an outstanding reference
+ /* There is no reason any cursor should have an outstanding reference
** to an overflow page belonging to a cell that is being deleted/updated.
- ** So if there exists more than one reference to this page, then it
- ** must not really be an overflow page and the database must be corrupt.
- ** It is helpful to detect this before calling freePage2(), as
+ ** So if there exists more than one reference to this page, then it
+ ** must not really be an overflow page and the database must be corrupt.
+ ** It is helpful to detect this before calling freePage2(), as
** freePage2() may zero the page contents if secure-delete mode is
** enabled. If this 'overflow' page happens to be a page that the
** caller is iterating through or using in some other way, this
@@ -43698,14 +53542,14 @@ static int fillInCell(
assert( info.nHeader==nHeader );
assert( info.nKey==nKey );
assert( info.nData==(u32)(nData+nZero) );
-
+
/* Fill in the payload */
nPayload = nData + nZero;
if( pPage->intKey ){
pSrc = pData;
nSrc = nData;
nData = 0;
- }else{
+ }else{
if( NEVER(nKey>0x7fffffff || pKey==0) ){
return SQLITE_CORRUPT_BKPT;
}
@@ -43725,8 +53569,8 @@ static int fillInCell(
if( pBt->autoVacuum ){
do{
pgnoOvfl++;
- } while(
- PTRMAP_ISPAGE(pBt, pgnoOvfl) || pgnoOvfl==PENDING_BYTE_PAGE(pBt)
+ } while(
+ PTRMAP_ISPAGE(pBt, pgnoOvfl) || pgnoOvfl==PENDING_BYTE_PAGE(pBt)
);
}
#endif
@@ -43734,9 +53578,9 @@ static int fillInCell(
#ifndef SQLITE_OMIT_AUTOVACUUM
/* If the database supports auto-vacuum, and the second or subsequent
** overflow page is being allocated, add an entry to the pointer-map
- ** for that page now.
+ ** for that page now.
**
- ** If this is the first overflow page, then write a partial entry
+ ** 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
@@ -43814,10 +53658,10 @@ static int fillInCell(
** "sz" must be the number of bytes in the cell.
*/
static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
- int i; /* Loop counter */
- int pc; /* Offset to cell content of cell being deleted */
+ u32 pc; /* Offset to cell content of cell being deleted */
u8 *data; /* pPage->aData */
u8 *ptr; /* Used to move bytes around within data[] */
+ u8 *endPtr; /* End of loop */
int rc; /* The return code */
int hdr; /* Beginning of the header. 0 most pages. 100 page 1 */
@@ -43833,7 +53677,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
hdr = pPage->hdrOffset;
testcase( pc==get2byte(&data[hdr+5]) );
testcase( pc+sz==pPage->pBt->usableSize );
- if( pc < get2byte(&data[hdr+5]) || pc+sz > pPage->pBt->usableSize ){
+ if( pc < (u32)get2byte(&data[hdr+5]) || pc+sz > pPage->pBt->usableSize ){
*pRC = SQLITE_CORRUPT_BKPT;
return;
}
@@ -43842,9 +53686,11 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
*pRC = rc;
return;
}
- for(i=idx+1; inCell; i++, ptr+=2){
- ptr[0] = ptr[2];
- ptr[1] = ptr[3];
+ endPtr = &data[pPage->cellOffset + 2*pPage->nCell - 2];
+ assert( (SQLITE_PTR_TO_INT(ptr)&1)==0 ); /* ptr is always 2-byte aligned */
+ while( ptrnCell--;
put2byte(&data[hdr+3], pPage->nCell);
@@ -43859,13 +53705,13 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
** will not fit, then make a copy of the cell content into pTemp if
** pTemp is not null. Regardless of pTemp, allocate a new entry
** in pPage->aOvfl[] and make it point to the cell content (either
-** in pTemp or the original pCell) and also record its index.
-** Allocating a new entry in pPage->aCell[] implies that
+** in pTemp or the original pCell) and also record its index.
+** Allocating a new entry in pPage->aCell[] implies that
** pPage->nOverflow is incremented.
**
** If nSkip is non-zero, then do not copy the first nSkip bytes of the
** cell. The caller will overwrite them after this function returns. If
-** nSkip is non-zero, then pCell may not point to an invalid memory location
+** nSkip is non-zero, then pCell may not point to an invalid memory location
** (but pCell+nSkip is always valid).
*/
static void insertCell(
@@ -43884,13 +53730,14 @@ static void insertCell(
int cellOffset; /* Address of first cell pointer in data[] */
u8 *data; /* The content of the whole page */
u8 *ptr; /* Used for moving information around in data[] */
+ u8 *endPtr; /* End of the loop */
int nSkip = (iChild ? 4 : 0);
if( *pRC ) return;
assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
- assert( pPage->nCell<=MX_CELL(pPage->pBt) && MX_CELL(pPage->pBt)<=5460 );
+ assert( pPage->nCell<=MX_CELL(pPage->pBt) && MX_CELL(pPage->pBt)<=10921 );
assert( pPage->nOverflow<=ArraySize(pPage->aOvfl) );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
/* The cell should normally be sized correctly. However, when moving a
@@ -43927,16 +53774,19 @@ static void insertCell(
/* The allocateSpace() routine guarantees the following two properties
** if it returns success */
assert( idx >= end+2 );
- assert( idx+sz <= pPage->pBt->usableSize );
+ assert( idx+sz <= (int)pPage->pBt->usableSize );
pPage->nCell++;
pPage->nFree -= (u16)(2 + sz);
memcpy(&data[idx+nSkip], pCell+nSkip, sz-nSkip);
if( iChild ){
put4byte(&data[idx], iChild);
}
- for(j=end, ptr=&data[j]; j>ins; j-=2, ptr-=2){
- ptr[0] = ptr[-2];
- ptr[1] = ptr[-1];
+ ptr = &data[end];
+ endPtr = &data[ins];
+ assert( (SQLITE_PTR_TO_INT(ptr)&1)==0 ); /* ptr is always 2-byte aligned */
+ while( ptr>endPtr ){
+ *(u16*)ptr = *(u16*)&ptr[-2];
+ ptr -= 2;
}
put2byte(&data[ins], idx);
put2byte(&data[pPage->hdrOffset+3], pPage->nCell);
@@ -43970,20 +53820,22 @@ static void assemblePage(
assert( pPage->nOverflow==0 );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- assert( nCell>=0 && nCell<=MX_CELL(pPage->pBt) && MX_CELL(pPage->pBt)<=5460 );
+ assert( nCell>=0 && nCell<=(int)MX_CELL(pPage->pBt)
+ && (int)MX_CELL(pPage->pBt)<=10921);
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
/* Check that the page has just been zeroed by zeroPage() */
assert( pPage->nCell==0 );
- assert( get2byte(&data[hdr+5])==nUsable );
+ assert( get2byteNotZero(&data[hdr+5])==nUsable );
pCellptr = &data[pPage->cellOffset + nCell*2];
cellbody = nUsable;
for(i=nCell-1; i>=0; i--){
+ u16 sz = aSize[i];
pCellptr -= 2;
- cellbody -= aSize[i];
+ cellbody -= sz;
put2byte(pCellptr, cellbody);
- memcpy(&data[cellbody], apCell[i], aSize[i]);
+ memcpy(&data[cellbody], apCell[i], sz);
}
put2byte(&data[hdr+3], nCell);
put2byte(&data[hdr+5], cellbody);
@@ -44041,9 +53893,10 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
assert( pPage->nOverflow==1 );
+ /* This error condition is now caught prior to reaching this function */
if( pPage->nCell<=0 ) return SQLITE_CORRUPT_BKPT;
- /* Allocate a new page. This page will become the right-sibling of
+ /* Allocate a new page. This page will become the right-sibling of
** pPage. Make the parent page writable, so that the new divider cell
** may be inserted. If both these operations are successful, proceed.
*/
@@ -44062,7 +53915,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
assemblePage(pNew, 1, &pCell, &szCell);
/* If this is an auto-vacuum database, update the pointer map
- ** with entries for the new page, and any pointer from the
+ ** with entries for the new page, and any pointer from the
** cell on the page to an overflow page. If either of these
** operations fails, the return code is set, but the contents
** of the parent page are still manipulated by thh code below.
@@ -44076,14 +53929,14 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
ptrmapPutOvflPtr(pNew, pCell, &rc);
}
}
-
+
/* Create a divider cell to insert into pParent. The divider cell
** consists of a 4-byte page number (the page number of pPage) and
** a variable length key value (which must be the same value as the
** largest key on pPage).
**
- ** To find the largest key value on pPage, first find the right-most
- ** cell on pPage. The first two fields of this cell are the
+ ** To find the largest key value on pPage, first find the right-most
+ ** cell on pPage. The first two fields of this cell are the
** record-length (a variable length integer at most 32-bits in size)
** and the key value (a variable length integer, may have any value).
** The first of the while(...) loops below skips over the record-length
@@ -44102,7 +53955,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
/* Set the right-child pointer of pParent to point to the new page. */
put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew);
-
+
/* Release the reference to the new page. */
releasePage(pNew);
}
@@ -44114,7 +53967,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
#if 0
/*
** This function does not contribute anything to the operation of SQLite.
-** it is sometimes activated temporarily while debugging code responsible
+** it is sometimes activated temporarily while debugging code responsible
** for setting pointer-map entries.
*/
static int ptrmapCheckPages(MemPage **apPage, int nPage){
@@ -44129,7 +53982,7 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){
for(j=0; jnCell; j++){
CellInfo info;
u8 *z;
-
+
z = findCell(pPage, j);
btreeParseCellPtr(pPage, z, &info);
if( info.iOverflow ){
@@ -44154,7 +54007,7 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){
#endif
/*
-** This function is used to copy the contents of the b-tree node stored
+** This function is used to copy the contents of the b-tree node stored
** on page pFrom to page pTo. If page pFrom was not a leaf page, then
** the pointer-map entries for each child page are updated so that the
** parent page stored in the pointer map is page pTo. If pFrom contained
@@ -44162,11 +54015,11 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){
** map entries are also updated so that the parent page is page pTo.
**
** If pFrom is currently carrying any overflow cells (entries in the
-** MemPage.aOvfl[] array), they are not copied to pTo.
+** MemPage.aOvfl[] array), they are not copied to pTo.
**
** Before returning, page pTo is reinitialized using btreeInitPage().
**
-** The performance of this function is not critical. It is only used by
+** The performance of this function is not critical. It is only used by
** the balance_shallower() and balance_deeper() procedures, neither of
** which are called often under normal circumstances.
*/
@@ -44179,20 +54032,20 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
int const iToHdr = ((pTo->pgno==1) ? 100 : 0);
int rc;
int iData;
-
-
+
+
assert( pFrom->isInit );
assert( pFrom->nFree>=iToHdr );
- assert( get2byte(&aFrom[iFromHdr+5])<=pBt->usableSize );
-
+ assert( get2byte(&aFrom[iFromHdr+5]) <= (int)pBt->usableSize );
+
/* Copy the b-tree node content from page pFrom to page pTo. */
iData = get2byte(&aFrom[iFromHdr+5]);
memcpy(&aTo[iData], &aFrom[iData], pBt->usableSize-iData);
memcpy(&aTo[iToHdr], &aFrom[iFromHdr], pFrom->cellOffset + 2*pFrom->nCell);
-
+
/* Reinitialize page pTo so that the contents of the MemPage structure
** match the new data. The initialization of pTo can actually fail under
- ** fairly obscure circumstances, even though it is a copy of initialized
+ ** fairly obscure circumstances, even though it is a copy of initialized
** page pFrom.
*/
pTo->isInit = 0;
@@ -44201,7 +54054,7 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
*pRC = rc;
return;
}
-
+
/* If this is an auto-vacuum database, update the pointer-map entries
** for any b-tree or overflow pages that pTo now contains the pointers to.
*/
@@ -44216,13 +54069,13 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
** (hereafter "the page") and up to 2 siblings so that all pages have about the
** same amount of free space. Usually a single sibling on either side of the
** page are used in the balancing, though both siblings might come from one
-** side if the page is the first or last child of its parent. If the page
+** side if the page is the first or last child of its parent. If the page
** has fewer than 2 siblings (something which can only happen if the page
** is a root page or a child of a root page) then all available siblings
** participate in the balancing.
**
-** The number of siblings of the page might be increased or decreased by
-** one or two in an effort to keep pages nearly full but not over full.
+** The number of siblings of the page might be increased or decreased by
+** one or two in an effort to keep pages nearly full but not over full.
**
** Note that when this routine is called, some of the cells on the page
** might not actually be stored in MemPage.aData[]. This can happen
@@ -44233,7 +54086,7 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
** inserted into or removed from the parent page (pParent). Doing so
** may cause the parent page to become overfull or underfull. If this
** happens, it is the responsibility of the caller to invoke the correct
-** balancing routine to fix this problem (see the balance() routine).
+** balancing routine to fix this problem (see the balance() routine).
**
** If this routine fails for any reason, it might leave the database
** in a corrupted state. So if this routine fails, the database should
@@ -44248,7 +54101,7 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
** of the page-size, the aOvflSpace[] buffer is guaranteed to be large
** enough for all overflow cells.
**
-** If aOvflSpace is set to a null pointer, this function returns
+** If aOvflSpace is set to a null pointer, this function returns
** SQLITE_NOMEM.
*/
static int balance_nonroot(
@@ -44294,7 +54147,7 @@ static int balance_nonroot(
#endif
/* At this point pParent may have at most one overflow cell. And if
- ** this overflow cell is present, it must be the cell with
+ ** this overflow cell is present, it must be the cell with
** index iParentIdx. This scenario comes about when this function
** is called (indirectly) from sqlite3BtreeDelete().
*/
@@ -44305,11 +54158,11 @@ static int balance_nonroot(
return SQLITE_NOMEM;
}
- /* Find the sibling pages to balance. Also locate the cells in pParent
- ** that divide the siblings. An attempt is made to find NN siblings on
- ** either side of pPage. More siblings are taken from one side, however,
+ /* Find the sibling pages to balance. Also locate the cells in pParent
+ ** that divide the siblings. An attempt is made to find NN siblings on
+ ** either side of pPage. More siblings are taken from one side, however,
** if there are fewer than NN siblings on the other side. If pParent
- ** has NB or fewer children then all children of pParent are taken.
+ ** has NB or fewer children then all children of pParent are taken.
**
** This loop also drops the divider cells from the parent page. This
** way, the remainder of the function does not have to deal with any
@@ -44322,7 +54175,7 @@ static int balance_nonroot(
nOld = i+1;
}else{
nOld = 3;
- if( iParentIdx==0 ){
+ if( iParentIdx==0 ){
nxDiv = 0;
}else if( iParentIdx==i ){
nxDiv = i-2;
@@ -44361,7 +54214,7 @@ static int balance_nonroot(
** This is safe because dropping a cell only overwrites the first
** four bytes of it, and this function does not need the first
** four bytes of the divider cell. So the pointer is safe to use
- ** later on.
+ ** later on.
**
** Unless SQLite is compiled in secure-delete mode. In this case,
** the dropCell() routine will overwrite the entire cell with zeroes.
@@ -44370,7 +54223,7 @@ static int balance_nonroot(
** is allocated. */
if( pBt->secureDelete ){
int iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData);
- if( (iOff+szNew[i])>pBt->usableSize ){
+ if( (iOff+szNew[i])>(int)pBt->usableSize ){
rc = SQLITE_CORRUPT_BKPT;
memset(apOld, 0, (i+1)*sizeof(MemPage*));
goto balance_cleanup;
@@ -44396,7 +54249,7 @@ static int balance_nonroot(
+ nMaxCells*sizeof(u16) /* szCell */
+ pBt->pageSize /* aSpace1 */
+ k*nOld; /* Page copies (apCopy) */
- apCell = sqlite3ScratchMalloc( szScratch );
+ apCell = sqlite3ScratchMalloc( szScratch );
if( apCell==0 ){
rc = SQLITE_NOMEM;
goto balance_cleanup;
@@ -44425,7 +54278,7 @@ static int balance_nonroot(
leafData = apOld[0]->hasData;
for(i=0; iaData, apOld[i]->aData, pBt->pageSize);
limit = pOld->nCell+pOld->nOverflow;
- for(j=0; jnOverflow>0 ){
+ for(j=0; jaData;
+ u16 maskPage = pOld->maskPage;
+ u16 cellOffset = pOld->cellOffset;
+ for(j=0; jpageSize/4 );
- assert( iSpace1<=pBt->pageSize );
+ assert( sz<=pBt->maxLocal+23 );
+ assert( iSpace1 <= (int)pBt->pageSize );
memcpy(pTemp, apDiv[i], sz);
apCell[nCell] = pTemp+leafCorrection;
assert( leafCorrection==0 || leafCorrection==4 );
@@ -44476,7 +54341,7 @@ static int balance_nonroot(
** Figure out the number of pages needed to hold all nCell cells.
** Store this number in "k". Also compute szNew[] which is the total
** size of all cells on the i-th page and cntNew[] which is the index
- ** in apCell[] of the cell that divides page i from page i+1.
+ ** in apCell[] of the cell that divides page i from page i+1.
** cntNew[k] should equal nCell.
**
** Values computed by this block:
@@ -44486,7 +54351,7 @@ static int balance_nonroot(
** cntNew[i]: Index in apCell[] and szCell[] for the first cell to
** the right of the i-th sibling page.
** usableSpace: Number of bytes of space available on each sibling.
- **
+ **
*/
usableSpace = pBt->usableSize - 12 + leafCorrection;
for(subtotal=k=i=0; i0 || (pParent->pgno==1 && pParent->nCell==0) );
TRACE(("BALANCE: old: %d %d %d ",
- apOld[0]->pgno,
+ apOld[0]->pgno,
nOld>=2 ? apOld[1]->pgno : 0,
nOld>=3 ? apOld[2]->pgno : 0
));
@@ -44615,9 +54480,7 @@ static int balance_nonroot(
}
}
if( minI>i ){
- int t;
MemPage *pT;
- t = apNew[i]->pgno;
pT = apNew[i];
apNew[i] = apNew[minI];
apNew[minI] = pT;
@@ -44665,9 +54528,9 @@ static int balance_nonroot(
if( !pNew->leaf ){
memcpy(&pNew->aData[8], pCell, 4);
}else if( leafData ){
- /* If the tree is a leaf-data tree, and the siblings are leaves,
- ** then there is no divider cell in apCell[]. Instead, the divider
- ** cell consists of the integer key for the right-most cell of
+ /* If the tree is a leaf-data tree, and the siblings are leaves,
+ ** then there is no divider cell in apCell[]. Instead, the divider
+ ** cell consists of the integer key for the right-most cell of
** the sibling-page assembled above only.
*/
CellInfo info;
@@ -44680,9 +54543,9 @@ static int balance_nonroot(
pCell -= 4;
/* Obscure case for non-leaf-data trees: If the cell at pCell was
** previously stored on a leaf node, and its reported size was 4
- ** bytes, then it may actually be smaller than this
+ ** bytes, then it may actually be smaller than this
** (see btreeParseCellPtr(), 4 bytes is the minimum size of
- ** any cell). But it is important to pass the correct size to
+ ** any cell). But it is important to pass the correct size to
** insertCell(), so reparse the cell now.
**
** Note that this can never happen in an SQLite data file, as all
@@ -44695,8 +54558,8 @@ static int balance_nonroot(
}
}
iOvflSpace += sz;
- assert( sz<=pBt->pageSize/4 );
- assert( iOvflSpace<=pBt->pageSize );
+ assert( sz<=pBt->maxLocal+23 );
+ assert( iOvflSpace <= (int)pBt->pageSize );
insertCell(pParent, nxDiv, pCell, sz, pTemp, pNew->pgno, &rc);
if( rc!=SQLITE_OK ) goto balance_cleanup;
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
@@ -44720,8 +54583,8 @@ static int balance_nonroot(
** b-tree structure by one. This is described as the "balance-shallower"
** sub-algorithm in some documentation.
**
- ** If this is an auto-vacuum database, the call to copyNodeContent()
- ** sets all pointer-map entries corresponding to database image pages
+ ** If this is an auto-vacuum database, the call to copyNodeContent()
+ ** sets all pointer-map entries corresponding to database image pages
** for which the pointer is stored within the content being copied.
**
** The second assert below verifies that the child page is defragmented
@@ -44729,13 +54592,13 @@ static int balance_nonroot(
** is important if the parent page happens to be page 1 of the database
** image. */
assert( nNew==1 );
- assert( apNew[0]->nFree ==
- (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2)
+ assert( apNew[0]->nFree ==
+ (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2)
);
copyNodeContent(apNew[0], pParent, &rc);
freePage(apNew[0], &rc);
}else if( ISAUTOVACUUM ){
- /* Fix the pointer-map entries for all the cells that were shifted around.
+ /* Fix the pointer-map entries for all the cells that were shifted around.
** There are several different types of pointer-map entries that need to
** be dealt with by this routine. Some of these have been set already, but
** many have not. The following is a summary:
@@ -44747,7 +54610,7 @@ static int balance_nonroot(
** of those.
**
** 2) The pointer-map entries associated with the first overflow
- ** page in any overflow chains used by new divider cells. These
+ ** page in any overflow chains used by new divider cells. These
** have also already been taken care of by the insertCell() code.
**
** 3) If the sibling pages are not leaves, then the child pages of
@@ -44785,7 +54648,7 @@ static int balance_nonroot(
nOverflow = pOld->nOverflow;
iOverflow = i + !leafData + pOld->aOvfl[0].idx;
}
- isDivider = !leafData;
+ isDivider = !leafData;
}
assert(nOverflow>0 || iOverflownOverflow>0 );
assert( sqlite3_mutex_held(pBt->mutex) );
- /* Make pRoot, the root page of the b-tree, writable. Allocate a new
+ /* Make pRoot, the root page of the b-tree, writable. Allocate a new
** page that will become the new right-child of pPage. Copy the contents
** of the node stored on pRoot into the new child page.
*/
@@ -44925,7 +54788,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
/*
** The page that pCur currently points to has just been modified in
** some way. This function figures out if this modification means the
-** tree needs to be balanced, and if so calls the appropriate balancing
+** tree needs to be balanced, and if so calls the appropriate balancing
** routine. Balancing routines are:
**
** balance_quick()
@@ -44951,7 +54814,7 @@ static int balance(BtCursor *pCur){
** balance_deeper() function to create a new child for the root-page
** and copy the current contents of the root-page to it. The
** next iteration of the do-loop will balance the child page.
- */
+ */
assert( (balance_deeper_called++)==0 );
rc = balance_deeper(pPage, &pCur->apPage[1]);
if( rc==SQLITE_OK ){
@@ -44981,10 +54844,10 @@ static int balance(BtCursor *pCur){
/* Call balance_quick() to create a new sibling of pPage on which
** to store the overflow cell. balance_quick() inserts a new cell
** into pParent, which may cause pParent overflow. If this
- ** happens, the next interation of the do-loop will balance pParent
+ ** happens, the next interation of the do-loop will balance pParent
** use either balance_nonroot() or balance_deeper(). Until this
** happens, the overflow cell is stored in the aBalanceQuickSpace[]
- ** buffer.
+ ** buffer.
**
** The purpose of the following assert() is to check that only a
** single call to balance_quick() is made for each call to this
@@ -45001,24 +54864,24 @@ static int balance(BtCursor *pCur){
** modifying the contents of pParent, which may cause pParent to
** become overfull or underfull. The next iteration of the do-loop
** will balance the parent page to correct this.
- **
+ **
** If the parent page becomes overfull, the overflow cell or cells
- ** are stored in the pSpace buffer allocated immediately below.
+ ** are stored in the pSpace buffer allocated immediately below.
** A subsequent iteration of the do-loop will deal with this by
** calling balance_nonroot() (balance_deeper() may be called first,
** but it doesn't deal with overflow cells - just moves them to a
- ** different page). Once this subsequent call to balance_nonroot()
+ ** different page). Once this subsequent call to balance_nonroot()
** has completed, it is safe to release the pSpace buffer used by
- ** the previous call, as the overflow cell data will have been
+ ** the previous call, as the overflow cell data will have been
** copied either into the body of a database page or into the new
** pSpace buffer passed to the latter call to balance_nonroot().
*/
u8 *pSpace = sqlite3PageMalloc(pCur->pBt->pageSize);
rc = balance_nonroot(pParent, iIdx, pSpace, iPage==1);
if( pFree ){
- /* If pFree is not NULL, it points to the pSpace buffer used
+ /* If pFree is not NULL, it points to the pSpace buffer used
** by a previous call to balance_nonroot(). Its contents are
- ** now stored either on real database pages or within the
+ ** now stored either on real database pages or within the
** new pSpace buffer, so it may be safely freed here. */
sqlite3PageFree(pFree);
}
@@ -45058,8 +54921,8 @@ static int balance(BtCursor *pCur){
** MovetoUnpacked() to seek cursor pCur to (pKey, nKey) has already
** been performed. seekResult is the search result returned (a negative
** number if pCur points at an entry that is smaller than (pKey, nKey), or
-** a positive value if pCur points at an etry that is larger than
-** (pKey, nKey)).
+** a positive value if pCur points at an etry that is larger than
+** (pKey, nKey)).
**
** If the seekResult parameter is non-zero, then the caller guarantees that
** cursor pCur is pointing at the existing copy of a row that is to be
@@ -45101,7 +54964,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
** blob of associated data. */
assert( (pKey==0)==(pCur->pKeyInfo==0) );
- /* If this is an insert into a table b-tree, invalidate any incrblob
+ /* If this is an insert into a table b-tree, invalidate any incrblob
** cursors open on the row being replaced (assuming this is a replace
** operation - if it is not, the following is a no-op). */
if( pCur->pKeyInfo==0 ){
@@ -45112,8 +54975,8 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
**
** In some cases, the call to btreeMoveto() below is a no-op. For
** example, when inserting data into a table with auto-generated integer
- ** keys, the VDBE layer invokes sqlite3BtreeLast() to figure out the
- ** integer key to use. It then calls this function to actually insert the
+ ** keys, the VDBE layer invokes sqlite3BtreeLast() to figure out the
+ ** integer key to use. It then calls this function to actually insert the
** data into the intkey B-Tree. In this case btreeMoveto() recognizes
** that the cursor is already where it needs to be and returns without
** doing any work. To avoid thwarting these optimizations, it is important
@@ -45141,7 +55004,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew);
if( rc ) goto end_insert;
assert( szNew==cellSizePtr(pPage, newCell) );
- assert( szNew<=MX_CELL_SIZE(pBt) );
+ assert( szNew <= MX_CELL_SIZE(pBt) );
idx = pCur->aiIdx[pCur->iPage];
if( loc==0 ){
u16 szOld;
@@ -45167,7 +55030,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 occured 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.
@@ -45193,7 +55056,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
rc = balance(pCur);
/* Must make sure nOverflow is reset to zero even if the balance()
- ** fails. Internal data structure corruption will result otherwise.
+ ** fails. Internal data structure corruption will result otherwise.
** Also, set the cursor state to invalid. This stops saveCursorPosition()
** from trying to save the current position of the cursor. */
pCur->apPage[pCur->iPage]->nOverflow = 0;
@@ -45211,12 +55074,12 @@ end_insert:
*/
SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
Btree *p = pCur->pBtree;
- BtShared *pBt = p->pBt;
+ BtShared *pBt = p->pBt;
int rc; /* Return code */
MemPage *pPage; /* Page to delete cell from */
unsigned char *pCell; /* Pointer to cell to delete */
int iCellIdx; /* Index of cell to delete */
- int iCellDepth; /* Depth of node containing pCell */
+ int iCellDepth; /* Depth of node containing pCell */
assert( cursorHoldsMutex(pCur) );
assert( pBt->inTransaction==TRANS_WRITE );
@@ -45225,7 +55088,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
- if( NEVER(pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell)
+ if( NEVER(pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell)
|| NEVER(pCur->eState!=CURSOR_VALID)
){
return SQLITE_ERROR; /* Something has gone awry. */
@@ -45256,9 +55119,9 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
}
/* Save the positions of any other cursors open on this table before
- ** making any modifications. Make the page containing the entry to be
- ** deleted writable. Then free any overflow pages associated with the
- ** entry and finally remove the cell itself from within the page.
+ ** making any modifications. Make the page containing the entry to be
+ ** deleted writable. Then free any overflow pages associated with the
+ ** entry and finally remove the cell itself from within the page.
*/
rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur);
if( rc ) return rc;
@@ -45281,7 +55144,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
pCell = findCell(pLeaf, pLeaf->nCell-1);
nCell = cellSizePtr(pLeaf, pCell);
- assert( MX_CELL_SIZE(pBt)>=nCell );
+ assert( MX_CELL_SIZE(pBt) >= nCell );
allocateTempSpace(pBt);
pTmp = pBt->pTmpSpace;
@@ -45305,7 +55168,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
** on the leaf node first. If the balance proceeds far enough up the
** tree that we can be sure that any problem in the internal node has
** been corrected, so be it. Otherwise, after balancing the leaf node,
- ** walk the cursor up the tree to the internal node and balance it as
+ ** walk the cursor up the tree to the internal node and balance it as
** well. */
rc = balance(pCur);
if( rc==SQLITE_OK && pCur->iPage>iCellDepth ){
@@ -45332,11 +55195,12 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys
** BTREE_ZERODATA Used for SQL indices
*/
-static int btreeCreateTable(Btree *p, int *piTable, int flags){
+static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
BtShared *pBt = p->pBt;
MemPage *pRoot;
Pgno pgnoRoot;
int rc;
+ int ptfFlags; /* Page-type flage for the root page of new table */
assert( sqlite3BtreeHoldsMutex(p) );
assert( pBt->inTransaction==TRANS_WRITE );
@@ -45429,7 +55293,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int flags){
}
}else{
pRoot = pPageMove;
- }
+ }
/* Update the pointer-map and meta-data with the new root-page number. */
ptrmapPut(pBt, pgnoRoot, PTRMAP_ROOTPAGE, 0, &rc);
@@ -45437,8 +55301,14 @@ static int btreeCreateTable(Btree *p, int *piTable, int flags){
releasePage(pRoot);
return rc;
}
+
+ /* When the new root page was allocated, page 1 was made writable in
+ ** order either to increase the database filesize, or to decrement the
+ ** freelist count. Hence, the sqlite3BtreeUpdateMeta() call cannot fail.
+ */
+ assert( sqlite3PagerIswriteable(pBt->pPage1->pDbPage) );
rc = sqlite3BtreeUpdateMeta(p, 4, pgnoRoot);
- if( rc ){
+ if( NEVER(rc) ){
releasePage(pRoot);
return rc;
}
@@ -45449,8 +55319,14 @@ static int btreeCreateTable(Btree *p, int *piTable, int flags){
}
#endif
assert( sqlite3PagerIswriteable(pRoot->pDbPage) );
- zeroPage(pRoot, flags | PTF_LEAF);
+ if( createTabFlags & BTREE_INTKEY ){
+ ptfFlags = PTF_INTKEY | PTF_LEAFDATA | PTF_LEAF;
+ }else{
+ ptfFlags = PTF_ZERODATA | PTF_LEAF;
+ }
+ zeroPage(pRoot, ptfFlags);
sqlite3PagerUnref(pRoot->pDbPage);
+ assert( (pBt->openFlags & BTREE_SINGLE)==0 || pgnoRoot==2 );
*piTable = (int)pgnoRoot;
return SQLITE_OK;
}
@@ -45478,7 +55354,7 @@ static int clearDatabasePage(
int i;
assert( sqlite3_mutex_held(pBt->mutex) );
- if( pgno>pagerPagecount(pBt) ){
+ if( pgno>btreePagecount(pBt) ){
return SQLITE_CORRUPT_BKPT;
}
@@ -45552,12 +55428,12 @@ SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
** cursors on the table.
**
** If AUTOVACUUM is enabled and the page at iTable is not the last
-** root page in the database file, then the last root page
+** root page in the database file, then the last root page
** in the database file is moved into the slot formerly occupied by
** iTable and that last slot formerly occupied by the last root page
** is added to the freelist instead of iTable. In this say, all
** root pages are kept at the beginning of the database file, which
-** is necessary for AUTOVACUUM to work right. *piMoved is set to the
+** is necessary for AUTOVACUUM to work right. *piMoved is set to the
** page number that used to be the last root page in the file before
** the move. If no page gets moved, *piMoved is set to 0.
** The last root page is recorded in meta[3] and the value of
@@ -45574,7 +55450,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
/* It is illegal to drop a table if any cursors are open on the
** database. This is because in auto-vacuum mode the backend may
** need to move another root-page to fill a gap left by the deleted
- ** root page. If an open cursor was using this page a problem would
+ ** root page. If an open cursor was using this page a problem would
** occur.
**
** This error is caught long before control reaches this point.
@@ -45605,7 +55481,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
if( iTable==maxRootPgno ){
/* If the table being dropped is the table with the largest root-page
- ** number in the database, put the root page on the free list.
+ ** number in the database, put the root page on the free list.
*/
freePage(pPage, &rc);
releasePage(pPage);
@@ -45614,7 +55490,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
}
}else{
/* The table being dropped does not have the largest root-page
- ** number in the database. So move the page that does into the
+ ** number in the database. So move the page that does into the
** gap left by the deleted root-page.
*/
MemPage *pMove;
@@ -45659,12 +55535,12 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
}else{
/* If sqlite3BtreeDropTable was called on page 1.
** This really never should happen except in a corrupt
- ** database.
+ ** database.
*/
zeroPage(pPage, PTF_INTKEY|PTF_LEAF );
releasePage(pPage);
}
- return rc;
+ return rc;
}
SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
int rc;
@@ -45683,7 +55559,7 @@ SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
** is the number of free pages currently in the database. Meta[1]
** through meta[15] are available for use by higher layers. Meta[0]
** is read-only, the others are read/write.
-**
+**
** The schema layer numbers meta values differently. At the schema
** layer (and the SetCookie and ReadCookie opcodes) the number of
** free pages is not visible. So Cookie[0] is the same as Meta[1].
@@ -45741,23 +55617,28 @@ SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){
** The first argument, pCur, is a cursor opened on some b-tree. Count the
** number of entries in the b-tree and write the result to *pnEntry.
**
-** SQLITE_OK is returned if the operation is successfully executed.
+** SQLITE_OK is returned if the operation is successfully executed.
** Otherwise, if an error is encountered (i.e. an IO error or database
** corruption) an SQLite error code is returned.
*/
SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
i64 nEntry = 0; /* Value to return in *pnEntry */
int rc; /* Return code */
+
+ if( pCur->pgnoRoot==0 ){
+ *pnEntry = 0;
+ return SQLITE_OK;
+ }
rc = moveToRoot(pCur);
/* Unless an error occurs, the following loop runs one iteration for each
- ** page in the B-Tree structure (not including overflow pages).
+ ** page in the B-Tree structure (not including overflow pages).
*/
while( rc==SQLITE_OK ){
int iIdx; /* Index of child node in parent */
MemPage *pPage; /* Current page of the b-tree */
- /* If this is a leaf page or the tree is not an int-key tree, then
+ /* If this is a leaf page or the tree is not an int-key tree, then
** this page contains countable entries. Increment the entry counter
** accordingly.
*/
@@ -45766,7 +55647,7 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
nEntry += pPage->nCell;
}
- /* pPage is a leaf node. This loop navigates the cursor so that it
+ /* pPage is a leaf node. This loop navigates the cursor so that it
** points to the first interior cell that it points to the parent of
** the next page in the tree that has not yet been visited. The
** pCur->aiIdx[pCur->iPage] value is set to the index of the parent cell
@@ -45790,7 +55671,7 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
pPage = pCur->apPage[pCur->iPage];
}
- /* Descend to the child node of the cell that the cursor currently
+ /* Descend to the child node of the cell that the cursor currently
** points at. This is the right-child if (iIdx==pPage->nCell).
*/
iIdx = pCur->aiIdx[pCur->iPage];
@@ -45867,7 +55748,7 @@ static int checkRef(IntegrityCk *pCheck, Pgno iPage, char *zContext){
#ifndef SQLITE_OMIT_AUTOVACUUM
/*
-** Check that the entry in the pointer-map for page iChild maps to
+** Check that the entry in the pointer-map for page iChild maps to
** page iParent, pointer type ptrType. If not, append an error message
** to pCheck.
*/
@@ -45890,8 +55771,8 @@ static void checkPtrmap(
}
if( ePtrmapType!=eType || iPtrmapParent!=iParent ){
- checkAppendMsg(pCheck, zContext,
- "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)",
+ checkAppendMsg(pCheck, zContext,
+ "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)",
iChild, eType, iParent, ePtrmapType, iPtrmapParent);
}
}
@@ -45933,7 +55814,7 @@ static void checkList(
checkPtrmap(pCheck, iPage, PTRMAP_FREEPAGE, 0, zContext);
}
#endif
- if( n>pCheck->pBt->usableSize/4-2 ){
+ if( n>(int)pCheck->pBt->usableSize/4-2 ){
checkAppendMsg(pCheck, zContext,
"freelist leaf count too big on page %d", iPage);
N--;
@@ -45973,7 +55854,7 @@ static void checkList(
** Do various sanity checks on a single page of a tree. Return
** the tree depth. Root pages return 0. Parents of root pages
** return 1, and so forth.
-**
+**
** These checks are done:
**
** 1. Make sure that cells and freeblocks do not overlap
@@ -45991,7 +55872,7 @@ static int checkTreePage(
IntegrityCk *pCheck, /* Context for the sanity check */
int iPage, /* Page number of the page to check */
char *zParentContext, /* Parent context */
- i64 *pnParentMinKey,
+ i64 *pnParentMinKey,
i64 *pnParentMaxKey
){
MemPage *pPage;
@@ -46025,7 +55906,7 @@ static int checkTreePage(
pPage->isInit = 0;
if( (rc = btreeInitPage(pPage))!=0 ){
assert( rc==SQLITE_CORRUPT ); /* The only possible error from InitPage */
- checkAppendMsg(pCheck, zContext,
+ checkAppendMsg(pCheck, zContext,
"btreeInitPage() returns error code %d", rc);
releasePage(pPage);
return 0;
@@ -46052,13 +55933,13 @@ static int checkTreePage(
else if( i==0 ) nMinKey = nMaxKey = info.nKey;
else{
if( info.nKey <= nMaxKey ){
- checkAppendMsg(pCheck, zContext,
+ checkAppendMsg(pCheck, zContext,
"Rowid %lld out of order (previous was %lld)", info.nKey, nMaxKey);
}
nMaxKey = info.nKey;
}
assert( sz==info.nPayload );
- if( (sz>info.nLocal)
+ if( (sz>info.nLocal)
&& (&pCell[info.iOverflow]<=&pPage->aData[pBt->usableSize])
){
int nPage = (sz - info.nLocal + usableSize - 5)/(usableSize - 4);
@@ -46090,7 +55971,7 @@ static int checkTreePage(
if( !pPage->leaf ){
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
- sqlite3_snprintf(sizeof(zContext), zContext,
+ sqlite3_snprintf(sizeof(zContext), zContext,
"On page %d at right child: ", iPage);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
@@ -46099,7 +55980,7 @@ static int checkTreePage(
#endif
checkTreePage(pCheck, pgno, zContext, NULL, !pPage->nCell ? NULL : &nMaxKey);
}
-
+
/* For intKey leaf pages, check that the min/max keys are in order
** with any left/parent/right pages.
*/
@@ -46109,18 +55990,18 @@ static int checkTreePage(
/* if we are the left most child page */
if( !pnParentMaxKey ){
if( nMaxKey > *pnParentMinKey ){
- checkAppendMsg(pCheck, zContext,
+ checkAppendMsg(pCheck, zContext,
"Rowid %lld out of order (max larger than parent min of %lld)",
nMaxKey, *pnParentMinKey);
}
}else{
if( nMinKey <= *pnParentMinKey ){
- checkAppendMsg(pCheck, zContext,
+ checkAppendMsg(pCheck, zContext,
"Rowid %lld out of order (min less than parent min of %lld)",
nMinKey, *pnParentMinKey);
}
if( nMaxKey > *pnParentMaxKey ){
- checkAppendMsg(pCheck, zContext,
+ checkAppendMsg(pCheck, zContext,
"Rowid %lld out of order (max larger than parent max of %lld)",
nMaxKey, *pnParentMaxKey);
}
@@ -46129,7 +56010,7 @@ static int checkTreePage(
/* else if we're a right child page */
} else if( pnParentMaxKey ){
if( nMinKey <= *pnParentMaxKey ){
- checkAppendMsg(pCheck, zContext,
+ checkAppendMsg(pCheck, zContext,
"Rowid %lld out of order (min less than parent max of %lld)",
nMinKey, *pnParentMaxKey);
}
@@ -46144,7 +56025,7 @@ static int checkTreePage(
if( hit==0 ){
pCheck->mallocFailed = 1;
}else{
- u16 contentOffset = get2byte(&data[hdr+5]);
+ int contentOffset = get2byteNotZero(&data[hdr+5]);
assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
memset(hit+contentOffset, 0, usableSize-contentOffset);
memset(hit, 1, contentOffset);
@@ -46152,13 +56033,13 @@ static int checkTreePage(
cellStart = hdr + 12 - 4*pPage->leaf;
for(i=0; i=usableSize ){
- checkAppendMsg(pCheck, 0,
+ if( (int)(pc+size-1)>=usableSize ){
+ checkAppendMsg(pCheck, 0,
"Corruption detected in cell %d on page %d",i,iPage);
}else{
for(j=pc+size-1; j>=pc; j--) hit[j]++;
@@ -46186,7 +56067,7 @@ static int checkTreePage(
}
}
if( cnt!=data[hdr+7] ){
- checkAppendMsg(pCheck, 0,
+ checkAppendMsg(pCheck, 0,
"Fragmentation of %d bytes reported as %d on page %d",
cnt, data[hdr+7], iPage);
}
@@ -46229,7 +56110,7 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
nRef = sqlite3PagerRefcount(pBt->pPager);
sCheck.pBt = pBt;
sCheck.pPager = pBt->pPager;
- sCheck.nPage = pagerPagecount(sCheck.pBt);
+ sCheck.nPage = btreePagecount(sCheck.pBt);
sCheck.mxErr = mxErr;
sCheck.nErr = 0;
sCheck.mallocFailed = 0;
@@ -46250,6 +56131,7 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
sCheck.anRef[i] = 1;
}
sqlite3StrAccumInit(&sCheck.errMsg, zErr, sizeof(zErr), 20000);
+ sCheck.errMsg.useMalloc = 2;
/* Check the integrity of the freelist
*/
@@ -46279,11 +56161,11 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
/* If the database supports auto-vacuum, make sure no tables contain
** references to pointer-map pages.
*/
- if( sCheck.anRef[i]==0 &&
+ if( sCheck.anRef[i]==0 &&
(PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
}
- if( sCheck.anRef[i]!=0 &&
+ if( sCheck.anRef[i]!=0 &&
(PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
checkAppendMsg(&sCheck, 0, "Pointer map page %d is referenced", i);
}
@@ -46295,7 +56177,7 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
** of the integrity check.
*/
if( NEVER(nRef != sqlite3PagerRefcount(pBt->pPager)) ){
- checkAppendMsg(&sCheck, 0,
+ checkAppendMsg(&sCheck, 0,
"Outstanding page count goes from %d to %d during this analysis",
nRef, sqlite3PagerRefcount(pBt->pPager)
);
@@ -46348,6 +56230,31 @@ SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree *p){
return (p && (p->inTrans==TRANS_WRITE));
}
+#ifndef SQLITE_OMIT_WAL
+/*
+** Run a checkpoint on the Btree passed as the first argument.
+**
+** Return SQLITE_LOCKED if this or any other connection has an open
+** transaction on the shared-cache the argument Btree is connected to.
+**
+** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
+*/
+SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int *pnCkpt){
+ int rc = SQLITE_OK;
+ if( p ){
+ BtShared *pBt = p->pBt;
+ sqlite3BtreeEnter(p);
+ if( pBt->inTransaction!=TRANS_NONE ){
+ rc = SQLITE_LOCKED;
+ }else{
+ rc = sqlite3PagerCheckpoint(pBt->pPager, eMode, pnLog, pnCkpt);
+ }
+ sqlite3BtreeLeave(p);
+ }
+ return rc;
+}
+#endif
+
/*
** Return non-zero if a read (or write) transaction is active.
*/
@@ -46366,28 +56273,28 @@ SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree *p){
/*
** This function returns a pointer to a blob of memory associated with
** a single shared-btree. The memory is used by client code for its own
-** purposes (for example, to store a high-level schema associated with
+** purposes (for example, to store a high-level schema associated with
** the shared-btree). The btree layer manages reference counting issues.
**
** The first time this is called on a shared-btree, nBytes bytes of memory
-** are allocated, zeroed, and returned to the caller. For each subsequent
+** are allocated, zeroed, and returned to the caller. For each subsequent
** call the nBytes parameter is ignored and a pointer to the same blob
-** of memory returned.
+** of memory returned.
**
** If the nBytes parameter is 0 and the blob of memory has not yet been
** allocated, a null pointer is returned. If the blob has already been
** allocated, it is returned as normal.
**
-** Just before the shared-btree is closed, the function passed as the
-** xFree argument when the memory allocation was made is invoked on the
-** blob of allocated memory. This function should not call sqlite3_free()
+** Just before the shared-btree is closed, the function passed as the
+** xFree argument when the memory allocation was made is invoked on the
+** blob of allocated memory. The xFree function should not call sqlite3_free()
** on the memory, the btree layer does that.
*/
SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){
BtShared *pBt = p->pBt;
sqlite3BtreeEnter(p);
if( !pBt->pSchema && nBytes ){
- pBt->pSchema = sqlite3MallocZero(nBytes);
+ pBt->pSchema = sqlite3DbMallocZero(0, nBytes);
pBt->xFreeSchema = xFree;
}
sqlite3BtreeLeave(p);
@@ -46395,8 +56302,8 @@ SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void
}
/*
-** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared
-** btree as the argument handle holds an exclusive lock on the
+** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared
+** btree as the argument handle holds an exclusive lock on the
** sqlite_master table. Otherwise SQLITE_OK.
*/
SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *p){
@@ -46437,11 +56344,11 @@ SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){
#ifndef SQLITE_OMIT_INCRBLOB
/*
-** Argument pCsr must be a cursor opened for writing on an
-** INTKEY table currently pointing at a valid table entry.
+** Argument pCsr must be a cursor opened for writing on an
+** INTKEY table currently pointing at a valid table entry.
** This function modifies the data stored as part of that entry.
**
-** Only the data content may only be modified, it is not possible to
+** Only the data content may only be modified, it is not possible to
** change the length of the data stored. If this function is called with
** parameters that attempt to write past the end of the existing data,
** no modifications are made and SQLITE_CORRUPT is returned.
@@ -46461,7 +56368,7 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void
return SQLITE_ABORT;
}
- /* Check some assumptions:
+ /* Check some assumptions:
** (a) the cursor is open for writing,
** (b) there is a read/write transaction open,
** (c) the connection holds a write-lock on the table (if required),
@@ -46479,8 +56386,8 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void
return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1);
}
-/*
-** Set a flag on this cursor to cache the locations of pages from the
+/*
+** Set a flag on this cursor to cache the locations of pages from the
** overflow list for the current row. This is used by cursors opened
** for incremental blob IO only.
**
@@ -46492,12 +56399,46 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void
SQLITE_PRIVATE void sqlite3BtreeCacheOverflow(BtCursor *pCur){
assert( cursorHoldsMutex(pCur) );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
- assert(!pCur->isIncrblobHandle);
- assert(!pCur->aOverflow);
+ invalidateOverflowCache(pCur);
pCur->isIncrblobHandle = 1;
}
#endif
+/*
+** Set both the "read version" (single byte at byte offset 18) and
+** "write version" (single byte at byte offset 19) fields in the database
+** header to iVersion.
+*/
+SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
+ BtShared *pBt = pBtree->pBt;
+ int rc; /* Return code */
+
+ assert( iVersion==1 || iVersion==2 );
+
+ /* If setting the version fields to 1, do not automatically open the
+ ** WAL connection, even if the version fields are currently set to 2.
+ */
+ pBt->doNotUseWAL = (u8)(iVersion==1);
+
+ rc = sqlite3BtreeBeginTrans(pBtree, 0);
+ if( rc==SQLITE_OK ){
+ u8 *aData = pBt->pPage1->aData;
+ if( aData[18]!=(u8)iVersion || aData[19]!=(u8)iVersion ){
+ rc = sqlite3BtreeBeginTrans(pBtree, 2);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
+ if( rc==SQLITE_OK ){
+ aData[18] = (u8)iVersion;
+ aData[19] = (u8)iVersion;
+ }
+ }
+ }
+ }
+
+ pBt->doNotUseWAL = 0;
+ return rc;
+}
+
/************** End of btree.c ***********************************************/
/************** Begin file backup.c ******************************************/
/*
@@ -46511,7 +56452,7 @@ SQLITE_PRIVATE void sqlite3BtreeCacheOverflow(BtCursor *pCur){
** May you share freely, never taking more than you give.
**
*************************************************************************
-** This file contains the implementation of the sqlite3_backup_XXX()
+** This file contains the implementation of the sqlite3_backup_XXX()
** API functions and the related features.
*/
@@ -46552,15 +56493,15 @@ struct sqlite3_backup {
** Once it has been created using backup_init(), a single sqlite3_backup
** structure may be accessed via two groups of thread-safe entry points:
**
-** * Via the sqlite3_backup_XXX() API function backup_step() and
+** * Via the sqlite3_backup_XXX() API function backup_step() and
** backup_finish(). Both these functions obtain the source database
-** handle mutex and the mutex associated with the source BtShared
+** handle mutex and the mutex associated with the source BtShared
** structure, in that order.
**
** * Via the BackupUpdate() and BackupRestart() functions, which are
** invoked by the pager layer to report various state changes in
** the page cache associated with the source database. The mutex
-** associated with the source database BtShared structure will always
+** associated with the source database BtShared structure will always
** be held when either of these functions are invoked.
**
** The other sqlite3_backup_XXX() API functions, backup_remaining() and
@@ -46581,8 +56522,8 @@ struct sqlite3_backup {
** in connection handle pDb. If such a database cannot be found, return
** a NULL pointer and write an error message to pErrorDb.
**
-** If the "temp" database is requested, it may need to be opened by this
-** function. If an error occurs while doing so, return 0 and write an
+** If the "temp" database is requested, it may need to be opened by this
+** function. If an error occurs while doing so, return 0 and write an
** error message to pErrorDb.
*/
static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
@@ -46617,6 +56558,16 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
return pDb->aDb[i].pBt;
}
+/*
+** Attempt to set the page size of the destination to match the page size
+** of the source.
+*/
+static int setDestPgsz(sqlite3_backup *p){
+ int rc;
+ rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),-1,0);
+ return rc;
+}
+
/*
** Create an sqlite3_backup process to copy the contents of zSrcDb from
** connection handle pSrcDb to zDestDb in pDestDb. If successful, return
@@ -46650,7 +56601,10 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init(
);
p = 0;
}else {
- /* Allocate space for a new sqlite3_backup object */
+ /* Allocate space for a new sqlite3_backup object...
+ ** EVIDENCE-OF: R-64852-21591 The sqlite3_backup object is created by a
+ ** call to sqlite3_backup_init() and is destroyed by a call to
+ ** sqlite3_backup_finish(). */
p = (sqlite3_backup *)sqlite3_malloc(sizeof(sqlite3_backup));
if( !p ){
sqlite3Error(pDestDb, SQLITE_NOMEM, 0);
@@ -46667,10 +56621,11 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init(
p->iNext = 1;
p->isAttached = 0;
- if( 0==p->pSrc || 0==p->pDest ){
- /* One (or both) of the named databases did not exist. An error has
- ** already been written into the pDestDb handle. All that is left
- ** to do here is free the sqlite3_backup structure.
+ if( 0==p->pSrc || 0==p->pDest || setDestPgsz(p)==SQLITE_NOMEM ){
+ /* One (or both) of the named databases did not exist or an OOM
+ ** error was hit. The error has already been written into the
+ ** pDestDb handle. All that is left to do here is free the
+ ** sqlite3_backup structure.
*/
sqlite3_free(p);
p = 0;
@@ -46686,7 +56641,7 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init(
}
/*
-** Argument rc is an SQLite error code. Return true if this error is
+** Argument rc is an SQLite error code. Return true if this error is
** considered fatal if encountered during a backup operation. All errors
** are considered fatal except for SQLITE_BUSY and SQLITE_LOCKED.
*/
@@ -46695,8 +56650,8 @@ static int isFatalError(int rc){
}
/*
-** Parameter zSrcData points to a buffer containing the data for
-** page iSrcPg from the source database. Copy this data into the
+** Parameter zSrcData points to a buffer containing the data for
+** page iSrcPg from the source database. Copy this data into the
** destination database.
*/
static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){
@@ -46705,6 +56660,10 @@ static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){
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);
+ int nDestReserve = sqlite3BtreeGetReserve(p->pDest);
+#endif
int rc = SQLITE_OK;
i64 iOff;
@@ -46715,13 +56674,33 @@ static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){
assert( zSrcData );
/* Catch the case where the destination is an in-memory database and the
- ** page sizes of the source and destination differ.
+ ** page sizes of the source and destination differ.
*/
- if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(sqlite3BtreePager(p->pDest)) ){
+ if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){
rc = SQLITE_READONLY;
}
- /* This loop runs once for each destination page spanned by the source
+#ifdef SQLITE_HAS_CODEC
+ /* Backup is not possible if the page size of the destination is changing
+ ** and a codec is in use.
+ */
+ if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){
+ rc = SQLITE_READONLY;
+ }
+
+ /* Backup is not possible if the number of bytes of reserve space differ
+ ** between source and destination. If there is a difference, try to
+ ** fix the destination to agree with the source. If that is not possible,
+ ** then the backup cannot proceed.
+ */
+ if( nSrcReserve!=nDestReserve ){
+ u32 newPgsz = nSrcPgsz;
+ rc = sqlite3PagerSetPagesize(pDestPager, &newPgsz, nSrcReserve);
+ if( rc==SQLITE_OK && newPgsz!=nSrcPgsz ) rc = SQLITE_READONLY;
+ }
+#endif
+
+ /* This loop runs once for each destination page spanned by the source
** page. For each iteration, variable iOff is set to the byte offset
** of the destination page.
*/
@@ -46740,7 +56719,7 @@ static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){
** Then clear the Btree layer MemPage.isInit flag. Both this module
** and the pager code use this trick (clearing the first byte
** of the page 'extra' space to invalidate the Btree layers
- ** cached parse of the page). MemPage.isInit is marked
+ ** cached parse of the page). MemPage.isInit is marked
** "MUST BE FIRST" for this purpose.
*/
memcpy(zOut, zIn, nCopy);
@@ -46757,7 +56736,7 @@ static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){
** exactly iSize bytes. If pFile is not larger than iSize bytes, then
** this function is a no-op.
**
-** Return SQLITE_OK if everything is successful, or an SQLite error
+** Return SQLITE_OK if everything is successful, or an SQLite error
** code if an error occurs.
*/
static int backupTruncateFile(sqlite3_file *pFile, i64 iSize){
@@ -46787,6 +56766,9 @@ static void attachBackupObject(sqlite3_backup *p){
*/
SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
int rc;
+ int destMode; /* Destination journal mode */
+ int pgszSrc = 0; /* Source page size */
+ int pgszDest = 0; /* Destination page size */
sqlite3_mutex_enter(p->pSrcDb->mutex);
sqlite3BtreeEnter(p->pSrc);
@@ -46813,7 +56795,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
/* Lock the destination database, if it is not locked already. */
if( SQLITE_OK==rc && p->bDestLocked==0
- && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2))
+ && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2))
){
p->bDestLocked = 1;
sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema);
@@ -46828,12 +56810,20 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
bCloseTrans = 1;
}
+ /* Do not allow backup if the destination database is in WAL mode
+ ** and the page sizes are different between source and destination */
+ pgszSrc = sqlite3BtreeGetPageSize(p->pSrc);
+ pgszDest = sqlite3BtreeGetPageSize(p->pDest);
+ destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest));
+ if( SQLITE_OK==rc && destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){
+ rc = SQLITE_READONLY;
+ }
+
/* Now that there is a read-lock on the source database, query the
** source pager for the number of pages in the database.
*/
- if( rc==SQLITE_OK ){
- rc = sqlite3PagerPagecount(pSrcPager, &nSrcPage);
- }
+ nSrcPage = (int)sqlite3BtreeLastPage(p->pSrc);
+ assert( nSrcPage>=0 );
for(ii=0; (nPage<0 || iiiNext<=(Pgno)nSrcPage && !rc; ii++){
const Pgno iSrcPg = p->iNext; /* Source page number */
if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){
@@ -46855,97 +56845,115 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
attachBackupObject(p);
}
}
-
+
/* Update the schema version field in the destination database. This
** is to make sure that the schema-version really does change in
** the case where the source and destination databases have the
** same schema version.
*/
- if( rc==SQLITE_DONE
- && (rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1))==SQLITE_OK
- ){
- const int nSrcPagesize = sqlite3BtreeGetPageSize(p->pSrc);
- const int nDestPagesize = sqlite3BtreeGetPageSize(p->pDest);
- int nDestTruncate;
-
- if( p->pDestDb ){
- sqlite3ResetInternalSchema(p->pDestDb, 0);
- }
-
- /* Set nDestTruncate to the final number of pages in the destination
- ** database. The complication here is that the destination page
- ** size may be different to the source page size.
- **
- ** If the source page size is smaller than the destination page size,
- ** round up. In this case the call to sqlite3OsTruncate() below will
- ** fix the size of the file. However it is important to call
- ** sqlite3PagerTruncateImage() here so that any pages in the
- ** destination file that lie beyond the nDestTruncate page mark are
- ** journalled by PagerCommitPhaseOne() before they are destroyed
- ** by the file truncation.
- */
- if( nSrcPagesizepDest->pBt) ){
- nDestTruncate--;
+ if( rc==SQLITE_DONE ){
+ rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1);
+ if( rc==SQLITE_OK ){
+ if( p->pDestDb ){
+ sqlite3ResetInternalSchema(p->pDestDb, -1);
+ }
+ if( destMode==PAGER_JOURNALMODE_WAL ){
+ rc = sqlite3BtreeSetVersion(p->pDest, 2);
}
- }else{
- nDestTruncate = nSrcPage * (nSrcPagesize/nDestPagesize);
}
- sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
-
- if( nSrcPagesizepSrc) );
+ assert( pgszDest==sqlite3BtreeGetPageSize(p->pDest) );
+ if( pgszSrcpDest->pBt) ){
+ nDestTruncate--;
+ }
+ }else{
+ nDestTruncate = nSrcPage * (pgszSrc/pgszDest);
+ }
+ sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
- assert( pFile );
- assert( (i64)nDestTruncate*(i64)nDestPagesize >= iSize || (
- nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
- && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+nDestPagesize
- ));
- if( SQLITE_OK==(rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1))
- && SQLITE_OK==(rc = backupTruncateFile(pFile, iSize))
- && SQLITE_OK==(rc = sqlite3PagerSync(pDestPager))
- ){
+ if( pgszSrc= 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
+ ** 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);
+
+ /* Write the extra pages and truncate the database file as required */
+ iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
for(
- iOff=PENDING_BYTE+nSrcPagesize;
- rc==SQLITE_OK && iOffpDest))
- ){
- rc = SQLITE_DONE;
+ /* Sync the database file to disk. */
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerSync(pDestPager);
+ }
+ }else{
+ rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0);
+ }
+
+ /* Finish committing the transaction to the destination database. */
+ if( SQLITE_OK==rc
+ && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0))
+ ){
+ rc = SQLITE_DONE;
+ }
}
}
-
+
/* If bCloseTrans is true, then this function opened a read transaction
** on the source database. Close the read transaction here. There is
** no need to check the return values of the btree methods here, as
@@ -46954,10 +56962,13 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
if( bCloseTrans ){
TESTONLY( int rc2 );
TESTONLY( rc2 = ) sqlite3BtreeCommitPhaseOne(p->pSrc, 0);
- TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc);
+ TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc, 0);
assert( rc2==SQLITE_OK );
}
-
+
+ if( rc==SQLITE_IOERR_NOMEM ){
+ rc = SQLITE_NOMEM;
+ }
p->rc = rc;
}
if( p->pDestDb ){
@@ -47010,6 +57021,9 @@ SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){
}
sqlite3BtreeLeave(p->pSrc);
if( p->pDestDb ){
+ /* EVIDENCE-OF: R-64852-21591 The sqlite3_backup object is created by a
+ ** call to sqlite3_backup_init() and is destroyed by a call to
+ ** sqlite3_backup_finish(). */
sqlite3_free(p);
}
sqlite3_mutex_leave(mutex);
@@ -47025,7 +57039,7 @@ SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p){
}
/*
-** Return the total number of pages in the source database as of the most
+** Return the total number of pages in the source database as of the most
** recent call to sqlite3_backup_step().
*/
SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p){
@@ -47034,7 +57048,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p){
/*
** This function is called after the contents of page iPage of the
-** source database have been modified. If page iPage has already been
+** source database have been modified. If page iPage has already been
** copied into the destination database, then the data written to the
** destination is now invalidated. The destination copy of iPage needs
** to be updated with the new data before the backup operation is
@@ -47053,7 +57067,11 @@ SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *pBackup, Pgno iPage, con
** has been modified by a transaction on the source pager. Copy
** the new data into the backup.
*/
- int rc = backupOnePage(p, iPage, aData);
+ int rc;
+ assert( p->pDestDb );
+ sqlite3_mutex_enter(p->pDestDb->mutex);
+ rc = backupOnePage(p, iPage, aData);
+ sqlite3_mutex_leave(p->pDestDb->mutex);
assert( rc!=SQLITE_BUSY && rc!=SQLITE_LOCKED );
if( rc!=SQLITE_OK ){
p->rc = rc;
@@ -47066,7 +57084,7 @@ SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *pBackup, Pgno iPage, con
** Restart the backup process. This is called when the pager layer
** detects that the database has been modified by an external database
** connection. In this case there is no way of knowing which of the
-** pages that have been copied into the destination database are still
+** pages that have been copied into the destination database are still
** valid and which are not, so the entire process needs to be restarted.
**
** It is assumed that the mutex associated with the BtShared object
@@ -47086,8 +57104,8 @@ SQLITE_PRIVATE void sqlite3BackupRestart(sqlite3_backup *pBackup){
** Copy the complete content of pBtFrom into pBtTo. A transaction
** must be active for both files.
**
-** The size of file pTo may be reduced by this operation. If anything
-** goes wrong, the transaction on pTo is rolled back. If successful, the
+** The size of file pTo may be reduced by this operation. If anything
+** goes wrong, the transaction on pTo is rolled back. If successful, the
** transaction is committed before returning.
*/
SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
@@ -47109,9 +57127,9 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
/* 0x7FFFFFFF is the hard limit for the number of pages in a database
** file. By passing this as the number of pages to copy to
- ** sqlite3_backup_step(), we can guarantee that the copy finishes
+ ** sqlite3_backup_step(), we can guarantee that the copy finishes
** within a single call (unless an error occurs). The assert() statement
- ** checks this assumption - (p->rc) should be set to either SQLITE_DONE
+ ** checks this assumption - (p->rc) should be set to either SQLITE_DONE
** or an error code.
*/
sqlite3_backup_step(&b, 0x7FFFFFFF);
@@ -47191,23 +57209,23 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
}
/*
-** Make sure pMem->z points to a writable allocation of at least
+** Make sure pMem->z points to a writable allocation of at least
** n bytes.
**
** If the memory cell currently contains string or blob data
-** and the third argument passed to this function is true, the
+** and the third argument passed to this function is true, the
** current content of the cell is preserved. Otherwise, it may
-** be discarded.
+** be discarded.
**
** This function sets the MEM_Dyn flag and clears any xDel callback.
-** It also clears MEM_Ephem and MEM_Static. If the preserve flag is
+** It also clears MEM_Ephem and MEM_Static. If the preserve flag is
** not set, Mem.n is zeroed.
*/
SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve){
assert( 1 >=
((pMem->zMalloc && pMem->zMalloc==pMem->z) ? 1 : 0) +
- (((pMem->flags&MEM_Dyn)&&pMem->xDel) ? 1 : 0) +
- ((pMem->flags&MEM_Ephem) ? 1 : 0) +
+ (((pMem->flags&MEM_Dyn)&&pMem->xDel) ? 1 : 0) +
+ ((pMem->flags&MEM_Ephem) ? 1 : 0) +
((pMem->flags&MEM_Static) ? 1 : 0)
);
assert( (pMem->flags&MEM_RowSet)==0 );
@@ -47261,6 +57279,9 @@ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){
pMem->z[pMem->n] = 0;
pMem->z[pMem->n+1] = 0;
pMem->flags |= MEM_Term;
+#ifdef SQLITE_DEBUG
+ pMem->pScopyFrom = 0;
+#endif
}
return SQLITE_OK;
@@ -47346,7 +57367,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, int enc){
/* For a Real or Integer, use sqlite3_mprintf() to produce the UTF-8
** string representation of the value. Then, if the required encoding
** is UTF-16le or UTF-16be do a translation.
- **
+ **
** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16.
*/
if( fg & MEM_Int ){
@@ -47381,7 +57402,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
ctx.s.db = pMem->db;
ctx.pMem = pMem;
ctx.pFunc = pFunc;
- pFunc->xFinalize(&ctx);
+ pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */
assert( 0==(pMem->flags&MEM_Dyn) && !pMem->xDel );
sqlite3DbFree(pMem->db, pMem->zMalloc);
memcpy(pMem, &ctx.s, sizeof(ctx.s));
@@ -47397,24 +57418,18 @@ SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
*/
SQLITE_PRIVATE void sqlite3VdbeMemReleaseExternal(Mem *p){
assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) );
- testcase( p->flags & MEM_Agg );
- testcase( p->flags & MEM_Dyn );
- testcase( p->flags & MEM_RowSet );
- testcase( p->flags & MEM_Frame );
- if( p->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame) ){
- if( p->flags&MEM_Agg ){
- sqlite3VdbeMemFinalize(p, p->u.pDef);
- assert( (p->flags & MEM_Agg)==0 );
- sqlite3VdbeMemRelease(p);
- }else if( p->flags&MEM_Dyn && p->xDel ){
- assert( (p->flags&MEM_RowSet)==0 );
- p->xDel((void *)p->z);
- p->xDel = 0;
- }else if( p->flags&MEM_RowSet ){
- sqlite3RowSetClear(p->u.pRowSet);
- }else if( p->flags&MEM_Frame ){
- sqlite3VdbeMemSetNull(p);
- }
+ if( p->flags&MEM_Agg ){
+ sqlite3VdbeMemFinalize(p, p->u.pDef);
+ assert( (p->flags & MEM_Agg)==0 );
+ sqlite3VdbeMemRelease(p);
+ }else if( p->flags&MEM_Dyn && p->xDel ){
+ assert( (p->flags&MEM_RowSet)==0 );
+ p->xDel((void *)p->z);
+ p->xDel = 0;
+ }else if( p->flags&MEM_RowSet ){
+ sqlite3RowSetClear(p->u.pRowSet);
+ }else if( p->flags&MEM_Frame ){
+ sqlite3VdbeMemSetNull(p);
}
}
@@ -47424,7 +57439,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemReleaseExternal(Mem *p){
** (Mem.type==SQLITE_TEXT).
*/
SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p){
- sqlite3VdbeMemReleaseExternal(p);
+ MemReleaseExt(p);
sqlite3DbFree(p->db, p->zMalloc);
p->z = 0;
p->zMalloc = 0;
@@ -47493,14 +57508,10 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){
}else if( flags & MEM_Real ){
return doubleToInt64(pMem->r);
}else if( flags & (MEM_Str|MEM_Blob) ){
- i64 value;
- pMem->flags |= MEM_Str;
- if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
- || sqlite3VdbeMemNulTerminate(pMem) ){
- return 0;
- }
- assert( pMem->z );
- sqlite3Atoi64(pMem->z, &value);
+ i64 value = 0;
+ assert( pMem->z || pMem->n==0 );
+ testcase( pMem->z==0 );
+ sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
return value;
}else{
return 0;
@@ -47523,14 +57534,7 @@ SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){
}else if( pMem->flags & (MEM_Str|MEM_Blob) ){
/* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
double val = (double)0;
- pMem->flags |= MEM_Str;
- if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
- || sqlite3VdbeMemNulTerminate(pMem) ){
- /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
- return (double)0;
- }
- assert( pMem->z );
- sqlite3AtoF(pMem->z, &val);
+ sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc);
return val;
}else{
/* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
@@ -47603,21 +57607,19 @@ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){
** as much of the string as we can and ignore the rest.
*/
SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
- int rc;
- assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 );
- assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
- assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
- rc = sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8);
- if( rc ) return rc;
- rc = sqlite3VdbeMemNulTerminate(pMem);
- if( rc ) return rc;
- if( sqlite3Atoi64(pMem->z, &pMem->u.i) ){
- MemSetTypeFlag(pMem, MEM_Int);
- }else{
- pMem->r = sqlite3VdbeRealValue(pMem);
- MemSetTypeFlag(pMem, MEM_Real);
- sqlite3VdbeIntegerAffinity(pMem);
+ if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){
+ assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
+ if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){
+ MemSetTypeFlag(pMem, MEM_Int);
+ }else{
+ pMem->r = sqlite3VdbeRealValue(pMem);
+ MemSetTypeFlag(pMem, MEM_Real);
+ sqlite3VdbeIntegerAffinity(pMem);
+ }
}
+ assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 );
+ pMem->flags &= ~(MEM_Str|MEM_Blob);
return SQLITE_OK;
}
@@ -47626,7 +57628,9 @@ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
*/
SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem *pMem){
if( pMem->flags & MEM_Frame ){
- sqlite3VdbeFrameDelete(pMem->u.pFrame);
+ VdbeFrame *pFrame = pMem->u.pFrame;
+ pFrame->pParent = pFrame->v->pDelFrame;
+ pFrame->v->pDelFrame = pFrame;
}
if( pMem->flags & MEM_RowSet ){
sqlite3RowSetClear(pMem->u.pRowSet);
@@ -47699,7 +57703,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem *pMem){
pMem->flags = MEM_Null;
}else{
assert( pMem->zMalloc );
- pMem->u.pRowSet = sqlite3RowSetInit(db, pMem->zMalloc,
+ pMem->u.pRowSet = sqlite3RowSetInit(db, pMem->zMalloc,
sqlite3DbMallocSize(db, pMem->zMalloc));
assert( pMem->u.pRowSet!=0 );
pMem->flags = MEM_RowSet;
@@ -47719,9 +57723,31 @@ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){
}
return n>p->db->aLimit[SQLITE_LIMIT_LENGTH];
}
- return 0;
+ return 0;
}
+#ifdef SQLITE_DEBUG
+/*
+** This routine prepares a memory cell for modication by breaking
+** its link to a shallow copy and by marking any current shallow
+** copies of this cell as invalid.
+**
+** This is used for testing and debugging only - to make sure shallow
+** copies are not misused.
+*/
+SQLITE_PRIVATE void sqlite3VdbeMemPrepareToChange(Vdbe *pVdbe, Mem *pMem){
+ int i;
+ Mem *pX;
+ for(i=1, pX=&pVdbe->aMem[1]; i<=pVdbe->nMem; i++, pX++){
+ if( pX->pScopyFrom==pMem ){
+ pX->flags |= MEM_Invalid;
+ pX->pScopyFrom = 0;
+ }
+ }
+ pMem->pScopyFrom = 0;
+}
+#endif /* SQLITE_DEBUG */
+
/*
** Size of struct Mem not including the Mem.zMalloc member.
*/
@@ -47735,7 +57761,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){
*/
SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
assert( (pFrom->flags & MEM_RowSet)==0 );
- sqlite3VdbeMemReleaseExternal(pTo);
+ MemReleaseExt(pTo);
memcpy(pTo, pFrom, MEMCELLSIZE);
pTo->xDel = 0;
if( (pFrom->flags&MEM_Static)==0 ){
@@ -47753,7 +57779,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
int rc = SQLITE_OK;
assert( (pFrom->flags & MEM_RowSet)==0 );
- sqlite3VdbeMemReleaseExternal(pTo);
+ MemReleaseExt(pTo);
memcpy(pTo, pFrom, MEMCELLSIZE);
pTo->flags &= ~MEM_Dyn;
@@ -47789,8 +57815,8 @@ SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){
** Change the value of a Mem to be a string or a BLOB.
**
** The memory management strategy depends on the value of the xDel
-** parameter. If the value passed is SQLITE_TRANSIENT, then the
-** string is copied into a (possibly existing) buffer managed by the
+** parameter. If the value passed is SQLITE_TRANSIENT, then the
+** string is copied into a (possibly existing) buffer managed by the
** Mem structure. Otherwise, any existing buffer is freed and the
** pointer copied.
**
@@ -47899,7 +57925,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
f2 = pMem2->flags;
combined_flags = f1|f2;
assert( (combined_flags & MEM_RowSet)==0 );
-
+
/* If one value is NULL, it is less than the other. If both values
** are NULL, return 0.
*/
@@ -47954,7 +57980,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
}
assert( pMem1->enc==pMem2->enc );
- assert( pMem1->enc==SQLITE_UTF8 ||
+ assert( pMem1->enc==SQLITE_UTF8 ||
pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE );
/* The collation sequence must be defined at this point, even if
@@ -47990,7 +58016,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
/* If a NULL pointer was passed as the collate function, fall through
** to the blob case and use memcmp(). */
}
-
+
/* Both values must be blobs. Compare using memcmp(). */
rc = memcmp(pMem1->z, pMem2->z, (pMem1->n>pMem2->n)?pMem2->n:pMem1->n);
if( rc==0 ){
@@ -48025,7 +58051,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
assert( sqlite3BtreeCursorIsValid(pCur) );
- /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert()
+ /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert()
** that both the BtShared and database handle mutexes are held. */
assert( (pMem->flags & MEM_RowSet)==0 );
if( key ){
@@ -48090,7 +58116,7 @@ SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
return 0;
}
}
- sqlite3VdbeMemNulTerminate(pVal);
+ sqlite3VdbeMemNulTerminate(pVal); /* IMP: R-59893-45467 */
}else{
assert( (pVal->flags&MEM_Blob)==0 );
sqlite3VdbeMemStringify(pVal, enc);
@@ -48138,23 +58164,43 @@ SQLITE_PRIVATE int sqlite3ValueFromExpr(
int op;
char *zVal = 0;
sqlite3_value *pVal = 0;
+ int negInt = 1;
+ const char *zNeg = "";
if( !pExpr ){
*ppVal = 0;
return SQLITE_OK;
}
op = pExpr->op;
- if( op==TK_REGISTER ){
- op = pExpr->op2; /* This only happens with SQLITE_ENABLE_STAT2 */
+
+ /* op can only be TK_REGISTER if we have compiled with SQLITE_ENABLE_STAT2.
+ ** The ifdef here is to enable us to achieve 100% branch test coverage even
+ ** when SQLITE_ENABLE_STAT2 is omitted.
+ */
+#ifdef SQLITE_ENABLE_STAT2
+ if( op==TK_REGISTER ) op = pExpr->op2;
+#else
+ if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
+#endif
+
+ /* Handle negative integers in a single step. This is needed in the
+ ** case when the value is -9223372036854775808.
+ */
+ if( op==TK_UMINUS
+ && (pExpr->pLeft->op==TK_INTEGER || pExpr->pLeft->op==TK_FLOAT) ){
+ pExpr = pExpr->pLeft;
+ op = pExpr->op;
+ negInt = -1;
+ zNeg = "-";
}
if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
pVal = sqlite3ValueNew(db);
if( pVal==0 ) goto no_mem;
if( ExprHasProperty(pExpr, EP_IntValue) ){
- sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue);
+ sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue*negInt);
}else{
- zVal = sqlite3DbStrDup(db, pExpr->u.zToken);
+ zVal = sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken);
if( zVal==0 ) goto no_mem;
sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
if( op==TK_FLOAT ) pVal->type = SQLITE_FLOAT;
@@ -48164,15 +58210,27 @@ SQLITE_PRIVATE int sqlite3ValueFromExpr(
}else{
sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8);
}
+ if( pVal->flags & (MEM_Int|MEM_Real) ) pVal->flags &= ~MEM_Str;
if( enc!=SQLITE_UTF8 ){
sqlite3VdbeChangeEncoding(pVal, enc);
}
}else if( op==TK_UMINUS ) {
+ /* This branch happens for multiple negative signs. Ex: -(-5) */
if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) ){
- pVal->u.i = -1 * pVal->u.i;
- /* (double)-1 In case of SQLITE_OMIT_FLOATING_POINT... */
- pVal->r = (double)-1 * pVal->r;
+ sqlite3VdbeMemNumerify(pVal);
+ if( pVal->u.i==SMALLEST_INT64 ){
+ pVal->flags &= MEM_Int;
+ pVal->flags |= MEM_Real;
+ pVal->r = (double)LARGEST_INT64;
+ }else{
+ pVal->u.i = -pVal->u.i;
+ }
+ pVal->r = -pVal->r;
+ sqlite3ValueApplyAffinity(pVal, affinity, enc);
}
+ }else if( op==TK_NULL ){
+ pVal = sqlite3ValueNew(db);
+ if( pVal==0 ) goto no_mem;
}
#ifndef SQLITE_OMIT_BLOB_LITERAL
else if( op==TK_BLOB ){
@@ -48343,12 +58401,12 @@ SQLITE_PRIVATE void sqlite3VdbeTrace(Vdbe *p, FILE *trace){
#endif
/*
-** Resize the Vdbe.aOp array so that it is at least one op larger than
+** Resize the Vdbe.aOp array so that it is at least one op larger than
** it was.
**
** If an out-of-memory error occurs while resizing the array, return
-** SQLITE_NOMEM. In this case Vdbe.aOp and Vdbe.nOpAlloc remain
-** unchanged (this is so that any opcodes already allocated can be
+** SQLITE_NOMEM. In this case Vdbe.aOp and Vdbe.nOpAlloc remain
+** unchanged (this is so that any opcodes already allocated can be
** correctly deallocated along with the rest of the Vdbe).
*/
static int growOpArray(Vdbe *p){
@@ -48399,7 +58457,6 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
pOp->p3 = p3;
pOp->p4.p = 0;
pOp->p4type = P4_NOTUSED;
- p->expired = 0;
#ifdef SQLITE_DEBUG
pOp->zComment = 0;
if( sqlite3VdbeAddopTrace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);
@@ -48438,6 +58495,20 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4(
return addr;
}
+/*
+** Add an OP_ParseSchema opcode. This routine is broken out from
+** sqlite3VdbeAddOp4() since it needs to also local all btrees.
+**
+** The zWhere string must have been obtained from sqlite3_malloc().
+** This routine will take ownership of the allocated memory.
+*/
+SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){
+ int j;
+ int addr = sqlite3VdbeAddOp3(p, OP_ParseSchema, iDb, 0, 0);
+ sqlite3VdbeChangeP4(p, addr, zWhere, P4_DYNAMIC);
+ for(j=0; jdb->nDb; j++) sqlite3VdbeUsesBtree(p, j);
+}
+
/*
** Add an opcode that includes the p4 value as an integer.
*/
@@ -48509,19 +58580,19 @@ SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe *p){
/*
** The following type and function are used to iterate through all opcodes
-** in a Vdbe main program and each of the sub-programs (triggers) it may
+** in a Vdbe main program and each of the sub-programs (triggers) it may
** invoke directly or indirectly. It should be used as follows:
**
** Op *pOp;
** VdbeOpIter sIter;
**
** memset(&sIter, 0, sizeof(sIter));
-** sIter.v = v; // v is of type Vdbe*
+** sIter.v = v; // v is of type Vdbe*
** while( (pOp = opIterNext(&sIter)) ){
** // Do something with pOp
** }
** sqlite3DbFree(v->db, sIter.apSub);
-**
+**
*/
typedef struct VdbeOpIter VdbeOpIter;
struct VdbeOpIter {
@@ -48554,7 +58625,7 @@ static Op *opIterNext(VdbeOpIter *p){
p->iSub++;
p->iAddr = 0;
}
-
+
if( pRet->p4type==P4_SUBPROGRAM ){
int nByte = (p->nSub+1)*sizeof(SubProgram*);
int j;
@@ -48604,11 +58675,11 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
while( (pOp = opIterNext(&sIter))!=0 ){
int opcode = pOp->opcode;
- if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
+ if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
#ifndef SQLITE_OMIT_FOREIGN_KEY
- || (opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1)
+ || (opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1)
#endif
- || ((opcode==OP_Halt || opcode==OP_HaltIfNull)
+ || ((opcode==OP_Halt || opcode==OP_HaltIfNull)
&& (pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
){
hasAbort = 1;
@@ -48633,8 +58704,8 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
**
** This routine is called once after all opcodes have been inserted.
**
-** Variable *pMaxFuncArgs is set to the maximum value of any P2 argument
-** to an OP_Function, OP_AggStep or OP_VFilter opcode. This is used by
+** Variable *pMaxFuncArgs is set to the maximum value of any P2 argument
+** to an OP_Function, OP_AggStep or OP_VFilter opcode. This is used by
** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array.
**
** The Op.opflags field is set on all opcodes.
@@ -48651,7 +58722,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
pOp->opflags = sqlite3OpcodeProperty[opcode];
if( opcode==OP_Function || opcode==OP_AggStep ){
if( pOp->p5>nMaxArgs ) nMaxArgs = pOp->p5;
- }else if( opcode==OP_Transaction && pOp->p2!=0 ){
+ }else if( (opcode==OP_Transaction && pOp->p2!=0) || opcode==OP_Vacuum ){
p->readOnly = 0;
#ifndef SQLITE_OMIT_VIRTUALTABLE
}else if( opcode==OP_VUpdate ){
@@ -48663,6 +58734,12 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
n = pOp[-1].p1;
if( n>nMaxArgs ) nMaxArgs = n;
#endif
+ }else if( opcode==OP_Next || opcode==OP_SorterNext ){
+ pOp->p4.xAdvance = sqlite3BtreeNext;
+ pOp->p4type = P4_ADVANCE;
+ }else if( opcode==OP_Prev ){
+ pOp->p4.xAdvance = sqlite3BtreePrevious;
+ pOp->p4type = P4_ADVANCE;
}
if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){
@@ -48687,12 +58764,12 @@ SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){
/*
** This function returns a pointer to the array of opcodes associated with
** the Vdbe passed as the first argument. It is the callers responsibility
-** to arrange for the returned array to be eventually freed using the
+** to arrange for the returned array to be eventually freed using the
** vdbeFreeOpArray() function.
**
** Before returning, *pnOp is set to the number of entries in the returned
-** array. Also, *pnMaxArg is set to the larger of its current value and
-** the number of entries in the Vdbe.apArg[] array required to execute the
+** array. Also, *pnMaxArg is set to the larger of its current value and
+** the number of entries in the Vdbe.apArg[] array required to execute the
** returned program.
*/
SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){
@@ -48700,7 +58777,7 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg)
assert( aOp && !p->db->mallocFailed );
/* Check that sqlite3VdbeUsesBtree() was not called on this VM */
- assert( p->aMutex.nMutex==0 );
+ assert( p->btreeMask==0 );
resolveP2Values(p, pnMaxArg);
*pnOp = p->nOp;
@@ -48754,10 +58831,9 @@ SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp)
** static array using sqlite3VdbeAddOpList but we want to make a
** few minor changes to the program.
*/
-SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){
+SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe *p, u32 addr, int val){
assert( p!=0 );
- assert( addr>=0 );
- if( p->nOp>addr ){
+ if( ((u32)p->nOp)>addr ){
p->aOp[addr].p1 = val;
}
}
@@ -48766,10 +58842,9 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){
** Change the value of the P2 operand for a specific instruction.
** This routine is useful for setting a jump destination.
*/
-SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
+SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, u32 addr, int val){
assert( p!=0 );
- assert( addr>=0 );
- if( p->nOp>addr ){
+ if( ((u32)p->nOp)>addr ){
p->aOp[addr].p2 = val;
}
}
@@ -48777,10 +58852,9 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
/*
** Change the value of the P3 operand for a specific instruction.
*/
-SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, int addr, int val){
+SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){
assert( p!=0 );
- assert( addr>=0 );
- if( p->nOp>addr ){
+ if( ((u32)p->nOp)>addr ){
p->aOp[addr].p3 = val;
}
}
@@ -48802,6 +58876,7 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 val){
** the address of the next instruction to be coded.
*/
SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){
+ assert( addr>=0 );
sqlite3VdbeChangeP2(p, addr, p->nOp);
}
@@ -48816,15 +58891,17 @@ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
}
}
+static void vdbeFreeOpArray(sqlite3 *, Op *, int);
+
/*
** Delete a P4 value if necessary.
*/
static void freeP4(sqlite3 *db, int p4type, void *p4){
if( p4 ){
+ assert( db );
switch( p4type ){
case P4_REAL:
case P4_INT64:
- case P4_MPRINTF:
case P4_DYNAMIC:
case P4_KEYINFO:
case P4_INTARRAY:
@@ -48832,10 +58909,14 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
sqlite3DbFree(db, p4);
break;
}
+ case P4_MPRINTF: {
+ if( db->pnBytesFreed==0 ) sqlite3_free(p4);
+ break;
+ }
case P4_VDBEFUNC: {
VdbeFunc *pVdbeFunc = (VdbeFunc *)p4;
freeEphemeralFunction(db, pVdbeFunc->pFunc);
- sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
+ if( db->pnBytesFreed==0 ) sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
sqlite3DbFree(db, pVdbeFunc);
break;
}
@@ -48844,15 +58925,17 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
break;
}
case P4_MEM: {
- sqlite3ValueFree((sqlite3_value*)p4);
+ if( db->pnBytesFreed==0 ){
+ sqlite3ValueFree((sqlite3_value*)p4);
+ }else{
+ Mem *p = (Mem*)p4;
+ sqlite3DbFree(db, p->zMalloc);
+ sqlite3DbFree(db, p);
+ }
break;
}
case P4_VTAB : {
- sqlite3VtabUnlock((VTable *)p4);
- break;
- }
- case P4_SUBPROGRAM : {
- sqlite3VdbeProgramDelete(db, (SubProgram *)p4, 1);
+ if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4);
break;
}
}
@@ -48861,8 +58944,8 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
/*
** Free the space allocated for aOp and any p4 values allocated for the
-** opcodes contained within. If aOp is not NULL it is assumed to contain
-** nOp entries.
+** opcodes contained within. If aOp is not NULL it is assumed to contain
+** nOp entries.
*/
static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
if( aOp ){
@@ -48871,55 +58954,32 @@ static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
freeP4(db, pOp->p4type, pOp->p4.p);
#ifdef SQLITE_DEBUG
sqlite3DbFree(db, pOp->zComment);
-#endif
+#endif
}
}
sqlite3DbFree(db, aOp);
}
/*
-** Decrement the ref-count on the SubProgram structure passed as the
-** second argument. If the ref-count reaches zero, free the structure.
-**
-** The array of VDBE opcodes stored as SubProgram.aOp is freed if
-** either the ref-count reaches zero or parameter freeop is non-zero.
-**
-** Since the array of opcodes pointed to by SubProgram.aOp may directly
-** or indirectly contain a reference to the SubProgram structure itself.
-** By passing a non-zero freeop parameter, the caller may ensure that all
-** SubProgram structures and their aOp arrays are freed, even when there
-** are such circular references.
+** Link the SubProgram object passed as the second argument into the linked
+** list at Vdbe.pSubProgram. This list is used to delete all sub-program
+** objects when the VM is no longer required.
*/
-SQLITE_PRIVATE void sqlite3VdbeProgramDelete(sqlite3 *db, SubProgram *p, int freeop){
- if( p ){
- assert( p->nRef>0 );
- if( freeop || p->nRef==1 ){
- Op *aOp = p->aOp;
- p->aOp = 0;
- vdbeFreeOpArray(db, aOp, p->nOp);
- p->nOp = 0;
- }
- p->nRef--;
- if( p->nRef==0 ){
- sqlite3DbFree(db, p);
- }
- }
+SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){
+ p->pNext = pVdbe->pProgram;
+ pVdbe->pProgram = p;
}
-
/*
-** Change N opcodes starting at addr to No-ops.
+** Change the opcode at addr into OP_Noop
*/
-SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe *p, int addr, int N){
+SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
if( p->aOp ){
VdbeOp *pOp = &p->aOp[addr];
sqlite3 *db = p->db;
- while( N-- ){
- freeP4(db, pOp->p4type, pOp->p4.p);
- memset(pOp, 0, sizeof(pOp[0]));
- pOp->opcode = OP_Noop;
- pOp++;
- }
+ freeP4(db, pOp->p4type, pOp->p4.p);
+ memset(pOp, 0, sizeof(pOp[0]));
+ pOp->opcode = OP_Noop;
}
}
@@ -48938,10 +58998,10 @@ SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe *p, int addr, int N){
** A copy is made of the KeyInfo structure into memory obtained from
** sqlite3_malloc, to be freed when the Vdbe is finalized.
** n==P4_KEYINFO_HANDOFF indicates that zP4 points to a KeyInfo structure
-** stored in memory that the caller has obtained from sqlite3_malloc. The
+** stored in memory that the caller has obtained from sqlite3_malloc. The
** caller should not free the allocation, it will be freed when the Vdbe is
** finalized.
-**
+**
** Other values of n (P4_STATIC, P4_COLLSEQ etc.) indicate that zP4 points
** to a string or structure that is guaranteed to exist for the lifetime of
** the Vdbe. In these cases we can just copy the pointer.
@@ -48982,11 +59042,11 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int
nField = ((KeyInfo*)zP4)->nField;
nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]) + nField;
- pKeyInfo = sqlite3Malloc( nByte );
+ pKeyInfo = sqlite3DbMallocRaw(0, nByte);
pOp->p4.pKeyInfo = pKeyInfo;
if( pKeyInfo ){
u8 *aSortOrder;
- memcpy(pKeyInfo, zP4, nByte);
+ memcpy((char*)pKeyInfo, zP4, nByte - nField);
aSortOrder = pKeyInfo->aSortOrder;
if( aSortOrder ){
pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField];
@@ -49057,9 +59117,12 @@ SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){
**
** If a memory allocation error has occurred prior to the calling of this
** routine, then a pointer to a dummy VdbeOp will be returned. That opcode
-** is readable and writable, but it has no effect. The return of a dummy
-** opcode allows the call to continue functioning after a OOM fault without
-** having to check to see if the return from this routine is a valid pointer.
+** is readable but not writable, though it is cast to a writable value.
+** The return of a dummy opcode allows the call to continue functioning
+** after a OOM fault without having to check to see if the return from
+** this routine is a valid pointer. But because the dummy.opcode is 0,
+** dummy will never be written to. This is verified by code inspection and
+** by running with Valgrind.
**
** About the #ifdef SQLITE_OMIT_TRACE: Normally, this routine is never called
** unless p->nOp>0. This is because in the absense of SQLITE_OMIT_TRACE,
@@ -49070,17 +59133,19 @@ SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){
** check the value of p->nOp-1 before continuing.
*/
SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
- static VdbeOp dummy;
+ /* C89 specifies that the constant "dummy" will be initialized to all
+ ** zeros, which is correct. MSVC generates a warning, nevertheless. */
+ static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */
assert( p->magic==VDBE_MAGIC_INIT );
if( addr<0 ){
#ifdef SQLITE_OMIT_TRACE
- if( p->nOp==0 ) return &dummy;
+ if( p->nOp==0 ) return (VdbeOp*)&dummy;
#endif
addr = p->nOp - 1;
}
assert( (addr>=0 && addrnOp) || p->db->mallocFailed );
if( p->db->mallocFailed ){
- return &dummy;
+ return (VdbeOp*)&dummy;
}else{
return &p->aOp[addr];
}
@@ -49178,6 +59243,10 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
sqlite3_snprintf(nTemp, zTemp, "program");
break;
}
+ case P4_ADVANCE: {
+ zTemp[0] = 0;
+ break;
+ }
default: {
zP4 = pOp->p4.z;
if( zP4==0 ){
@@ -49193,18 +59262,81 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
/*
** Declare to the Vdbe that the BTree object at db->aDb[i] is used.
+**
+** The prepared statements need to know in advance the complete set of
+** attached databases that they will be using. A mask of these databases
+** is maintained in p->btreeMask and is used for locking and other purposes.
*/
SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){
- int mask;
- assert( i>=0 && idb->nDb && i=0 && idb->nDb && i<(int)sizeof(yDbMask)*8 );
assert( i<(int)sizeof(p->btreeMask)*8 );
- mask = ((u32)1)<btreeMask & mask)==0 ){
- p->btreeMask |= mask;
- sqlite3BtreeMutexArrayInsert(&p->aMutex, p->db->aDb[i].pBt);
+ p->btreeMask |= ((yDbMask)1)<db->aDb[i].pBt) ){
+ p->lockMask |= ((yDbMask)1)<0
+/*
+** If SQLite is compiled to support shared-cache mode and to be threadsafe,
+** this routine obtains the mutex associated with each BtShared structure
+** that may be accessed by the VM passed as an argument. In doing so it also
+** sets the BtShared.db member of each of the BtShared structures, ensuring
+** that the correct busy-handler callback is invoked if required.
+**
+** If SQLite is not threadsafe but does support shared-cache mode, then
+** sqlite3BtreeEnter() is invoked to set the BtShared.db variables
+** of all of BtShared structures accessible via the database handle
+** associated with the VM.
+**
+** If SQLite is not threadsafe and does not support shared-cache mode, this
+** function is a no-op.
+**
+** The p->btreeMask field is a bitmask of all btrees that the prepared
+** statement p will ever use. Let N be the number of bits in p->btreeMask
+** corresponding to btrees that use shared cache. Then the runtime of
+** this routine is N*N. But as N is rarely more than 1, this should not
+** be a problem.
+*/
+SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe *p){
+ int i;
+ yDbMask mask;
+ sqlite3 *db;
+ Db *aDb;
+ int nDb;
+ if( p->lockMask==0 ) return; /* The common case */
+ db = p->db;
+ aDb = db->aDb;
+ nDb = db->nDb;
+ for(i=0, mask=1; ilockMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){
+ sqlite3BtreeEnter(aDb[i].pBt);
+ }
+ }
+}
+#endif
+
+#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
+/*
+** Unlock all of the btrees previously locked by a call to sqlite3VdbeEnter().
+*/
+SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe *p){
+ int i;
+ yDbMask mask;
+ sqlite3 *db;
+ Db *aDb;
+ int nDb;
+ if( p->lockMask==0 ) return; /* The common case */
+ db = p->db;
+ aDb = db->aDb;
+ nDb = db->nDb;
+ for(i=0, mask=1; ilockMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){
+ sqlite3BtreeLeave(aDb[i].pBt);
+ }
+ }
+}
+#endif
#if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
/*
@@ -49216,7 +59348,7 @@ SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){
static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-4s %.2X %s\n";
if( pOut==0 ) pOut = stdout;
zP4 = displayP4(pOp, zPtr, sizeof(zPtr));
- fprintf(pOut, zFormat1, pc,
+ fprintf(pOut, zFormat1, pc,
sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5,
#ifdef SQLITE_DEBUG
pOp->zComment ? pOp->zComment : ""
@@ -49236,19 +59368,25 @@ static void releaseMemArray(Mem *p, int N){
Mem *pEnd;
sqlite3 *db = p->db;
u8 malloc_failed = db->mallocFailed;
+ if( db->pnBytesFreed ){
+ for(pEnd=&p[N]; pzMalloc);
+ }
+ return;
+ }
for(pEnd=&p[N]; pflags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){
@@ -49382,7 +59520,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
pMem->type = SQLITE_INTEGER;
pMem->u.i = i; /* Program counter */
pMem++;
-
+
pMem->flags = MEM_Static|MEM_Str|MEM_Term;
pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */
assert( pMem->z!=0 );
@@ -49421,12 +59559,10 @@ SQLITE_PRIVATE int sqlite3VdbeList(
pMem->type = SQLITE_INTEGER;
pMem++;
- if( p->explain==1 ){
- pMem->flags = MEM_Int;
- pMem->u.i = pOp->p3; /* P3 */
- pMem->type = SQLITE_INTEGER;
- pMem++;
- }
+ pMem->flags = MEM_Int;
+ pMem->u.i = pOp->p3; /* P3 */
+ pMem->type = SQLITE_INTEGER;
+ pMem++;
if( sqlite3VdbeMemGrow(pMem, 32, 0) ){ /* P4 */
assert( p->db->mallocFailed );
@@ -49455,7 +59591,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
pMem->type = SQLITE_TEXT;
pMem->enc = SQLITE_UTF8;
pMem++;
-
+
#ifdef SQLITE_DEBUG
if( pOp->zComment ){
pMem->flags = MEM_Str|MEM_Term;
@@ -49471,7 +59607,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
}
}
- p->nResColumn = 8 - 5*(p->explain-1);
+ p->nResColumn = 8 - 4*(p->explain-1);
p->rc = SQLITE_OK;
rc = SQLITE_ROW;
}
@@ -49567,34 +59703,13 @@ static void *allocSpace(
}
/*
-** Prepare a virtual machine for execution. This involves things such
-** as allocating stack space and initializing the program counter.
-** After the VDBE has be prepped, it can be executed by one or more
-** calls to sqlite3VdbeExec().
-**
-** This is the only way to move a VDBE from VDBE_MAGIC_INIT to
-** VDBE_MAGIC_RUN.
-**
-** This function may be called more than once on a single virtual machine.
-** The first call is made while compiling the SQL statement. Subsequent
-** calls are made as part of the process of resetting a statement to be
-** re-executed (from a call to sqlite3_reset()). The nVar, nMem, nCursor
-** and isExplain parameters are only passed correct values the first time
-** the function is called. On subsequent calls, from sqlite3_reset(), nVar
-** is passed -1 and nMem, nCursor and isExplain are all passed zero.
+** Rewind the VDBE back to the beginning in preparation for
+** running it.
*/
-SQLITE_PRIVATE void sqlite3VdbeMakeReady(
- Vdbe *p, /* The VDBE */
- int nVar, /* Number of '?' see in the SQL statement */
- int nMem, /* Number of memory cells to allocate */
- int nCursor, /* Number of cursors to allocate */
- int nArg, /* Maximum number of args in SubPrograms */
- int isExplain, /* True if the EXPLAIN keywords is present */
- int usesStmtJournal /* True to set Vdbe.usesStmtJournal */
-){
- int n;
- sqlite3 *db = p->db;
-
+SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){
+#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
+ int i;
+#endif
assert( p!=0 );
assert( p->magic==VDBE_MAGIC_INIT );
@@ -49605,10 +59720,75 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
/* Set the magic to VDBE_MAGIC_RUN sooner rather than later. */
p->magic = VDBE_MAGIC_RUN;
+#ifdef SQLITE_DEBUG
+ for(i=1; inMem; i++){
+ assert( p->aMem[i].db==p->db );
+ }
+#endif
+ p->pc = -1;
+ p->rc = SQLITE_OK;
+ p->errorAction = OE_Abort;
+ p->magic = VDBE_MAGIC_RUN;
+ p->nChange = 0;
+ p->cacheCtr = 1;
+ p->minWriteFileFormat = 255;
+ p->iStatement = 0;
+ p->nFkConstraint = 0;
+#ifdef VDBE_PROFILE
+ for(i=0; inOp; i++){
+ p->aOp[i].cnt = 0;
+ p->aOp[i].cycles = 0;
+ }
+#endif
+}
+
+/*
+** Prepare a virtual machine for execution for the first time after
+** creating the virtual machine. This involves things such
+** as allocating stack space and initializing the program counter.
+** After the VDBE has be prepped, it can be executed by one or more
+** calls to sqlite3VdbeExec().
+**
+** This function may be called exact once on a each virtual machine.
+** After this routine is called the VM has been "packaged" and is ready
+** to run. After this routine is called, futher calls to
+** sqlite3VdbeAddOp() functions are prohibited. This routine disconnects
+** the Vdbe from the Parse object that helped generate it so that the
+** the Vdbe becomes an independent entity and the Parse object can be
+** destroyed.
+**
+** Use the sqlite3VdbeRewind() procedure to restore a virtual machine back
+** to its initial state after it has been run.
+*/
+SQLITE_PRIVATE void sqlite3VdbeMakeReady(
+ Vdbe *p, /* The VDBE */
+ Parse *pParse /* Parsing context */
+){
+ sqlite3 *db; /* The database connection */
+ int nVar; /* Number of parameters */
+ int nMem; /* Number of VM memory registers */
+ int nCursor; /* Number of cursors required */
+ int nArg; /* Number of arguments in subprograms */
+ int n; /* Loop counter */
+ u8 *zCsr; /* Memory available for allocation */
+ u8 *zEnd; /* First byte past allocated memory */
+ int nByte; /* How much extra memory is needed */
+
+ assert( p!=0 );
+ assert( p->nOp>0 );
+ assert( pParse!=0 );
+ assert( p->magic==VDBE_MAGIC_INIT );
+ db = p->db;
+ assert( db->mallocFailed==0 );
+ nVar = pParse->nVar;
+ nMem = pParse->nMem;
+ nCursor = pParse->nTab;
+ nArg = pParse->nMaxArg;
+
/* For each cursor required, also allocate a memory cell. Memory
** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by
** the vdbe program. Instead they are used to allocate space for
- ** VdbeCursor/BtCursor structures. The blob of memory associated with
+ ** VdbeCursor/BtCursor structures. The blob of memory associated with
** cursor 0 is stored in memory cell nMem. Memory cell (nMem-1)
** stores the blob of memory associated with cursor 1, etc.
**
@@ -49616,101 +59796,81 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
*/
nMem += nCursor;
- /* Allocate space for memory registers, SQL variables, VDBE cursors and
- ** an array to marshal SQL function arguments in. This is only done the
- ** first time this function is called for a given VDBE, not when it is
- ** being called from sqlite3_reset() to reset the virtual machine.
+ /* Allocate space for memory registers, SQL variables, VDBE cursors and
+ ** an array to marshal SQL function arguments in.
*/
- if( nVar>=0 && ALWAYS(db->mallocFailed==0) ){
- u8 *zCsr = (u8 *)&p->aOp[p->nOp]; /* Memory avaliable for alloation */
- u8 *zEnd = (u8 *)&p->aOp[p->nOpAlloc]; /* First byte past available mem */
- int nByte; /* How much extra memory needed */
+ zCsr = (u8*)&p->aOp[p->nOp]; /* Memory avaliable for allocation */
+ zEnd = (u8*)&p->aOp[p->nOpAlloc]; /* First byte past end of zCsr[] */
- resolveP2Values(p, &nArg);
- p->usesStmtJournal = (u8)usesStmtJournal;
- if( isExplain && nMem<10 ){
- nMem = 10;
+ resolveP2Values(p, &nArg);
+ p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);
+ if( pParse->explain && nMem<10 ){
+ nMem = 10;
+ }
+ memset(zCsr, 0, zEnd-zCsr);
+ zCsr += (zCsr - (u8*)0)&7;
+ assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
+ p->expired = 0;
+
+ /* Memory for registers, parameters, cursor, etc, is allocated in two
+ ** passes. On the first pass, we try to reuse unused space at the
+ ** end of the opcode array. If we are unable to satisfy all memory
+ ** requirements by reusing the opcode array tail, then the second
+ ** pass will fill in the rest using a fresh allocation.
+ **
+ ** This two-pass approach that reuses as much memory as possible from
+ ** the leftover space at the end of the opcode array can significantly
+ ** reduce the amount of memory held by a prepared statement.
+ */
+ do {
+ nByte = 0;
+ p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
+ p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
+ p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
+ p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
+ p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
+ &zCsr, zEnd, &nByte);
+ if( nByte ){
+ p->pFree = sqlite3DbMallocZero(db, nByte);
}
- memset(zCsr, 0, zEnd-zCsr);
- zCsr += (zCsr - (u8*)0)&7;
- assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
+ zCsr = p->pFree;
+ zEnd = &zCsr[nByte];
+ }while( nByte && !db->mallocFailed );
- /* Memory for registers, parameters, cursor, etc, is allocated in two
- ** passes. On the first pass, we try to reuse unused space at the
- ** end of the opcode array. If we are unable to satisfy all memory
- ** requirements by reusing the opcode array tail, then the second
- ** pass will fill in the rest using a fresh allocation.
- **
- ** This two-pass approach that reuses as much memory as possible from
- ** the leftover space at the end of the opcode array can significantly
- ** reduce the amount of memory held by a prepared statement.
- */
- do {
- nByte = 0;
- p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
- p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
- p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
- p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
- p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
- &zCsr, zEnd, &nByte);
- if( nByte ){
- p->pFree = sqlite3DbMallocZero(db, nByte);
- }
- zCsr = p->pFree;
- zEnd = &zCsr[nByte];
- }while( nByte && !db->mallocFailed );
-
- p->nCursor = (u16)nCursor;
- if( p->aVar ){
- p->nVar = (ynVar)nVar;
- for(n=0; naVar[n].flags = MEM_Null;
- p->aVar[n].db = db;
- }
- }
- if( p->aMem ){
- p->aMem--; /* aMem[] goes from 1..nMem */
- p->nMem = nMem; /* not from 0..nMem-1 */
- for(n=1; n<=nMem; n++){
- p->aMem[n].flags = MEM_Null;
- p->aMem[n].db = db;
- }
+ p->nCursor = (u16)nCursor;
+ if( p->aVar ){
+ p->nVar = (ynVar)nVar;
+ for(n=0; naVar[n].flags = MEM_Null;
+ p->aVar[n].db = db;
}
}
-#ifdef SQLITE_DEBUG
- for(n=1; nnMem; n++){
- assert( p->aMem[n].db==db );
+ if( p->azVar ){
+ p->nzVar = pParse->nzVar;
+ memcpy(p->azVar, pParse->azVar, p->nzVar*sizeof(p->azVar[0]));
+ memset(pParse->azVar, 0, pParse->nzVar*sizeof(pParse->azVar[0]));
}
-#endif
-
- p->pc = -1;
- p->rc = SQLITE_OK;
- p->errorAction = OE_Abort;
- p->explain |= isExplain;
- p->magic = VDBE_MAGIC_RUN;
- p->nChange = 0;
- p->cacheCtr = 1;
- p->minWriteFileFormat = 255;
- p->iStatement = 0;
-#ifdef VDBE_PROFILE
- {
- int i;
- for(i=0; inOp; i++){
- p->aOp[i].cnt = 0;
- p->aOp[i].cycles = 0;
+ if( p->aMem ){
+ p->aMem--; /* aMem[] goes from 1..nMem */
+ p->nMem = nMem; /* not from 0..nMem-1 */
+ for(n=1; n<=nMem; n++){
+ p->aMem[n].flags = MEM_Null;
+ p->aMem[n].db = db;
}
}
-#endif
+ p->explain = pParse->explain;
+ sqlite3VdbeRewind(p);
}
/*
-** Close a VDBE cursor and release all the resources that cursor
+** Close a VDBE cursor and release all the resources that cursor
** happens to hold.
*/
SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
if( pCx==0 ){
return;
}
+ sqlite3VdbeSorterClose(p->db, pCx);
if( pCx->pBt ){
sqlite3BtreeClose(pCx->pBt);
/* The pCx->pCursor will be close automatically, if it exists, by
@@ -49750,14 +59910,14 @@ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
/*
** Close all cursors.
**
-** Also release any dynamic memory held by the VM in the Vdbe.aMem memory
+** Also release any dynamic memory held by the VM in the Vdbe.aMem memory
** cell array. This is necessary as the memory cell array may contain
** pointers to VdbeFrame objects, which may in turn contain pointers to
** open cursors.
*/
static void closeAllCursors(Vdbe *p){
if( p->pFrame ){
- VdbeFrame *pFrame = p->pFrame;
+ VdbeFrame *pFrame;
for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
sqlite3VdbeFrameRestore(pFrame);
}
@@ -49777,6 +59937,11 @@ static void closeAllCursors(Vdbe *p){
if( p->aMem ){
releaseMemArray(&p->aMem[1], p->nMem);
}
+ while( p->pDelFrame ){
+ VdbeFrame *pDel = p->pDelFrame;
+ p->pDelFrame = pDel->pParent;
+ sqlite3VdbeFrameDelete(pDel);
+ }
}
/*
@@ -49790,7 +59955,7 @@ static void Cleanup(Vdbe *p){
sqlite3 *db = p->db;
#ifdef SQLITE_DEBUG
- /* Execute assert() statements to ensure that the Vdbe.apCsr[] and
+ /* Execute assert() statements to ensure that the Vdbe.apCsr[] and
** Vdbe.aMem[] arrays have already been cleaned up. */
int i;
for(i=0; inCursor; i++) assert( p->apCsr==0 || p->apCsr[i]==0 );
@@ -49871,36 +60036,37 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
int needXcommit = 0;
#ifdef SQLITE_OMIT_VIRTUALTABLE
- /* With this option, sqlite3VtabSync() is defined to be simply
- ** SQLITE_OK so p is not used.
+ /* With this option, sqlite3VtabSync() is defined to be simply
+ ** SQLITE_OK so p is not used.
*/
UNUSED_PARAMETER(p);
#endif
/* Before doing anything else, call the xSync() callback for any
** virtual module tables written in this transaction. This has to
- ** be done before determining whether a master journal file is
+ ** be done before determining whether a master journal file is
** required, as an xSync() callback may add an attached database
** to the transaction.
*/
rc = sqlite3VtabSync(db, &p->zErrMsg);
- if( rc!=SQLITE_OK ){
- return rc;
- }
/* This loop determines (a) if the commit hook should be invoked and
- ** (b) how many database files have open write transactions, not
- ** including the temp database. (b) is important because if more than
+ ** (b) how many database files have open write transactions, not
+ ** including the temp database. (b) is important because if more than
** one database file has an open write transaction, a master journal
** file is required for an atomic commit.
- */
- for(i=0; inDb; i++){
+ */
+ for(i=0; rc==SQLITE_OK && inDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( sqlite3BtreeIsInTrans(pBt) ){
needXcommit = 1;
if( i!=1 ) nTrans++;
+ rc = sqlite3PagerExclusiveLock(sqlite3BtreePager(pBt));
}
}
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
/* If there are any write-transactions at all, invoke the commit hook */
if( needXcommit && db->xCommitCallback ){
@@ -49915,8 +60081,8 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
** master-journal.
**
** If the return value of sqlite3BtreeGetFilename() is a zero length
- ** string, it means the main database is :memory: or a temp file. In
- ** that case we do not support atomic multi-file commits, so use the
+ ** string, it means the main database is :memory: or a temp file. In
+ ** that case we do not support atomic multi-file commits, so use the
** simple case then too.
*/
if( 0==sqlite3Strlen30(sqlite3BtreeGetFilename(db->aDb[0].pBt))
@@ -49929,7 +60095,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
}
}
- /* Do the commit only if all databases successfully complete phase 1.
+ /* Do the commit only if all databases successfully complete phase 1.
** If one of the BtreeCommitPhaseOne() calls fails, this indicates an
** IO error while deleting or truncating a journal file. It is unlikely,
** but could happen. In this case abandon processing and return the error.
@@ -49937,7 +60103,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
for(i=0; rc==SQLITE_OK && inDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
- rc = sqlite3BtreeCommitPhaseTwo(pBt);
+ rc = sqlite3BtreeCommitPhaseTwo(pBt, 0);
}
}
if( rc==SQLITE_OK ){
@@ -49968,11 +60134,12 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
if( !zMaster ){
return SQLITE_NOMEM;
}
+ sqlite3FileSuffix3(zMainFile, zMaster);
rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res);
}while( rc==SQLITE_OK && res );
if( rc==SQLITE_OK ){
/* Open the master journal. */
- rc = sqlite3OsOpenMalloc(pVfs, zMaster, &pMaster,
+ rc = sqlite3OsOpenMalloc(pVfs, zMaster, &pMaster,
SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_MASTER_JOURNAL, 0
);
@@ -49981,7 +60148,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
sqlite3DbFree(db, zMaster);
return rc;
}
-
+
/* Write the name of each database file in the transaction into the new
** master journal file. If an error occurs at this point close
** and delete the master journal file. All the individual journal files
@@ -49992,9 +60159,10 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
Btree *pBt = db->aDb[i].pBt;
if( sqlite3BtreeIsInTrans(pBt) ){
char const *zFile = sqlite3BtreeGetJournalname(pBt);
- if( zFile==0 || zFile[0]==0 ){
+ if( zFile==0 ){
continue; /* Ignore TEMP and :memory: databases */
}
+ assert( zFile[0]!=0 );
if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){
needSync = 1;
}
@@ -50012,7 +60180,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
/* Sync the master journal file. If the IOCAP_SEQUENTIAL device
** flag is set this is not required.
*/
- if( needSync
+ if( needSync
&& 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL)
&& SQLITE_OK!=(rc = sqlite3OsSync(pMaster, SQLITE_SYNC_NORMAL))
){
@@ -50032,13 +60200,14 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
** in case the master journal file name was written into the journal
** file before the failure occurred.
*/
- for(i=0; rc==SQLITE_OK && inDb; i++){
+ for(i=0; rc==SQLITE_OK && inDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
rc = sqlite3BtreeCommitPhaseOne(pBt, zMaster);
}
}
sqlite3OsCloseFree(pMaster);
+ assert( rc!=SQLITE_BUSY );
if( rc!=SQLITE_OK ){
sqlite3DbFree(db, zMaster);
return rc;
@@ -50064,10 +60233,10 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
*/
disable_simulated_io_errors();
sqlite3BeginBenignMalloc();
- for(i=0; inDb; i++){
+ for(i=0; inDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
- sqlite3BtreeCommitPhaseTwo(pBt);
+ sqlite3BtreeCommitPhaseTwo(pBt, 1);
}
}
sqlite3EndBenignMalloc();
@@ -50080,7 +60249,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
return rc;
}
-/*
+/*
** This routine checks that the sqlite3.activeVdbeCnt count variable
** matches the number of vdbe's in the list sqlite3.pVdbe that are
** currently active. An assertion fails if the two counts do not match.
@@ -50110,7 +60279,7 @@ static void checkActiveVdbeCnt(sqlite3 *db){
#endif
/*
-** For every Btree that in database connection db which
+** For every Btree that in database connection db which
** has been modified, "trip" or invalidate each cursor in
** that Btree might have been modified so that the cursor
** can never be used again. This happens when a rollback
@@ -50139,17 +60308,17 @@ static void invalidateCursorsOnModifiedBtrees(sqlite3 *db){
** If the Vdbe passed as the first argument opened a statement-transaction,
** close it now. Argument eOp must be either SAVEPOINT_ROLLBACK or
** SAVEPOINT_RELEASE. If it is SAVEPOINT_ROLLBACK, then the statement
-** transaction is rolled back. If eOp is SAVEPOINT_RELEASE, then the
+** transaction is rolled back. If eOp is SAVEPOINT_RELEASE, then the
** statement transaction is commtted.
**
-** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned.
+** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned.
** Otherwise SQLITE_OK.
*/
SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
sqlite3 *const db = p->db;
int rc = SQLITE_OK;
- /* If p->iStatement is greater than zero, then this Vdbe opened a
+ /* 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.
** In this case (db->nStatement==0), and there is nothing to do.
@@ -50162,7 +60331,7 @@ SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
assert( db->nStatement>0 );
assert( p->iStatement==(db->nStatement+db->nSavepoint) );
- for(i=0; inDb; i++){
+ for(i=0; inDb; i++){
int rc2 = SQLITE_OK;
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
@@ -50180,8 +60349,17 @@ SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
db->nStatement--;
p->iStatement = 0;
- /* If the statement transaction is being rolled back, also restore the
- ** database handles deferred constraint counter to the value it had when
+ if( rc==SQLITE_OK ){
+ if( eOp==SAVEPOINT_ROLLBACK ){
+ rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint);
+ }
+ }
+
+ /* If the statement transaction is being rolled back, also restore the
+ ** database handles deferred constraint counter to the value it had when
** the statement transaction was opened. */
if( eOp==SAVEPOINT_ROLLBACK ){
db->nDeferredCons = p->nStmtDefCons;
@@ -50191,39 +60369,12 @@ SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
}
/*
-** If SQLite is compiled to support shared-cache mode and to be threadsafe,
-** this routine obtains the mutex associated with each BtShared structure
-** that may be accessed by the VM passed as an argument. In doing so it
-** sets the BtShared.db member of each of the BtShared structures, ensuring
-** that the correct busy-handler callback is invoked if required.
-**
-** If SQLite is not threadsafe but does support shared-cache mode, then
-** sqlite3BtreeEnterAll() is invoked to set the BtShared.db variables
-** of all of BtShared structures accessible via the database handle
-** associated with the VM. Of course only a subset of these structures
-** will be accessed by the VM, and we could use Vdbe.btreeMask to figure
-** that subset out, but there is no advantage to doing so.
-**
-** If SQLite is not threadsafe and does not support shared-cache mode, this
-** function is a no-op.
-*/
-#ifndef SQLITE_OMIT_SHARED_CACHE
-SQLITE_PRIVATE void sqlite3VdbeMutexArrayEnter(Vdbe *p){
-#if SQLITE_THREADSAFE
- sqlite3BtreeMutexArrayEnter(&p->aMutex);
-#else
- sqlite3BtreeEnterAll(p->db);
-#endif
-}
-#endif
-
-/*
-** This function is called when a transaction opened by the database
-** handle associated with the VM passed as an argument is about to be
+** This function is called when a transaction opened by the database
+** handle associated with the VM passed as an argument is about to be
** committed. If there are outstanding deferred foreign key constraint
** violations, return SQLITE_ERROR. Otherwise, SQLITE_OK.
**
-** If there are outstanding FK violations and this function returns
+** 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.
*/
@@ -50259,7 +60410,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
/* This function contains the logic that determines if a statement or
** transaction will be committed or rolled back as a result of the
- ** execution of this virtual machine.
+ ** execution of this virtual machine.
**
** If any of the following errors occur:
**
@@ -50289,7 +60440,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
int isSpecialError; /* Set to true if a 'special' error */
/* Lock all btrees used by the statement */
- sqlite3VdbeMutexArrayEnter(p);
+ sqlite3VdbeEnter(p);
/* Check for one of the special errors */
mrc = p->rc & 0xff;
@@ -50297,8 +60448,17 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR
|| mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL;
if( isSpecialError ){
- /* If the query was read-only, we need do no rollback at all. Otherwise,
- ** proceed with the special handling.
+ /* If the query was read-only and the error code is SQLITE_INTERRUPT,
+ ** no rollback is necessary. Otherwise, at least a savepoint
+ ** transaction must be rolled back to restore the database to a
+ ** consistent state.
+ **
+ ** 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
+ ** 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.
*/
if( !p->readOnly || mrc!=SQLITE_INTERRUPT ){
if( (mrc==SQLITE_NOMEM || mrc==SQLITE_FULL) && p->usesStmtJournal ){
@@ -50319,29 +60479,34 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
if( p->rc==SQLITE_OK ){
sqlite3VdbeCheckFk(p, 0);
}
-
- /* If the auto-commit flag is set and this is the only active writer
- ** VM, then we do either a commit or rollback of the current transaction.
+
+ /* If the auto-commit flag is set and this is the only active writer
+ ** VM, then we do either a commit or rollback of the current transaction.
**
- ** Note: This block also runs if one of the special errors handled
- ** above has occurred.
+ ** Note: This block also runs if one of the special errors handled
+ ** above has occurred.
*/
- if( !sqlite3VtabInSync(db)
- && db->autoCommit
- && db->writeVdbeCnt==(p->readOnly==0)
+ if( !sqlite3VtabInSync(db)
+ && db->autoCommit
+ && db->writeVdbeCnt==(p->readOnly==0)
){
if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
- if( sqlite3VdbeCheckFk(p, 1) ){
- sqlite3BtreeMutexArrayLeave(&p->aMutex);
- return SQLITE_ERROR;
+ rc = sqlite3VdbeCheckFk(p, 1);
+ if( rc!=SQLITE_OK ){
+ if( NEVER(p->readOnly) ){
+ sqlite3VdbeLeave(p);
+ return SQLITE_ERROR;
+ }
+ rc = SQLITE_CONSTRAINT;
+ }else{
+ /* The auto-commit flag is true, the vdbe program was successful
+ ** or hit an 'OR FAIL' constraint and there are no deferred foreign
+ ** key constraints to hold up the transaction. This means a commit
+ ** is required. */
+ rc = vdbeCommit(db, p);
}
- /* The auto-commit flag is true, the vdbe program was successful
- ** or hit an 'OR FAIL' constraint and there are no deferred foreign
- ** key constraints to hold up the transaction. This means a commit
- ** is required. */
- rc = vdbeCommit(db, p);
- if( rc==SQLITE_BUSY ){
- sqlite3BtreeMutexArrayLeave(&p->aMutex);
+ if( rc==SQLITE_BUSY && p->readOnly ){
+ sqlite3VdbeLeave(p);
return SQLITE_BUSY;
}else if( rc!=SQLITE_OK ){
p->rc = rc;
@@ -50366,29 +60531,30 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
db->autoCommit = 1;
}
}
-
+
/* If eStatementOp is non-zero, then a statement transaction needs to
** be committed or rolled back. Call sqlite3VdbeCloseStatement() to
** do so. If this operation returns an error, and the current statement
** error code is SQLITE_OK or SQLITE_CONSTRAINT, then promote the
** current statement error code.
- **
- ** Note that sqlite3VdbeCloseStatement() can only fail if eStatementOp
- ** is SAVEPOINT_ROLLBACK. But if p->rc==SQLITE_OK then eStatementOp
- ** must be SAVEPOINT_RELEASE. Hence the NEVER(p->rc==SQLITE_OK) in
- ** the following code.
*/
if( eStatementOp ){
rc = sqlite3VdbeCloseStatement(p, eStatementOp);
- if( rc && (NEVER(p->rc==SQLITE_OK) || p->rc==SQLITE_CONSTRAINT) ){
- p->rc = rc;
- sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = 0;
+ if( rc ){
+ if( p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT ){
+ p->rc = rc;
+ sqlite3DbFree(db, p->zErrMsg);
+ p->zErrMsg = 0;
+ }
+ invalidateCursorsOnModifiedBtrees(db);
+ sqlite3RollbackAll(db);
+ sqlite3CloseSavepoints(db);
+ db->autoCommit = 1;
}
}
-
+
/* If this was an INSERT, UPDATE or DELETE and no statement transaction
- ** has been rolled back, update the database connection change-counter.
+ ** has been rolled back, update the database connection change-counter.
*/
if( p->changeCntOn ){
if( eStatementOp!=SAVEPOINT_ROLLBACK ){
@@ -50398,15 +60564,15 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
}
p->nChange = 0;
}
-
+
/* Rollback or commit any schema changes that occurred. */
if( p->rc!=SQLITE_OK && db->flags&SQLITE_InternChanges ){
- sqlite3ResetInternalSchema(db, 0);
+ sqlite3ResetInternalSchema(db, -1);
db->flags = (db->flags | SQLITE_InternChanges);
}
/* Release the locks */
- sqlite3BtreeMutexArrayLeave(&p->aMutex);
+ sqlite3VdbeLeave(p);
}
/* We have successfully halted and closed the VM. Record this fact. */
@@ -50424,7 +60590,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
}
/* If the auto-commit flag is set to true, then any locks that were held
- ** by connection db have now been released. Call sqlite3ConnectionUnlocked()
+ ** by connection db have now been released. Call sqlite3ConnectionUnlocked()
** to invoke any required unlock-notify callbacks.
*/
if( db->autoCommit ){
@@ -50432,7 +60598,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
}
assert( db->activeVdbeCnt>0 || db->autoCommit==0 || db->nStatement==0 );
- return SQLITE_OK;
+ return (p->rc==SQLITE_BUSY ? SQLITE_BUSY : SQLITE_OK);
}
@@ -50526,7 +60692,7 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
p->magic = VDBE_MAGIC_INIT;
return p->rc & db->errMask;
}
-
+
/*
** Clean up and delete a VDBE after execution. Return an integer which is
** the result code. Write any error message text into *pzErrMsg.
@@ -50560,6 +60726,32 @@ SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(VdbeFunc *pVdbeFunc, int mask){
}
}
+/*
+** Free all memory associated with the Vdbe passed as the second argument.
+** The difference between this function and sqlite3VdbeDelete() is that
+** VdbeDelete() also unlinks the Vdbe from the list of VMs associated with
+** the database connection.
+*/
+SQLITE_PRIVATE void sqlite3VdbeDeleteObject(sqlite3 *db, Vdbe *p){
+ SubProgram *pSub, *pNext;
+ int i;
+ assert( p->db==0 || p->db==db );
+ releaseMemArray(p->aVar, p->nVar);
+ releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
+ for(pSub=p->pProgram; pSub; pSub=pNext){
+ pNext = pSub->pNext;
+ vdbeFreeOpArray(db, pSub->aOp, pSub->nOp);
+ sqlite3DbFree(db, pSub);
+ }
+ for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]);
+ vdbeFreeOpArray(db, p->aOp, p->nOp);
+ sqlite3DbFree(db, p->aLabel);
+ sqlite3DbFree(db, p->aColName);
+ sqlite3DbFree(db, p->zSql);
+ sqlite3DbFree(db, p->pFree);
+ sqlite3DbFree(db, p);
+}
+
/*
** Delete an entire VDBE.
*/
@@ -50577,16 +60769,9 @@ SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){
if( p->pNext ){
p->pNext->pPrev = p->pPrev;
}
- releaseMemArray(p->aVar, p->nVar);
- releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
- vdbeFreeOpArray(db, p->aOp, p->nOp);
- sqlite3DbFree(db, p->aLabel);
- sqlite3DbFree(db, p->aColName);
- sqlite3DbFree(db, p->zSql);
p->magic = VDBE_MAGIC_DEAD;
- sqlite3DbFree(db, p->pFree);
p->db = 0;
- sqlite3DbFree(db, p);
+ sqlite3VdbeDeleteObject(db, p);
}
/*
@@ -50612,11 +60797,8 @@ SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor *p){
rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res);
if( rc ) return rc;
p->lastRowid = p->movetoTarget;
- p->rowidIsValid = ALWAYS(res==0) ?1:0;
- if( NEVER(res<0) ){
- rc = sqlite3BtreeNext(p->pCursor, &res);
- if( rc ) return rc;
- }
+ if( res!=0 ) return SQLITE_CORRUPT_BKPT;
+ p->rowidIsValid = 1;
#ifdef SQLITE_TEST
sqlite3_search_count++;
#endif
@@ -50694,7 +60876,13 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
if( file_format>=4 && (i&1)==i ){
return 8+(u32)i;
}
- u = i<0 ? -i : i;
+ if( i<0 ){
+ if( i<(-MAX_6BYTE) ) return 6;
+ /* Previous test prevents: u = -(-9223372036854775808) */
+ u = -i;
+ }else{
+ u = i;
+ }
if( u<=127 ) return 1;
if( u<=32767 ) return 2;
if( u<=8388607 ) return 3;
@@ -50727,8 +60915,8 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32 serial_type){
}
/*
-** If we are on an architecture with mixed-endian floating
-** points (ex: ARM7) then swap the lower 4 bytes with the
+** If we are on an architecture with mixed-endian floating
+** points (ex: ARM7) then swap the lower 4 bytes with the
** upper 4 bytes. Return the result.
**
** For most architectures, this is a no-op.
@@ -50750,7 +60938,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32 serial_type){
** (2007-08-30) Frank van Vugt has studied this problem closely
** and has send his findings to the SQLite developers. Frank
** writes that some Linux kernels offer floating point hardware
-** emulation that uses only 32-bit mantissas instead of a full
+** emulation that uses only 32-bit mantissas instead of a full
** 48-bits as required by the IEEE standard. (This is the
** CONFIG_FPE_FASTFPE option.) On such systems, floating point
** byte swapping becomes very complicated. To avoid problems,
@@ -50780,7 +60968,7 @@ static u64 floatSwap(u64 in){
#endif
/*
-** Write the serialized data blob for the value stored in pMem into
+** Write the serialized data blob for the value stored in pMem into
** buf. It is assumed that the caller has allocated sufficient space.
** Return the number of bytes written.
**
@@ -50796,7 +60984,7 @@ static u64 floatSwap(u64 in){
** Return the number of bytes actually written into buf[]. The number
** of bytes in the zero-filled tail is included in the return value only
** if those bytes were zeroed in buf[].
-*/
+*/
SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, int nBuf, Mem *pMem, int file_format){
u32 serial_type = sqlite3VdbeSerialType(pMem, file_format);
u32 len;
@@ -50846,7 +61034,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, int nBuf, Mem *pMem, int file_f
/*
** Deserialize the data blob pointed to by buf as serial type serial_type
** and store the result in pMem. Return the number of bytes read.
-*/
+*/
SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
const unsigned char *buf, /* Buffer to deserialize from */
u32 serial_type, /* Serial type to deserialize */
@@ -50940,57 +61128,70 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
return 0;
}
-
/*
-** Given the nKey-byte encoding of a record in pKey[], parse the
-** record into a UnpackedRecord structure. Return a pointer to
-** that structure.
+** This routine is used to allocate sufficient space for an UnpackedRecord
+** structure large enough to be used with sqlite3VdbeRecordUnpack() if
+** the first argument is a pointer to KeyInfo structure pKeyInfo.
**
-** The calling function might provide szSpace bytes of memory
-** space at pSpace. This space can be used to hold the returned
-** VDbeParsedRecord structure if it is large enough. If it is
-** not big enough, space is obtained from sqlite3_malloc().
+** The space is either allocated using sqlite3DbMallocRaw() or from within
+** the unaligned buffer passed via the second and third arguments (presumably
+** stack space). If the former, then *ppFree is set to a pointer that should
+** be eventually freed by the caller using sqlite3DbFree(). Or, if the
+** allocation comes from the pSpace/szSpace buffer, *ppFree is set to NULL
+** before returning.
**
-** The returned structure should be closed by a call to
-** sqlite3VdbeDeleteUnpackedRecord().
+** If an OOM error occurs, NULL is returned.
*/
-SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeRecordUnpack(
- KeyInfo *pKeyInfo, /* Information about the record format */
- int nKey, /* Size of the binary record */
- const void *pKey, /* The binary record */
- char *pSpace, /* Unaligned space available to hold the object */
- int szSpace /* Size of pSpace[] in bytes */
+SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(
+ KeyInfo *pKeyInfo, /* Description of the record */
+ char *pSpace, /* Unaligned space available */
+ int szSpace, /* Size of pSpace[] in bytes */
+ char **ppFree /* OUT: Caller should free this pointer */
){
- const unsigned char *aKey = (const unsigned char *)pKey;
- UnpackedRecord *p; /* The unpacked record that we will return */
- int nByte; /* Memory space needed to hold p, in bytes */
- int d;
- u32 idx;
- u16 u; /* Unsigned loop counter */
- u32 szHdr;
- Mem *pMem;
- int nOff; /* Increase pSpace by this much to 8-byte align it */
+ UnpackedRecord *p; /* Unpacked record to return */
+ int nOff; /* Increment pSpace by nOff to align it */
+ int nByte; /* Number of bytes required for *p */
- /*
- ** We want to shift the pointer pSpace up such that it is 8-byte aligned.
- ** Thus, we need to calculate a value, nOff, between 0 and 7, to shift
+ /* We want to shift the pointer pSpace up such that it is 8-byte aligned.
+ ** Thus, we need to calculate a value, nOff, between 0 and 7, to shift
** it by. If pSpace is already 8-byte aligned, nOff should be zero.
*/
nOff = (8 - (SQLITE_PTR_TO_INT(pSpace) & 7)) & 7;
- pSpace += nOff;
- szSpace -= nOff;
nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nField+1);
- if( nByte>szSpace ){
- p = sqlite3DbMallocRaw(pKeyInfo->db, nByte);
- if( p==0 ) return 0;
- p->flags = UNPACKED_NEED_FREE | UNPACKED_NEED_DESTROY;
+ if( nByte>szSpace+nOff ){
+ p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte);
+ *ppFree = (char *)p;
+ if( !p ) return 0;
}else{
- p = (UnpackedRecord*)pSpace;
- p->flags = UNPACKED_NEED_DESTROY;
+ p = (UnpackedRecord*)&pSpace[nOff];
+ *ppFree = 0;
}
+
+ p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))];
p->pKeyInfo = pKeyInfo;
p->nField = pKeyInfo->nField + 1;
- p->aMem = pMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))];
+ return p;
+}
+
+/*
+** Given the nKey-byte encoding of a record in pKey[], populate the
+** UnpackedRecord structure indicated by the fourth argument with the
+** contents of the decoded record.
+*/
+SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(
+ KeyInfo *pKeyInfo, /* Information about the record format */
+ int nKey, /* Size of the binary record */
+ const void *pKey, /* The binary record */
+ UnpackedRecord *p /* Populate this structure before returning. */
+){
+ const unsigned char *aKey = (const unsigned char *)pKey;
+ int d;
+ u32 idx; /* Offset in aKey[] to read from */
+ u16 u; /* Unsigned loop counter */
+ u32 szHdr;
+ Mem *pMem = p->aMem;
+
+ p->flags = 0;
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
idx = getVarint32(aKey, szHdr);
d = szHdr;
@@ -51001,7 +61202,7 @@ SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeRecordUnpack(
idx += getVarint32(&aKey[idx], serial_type);
pMem->enc = pKeyInfo->enc;
pMem->db = pKeyInfo->db;
- pMem->flags = 0;
+ /* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */
pMem->zMalloc = 0;
d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem);
pMem++;
@@ -51009,42 +61210,19 @@ SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeRecordUnpack(
}
assert( u<=pKeyInfo->nField + 1 );
p->nField = u;
- return (void*)p;
-}
-
-/*
-** This routine destroys a UnpackedRecord object.
-*/
-SQLITE_PRIVATE void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){
- int i;
- Mem *pMem;
-
- assert( p!=0 );
- assert( p->flags & UNPACKED_NEED_DESTROY );
- for(i=0, pMem=p->aMem; inField; i++, pMem++){
- /* The unpacked record is always constructed by the
- ** sqlite3VdbeUnpackRecord() function above, which makes all
- ** strings and blobs static. And none of the elements are
- ** ever transformed, so there is never anything to delete.
- */
- if( NEVER(pMem->zMalloc) ) sqlite3VdbeMemRelease(pMem);
- }
- if( p->flags & UNPACKED_NEED_FREE ){
- sqlite3DbFree(p->pKeyInfo->db, p);
- }
}
/*
** This function compares the two table rows or index records
** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero
-** or positive integer if key1 is less than, equal to or
+** or positive integer if key1 is less than, equal to or
** greater than key2. The {nKey1, pKey1} key must be a blob
** created by th OP_MakeRecord opcode of the VDBE. The pPKey2
** key must be a parsed key such as obtained from
** sqlite3VdbeParseRecord.
**
** Key1 and Key2 do not have to contain the same number of fields.
-** The key with fewer fields is usually compares less than the
+** The key with fewer fields is usually compares less than the
** longer key. However if the UNPACKED_INCRKEY flags in pPKey2 is set
** and the common prefixes are equal, then key1 is less than key2.
** Or if the UNPACKED_MATCH_PREFIX flag is set and the prefixes are
@@ -51082,13 +61260,13 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
/* Compilers may complain that mem1.u.i is potentially uninitialized.
** We could initialize it, as shown here, to silence those complaints.
- ** But in fact, mem1.u.i will never actually be used initialized, and doing
+ ** But in fact, mem1.u.i will never actually be used uninitialized, and doing
** the unnecessary initialization has a measurable negative performance
** impact, since this routine is a very high runner. And so, we choose
** to ignore the compiler warnings and leave this variable uninitialized.
*/
/* mem1.u.i = 0; // not needed, here to silence compiler warning */
-
+
idx1 = getVarint32(aKey1, szHdr1);
d1 = szHdr1;
if( pPKey2->flags & UNPACKED_IGNORE_ROWID ){
@@ -51117,9 +61295,9 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
if( pKeyInfo->aSortOrder && iaSortOrder[i] ){
rc = -rc;
}
-
+
/* If the PREFIX_SEARCH flag is set and all fields except the final
- ** rowid field were equal, then clear the PREFIX_SEARCH flag and set
+ ** rowid field were equal, then clear the PREFIX_SEARCH flag and set
** pPKey2->rowid to the value of the rowid field in (pKey1, nKey1).
** This is used by the OP_IsUnique opcode.
*/
@@ -51129,7 +61307,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
pPKey2->flags &= ~UNPACKED_PREFIX_SEARCH;
pPKey2->rowid = mem1.u.i;
}
-
+
return rc;
}
i++;
@@ -51145,7 +61323,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
** all the fields up to that point were equal. If the UNPACKED_INCRKEY
** flag is set, then break the tie by treating key2 as larger.
** If the UPACKED_PREFIX_MATCH flag is set, then keys with common prefixes
- ** are considered to be equal. Otherwise, the longer key is the
+ ** are considered to be equal. Otherwise, the longer key is the
** larger. As it happens, the pPKey2 will always be the longer
** if there is a difference.
*/
@@ -51159,7 +61337,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
}
return rc;
}
-
+
/*
** pCur points at an index entry created using the OP_MakeRecord opcode.
@@ -51182,7 +61360,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
/* Get the size of the index entry. Only indices entries of less
** than 2GiB are support - anything large must be database corruption.
** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so
- ** this code can safely assume that nCellKey is 32-bits
+ ** this code can safely assume that nCellKey is 32-bits
*/
assert( sqlite3BtreeCursorIsValid(pCur) );
rc = sqlite3BtreeKeySize(pCur, &nCellKey);
@@ -51246,7 +61424,7 @@ idx_rowid_corruption:
**
** pUnpacked is either created without a rowid or is truncated so that it
** omits the rowid at the end. The rowid at the end of the index entry
-** is ignored as well. Hence, this routine only compares the prefixes
+** is ignored as well. Hence, this routine only compares the prefixes
** of the keys prior to the final rowid, not the entire key.
*/
SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
@@ -51281,7 +61459,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
/*
** This routine sets the value to be returned by subsequent calls to
-** sqlite3_changes() on the database handle 'db'.
+** sqlite3_changes() on the database handle 'db'.
*/
SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *db, int nChange){
assert( sqlite3_mutex_held(db->mutex) );
@@ -51323,7 +61501,7 @@ SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe *v){
/*
** Return a pointer to an sqlite3_value structure containing the value bound
-** parameter iVar of VM v. Except, if the value is an SQL NULL, return
+** parameter iVar of VM v. Except, if the value is an SQL NULL, return
** 0 instead. Unless it is NULL, apply affinity aff (one of the SQLITE_AFF_*
** constants) to the value before returning it.
**
@@ -51427,6 +61605,8 @@ static int vdbeSafetyNotNull(Vdbe *p){
SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt){
int rc;
if( pStmt==0 ){
+ /* IMPLEMENTATION-OF: R-57228-12904 Invoking sqlite3_finalize() on a NULL
+ ** pointer is a harmless no-op. */
rc = SQLITE_OK;
}else{
Vdbe *v = (Vdbe*)pStmt;
@@ -51462,7 +61642,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt){
Vdbe *v = (Vdbe*)pStmt;
sqlite3_mutex_enter(v->db->mutex);
rc = sqlite3VdbeReset(v);
- sqlite3VdbeMakeReady(v, -1, 0, 0, 0, 0, 0);
+ sqlite3VdbeRewind(v);
assert( (rc & (v->db->errMask))==rc );
rc = sqlite3ApiExit(v->db, rc);
sqlite3_mutex_leave(v->db->mutex);
@@ -51503,7 +61683,7 @@ SQLITE_API const void *sqlite3_value_blob(sqlite3_value *pVal){
sqlite3VdbeMemExpandBlob(p);
p->flags &= ~MEM_Str;
p->flags |= MEM_Blob;
- return p->z;
+ return p->n ? p->z : 0;
}else{
return sqlite3_value_text(pVal);
}
@@ -51561,9 +61741,9 @@ static void setResultStrOrError(
}
}
SQLITE_API void sqlite3_result_blob(
- sqlite3_context *pCtx,
- const void *z,
- int n,
+ sqlite3_context *pCtx,
+ const void *z,
+ int n,
void (*xDel)(void *)
){
assert( n>=0 );
@@ -51599,8 +61779,8 @@ SQLITE_API void sqlite3_result_null(sqlite3_context *pCtx){
sqlite3VdbeMemSetNull(&pCtx->s);
}
SQLITE_API void sqlite3_result_text(
- sqlite3_context *pCtx,
- const char *z,
+ sqlite3_context *pCtx,
+ const char *z,
int n,
void (*xDel)(void *)
){
@@ -51609,27 +61789,27 @@ SQLITE_API void sqlite3_result_text(
}
#ifndef SQLITE_OMIT_UTF16
SQLITE_API void sqlite3_result_text16(
- sqlite3_context *pCtx,
- const void *z,
- int n,
+ sqlite3_context *pCtx,
+ const void *z,
+ int n,
void (*xDel)(void *)
){
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel);
}
SQLITE_API void sqlite3_result_text16be(
- sqlite3_context *pCtx,
- const void *z,
- int n,
+ sqlite3_context *pCtx,
+ const void *z,
+ int n,
void (*xDel)(void *)
){
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel);
}
SQLITE_API void sqlite3_result_text16le(
- sqlite3_context *pCtx,
- const void *z,
- int n,
+ sqlite3_context *pCtx,
+ const void *z,
+ int n,
void (*xDel)(void *)
){
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
@@ -51647,7 +61827,7 @@ SQLITE_API void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
pCtx->isError = errCode;
if( pCtx->s.flags & MEM_Null ){
- sqlite3VdbeMemSetStr(&pCtx->s, sqlite3ErrStr(errCode), -1,
+ sqlite3VdbeMemSetStr(&pCtx->s, sqlite3ErrStr(errCode), -1,
SQLITE_UTF8, SQLITE_STATIC);
}
}
@@ -51656,7 +61836,7 @@ SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
pCtx->isError = SQLITE_TOOBIG;
- sqlite3VdbeMemSetStr(&pCtx->s, "string or blob too big", -1,
+ sqlite3VdbeMemSetStr(&pCtx->s, "string or blob too big", -1,
SQLITE_UTF8, SQLITE_STATIC);
}
@@ -51668,12 +61848,33 @@ SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){
pCtx->s.db->mallocFailed = 1;
}
+/*
+** This function is called after a transaction has been committed. It
+** invokes callbacks registered with sqlite3_wal_hook() as required.
+*/
+static int doWalCallbacks(sqlite3 *db){
+ int rc = SQLITE_OK;
+#ifndef SQLITE_OMIT_WAL
+ int i;
+ for(i=0; inDb; i++){
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ){
+ int nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
+ if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
+ rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry);
+ }
+ }
+ }
+#endif
+ return rc;
+}
+
/*
** Execute the statement pStmt, either until a row of data is ready, the
** statement is completely executed or an error occurs.
**
** This routine implements the bulk of the logic behind the sqlite_step()
-** API. The only thing omitted is the automatic recompile if a
+** API. The only thing omitted is the automatic recompile if a
** schema change has occurred. That detail is handled by the
** outer sqlite3_step() wrapper procedure.
*/
@@ -51683,9 +61884,31 @@ static int sqlite3Step(Vdbe *p){
assert(p);
if( p->magic!=VDBE_MAGIC_RUN ){
- sqlite3_log(SQLITE_MISUSE,
- "attempt to step a halted statement: [%s]", p->zSql);
- return SQLITE_MISUSE_BKPT;
+ /* We used to require that sqlite3_reset() be called before retrying
+ ** sqlite3_step() after any error or after SQLITE_DONE. But beginning
+ ** with version 3.7.0, we changed this so that sqlite3_reset() would
+ ** be called automatically instead of throwing the SQLITE_MISUSE error.
+ ** This "automatic-reset" change is not technically an incompatibility,
+ ** since any application that receives an SQLITE_MISUSE is broken by
+ ** definition.
+ **
+ ** Nevertheless, some published applications that were originally written
+ ** for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE
+ ** returns, and the so were broken by the automatic-reset change. As a
+ ** a work-around, the SQLITE_OMIT_AUTORESET compile-time restores the
+ ** legacy behavior of returning SQLITE_MISUSE for cases where the
+ ** previous sqlite3_step() returned something other than a SQLITE_LOCKED
+ ** or SQLITE_BUSY error.
+ */
+#ifdef SQLITE_OMIT_AUTORESET
+ if( p->rc==SQLITE_BUSY || p->rc==SQLITE_LOCKED ){
+ sqlite3_reset((sqlite3_stmt*)p);
+ }else{
+ return SQLITE_MISUSE_BKPT;
+ }
+#else
+ sqlite3_reset((sqlite3_stmt*)p);
+#endif
}
/* Check that malloc() has not failed. If it has, return early. */
@@ -51713,9 +61936,7 @@ static int sqlite3Step(Vdbe *p){
#ifndef SQLITE_OMIT_TRACE
if( db->xProfile && !db->init.busy ){
- double rNow;
- sqlite3OsCurrentTime(db->pVfs, &rNow);
- p->startTime = (u64)((rNow - (int)rNow)*3600.0*24.0*1000000000.0);
+ sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
}
#endif
@@ -51729,36 +61950,42 @@ static int sqlite3Step(Vdbe *p){
}else
#endif /* SQLITE_OMIT_EXPLAIN */
{
+ db->vdbeExecCnt++;
rc = sqlite3VdbeExec(p);
+ db->vdbeExecCnt--;
}
#ifndef SQLITE_OMIT_TRACE
/* Invoke the profile callback if there is one
*/
if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy && p->zSql ){
- double rNow;
- u64 elapseTime;
-
- sqlite3OsCurrentTime(db->pVfs, &rNow);
- elapseTime = (u64)((rNow - (int)rNow)*3600.0*24.0*1000000000.0);
- elapseTime -= p->startTime;
- db->xProfile(db->pProfileArg, p->zSql, elapseTime);
+ sqlite3_int64 iNow;
+ sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
+ db->xProfile(db->pProfileArg, p->zSql, (iNow - p->startTime)*1000000);
}
#endif
+ if( rc==SQLITE_DONE ){
+ assert( p->rc==SQLITE_OK );
+ p->rc = doWalCallbacks(db);
+ if( p->rc!=SQLITE_OK ){
+ rc = SQLITE_ERROR;
+ }
+ }
+
db->errCode = rc;
if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){
p->rc = SQLITE_NOMEM;
}
end_of_step:
- /* At this point local variable rc holds the value that should be
- ** returned if this statement was compiled using the legacy
+ /* At this point local variable rc holds the value that should be
+ ** returned if this statement was compiled using the legacy
** sqlite3_prepare() interface. According to the docs, this can only
- ** be one of the values in the first assert() below. Variable p->rc
- ** contains the value that would be returned if sqlite3_finalize()
+ ** be one of the values in the first assert() below. Variable p->rc
+ ** contains the value that would be returned if sqlite3_finalize()
** were called on statement p.
*/
- assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR
+ assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR
|| rc==SQLITE_BUSY || rc==SQLITE_MISUSE
);
assert( p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE );
@@ -51766,12 +61993,20 @@ end_of_step:
/* If this statement was prepared using sqlite3_prepare_v2(), and an
** error has occured, then return the error code in p->rc to the
** caller. Set the error code in the database handle to the same value.
- */
+ */
rc = db->errCode = p->rc;
}
return (rc&db->errMask);
}
+/*
+** 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,
@@ -51790,21 +62025,21 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
db = v->db;
sqlite3_mutex_enter(db->mutex);
while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
- && cnt++ < 5
+ && cnt++ < SQLITE_MAX_SCHEMA_RETRY
&& (rc2 = rc = sqlite3Reprepare(v))==SQLITE_OK ){
sqlite3_reset(pStmt);
- v->expired = 0;
+ assert( v->expired==0 );
}
if( rc2!=SQLITE_OK && ALWAYS(v->isPrepareV2) && ALWAYS(db->pErr) ){
- /* This case occurs after failing to recompile an sql statement.
- ** The error message from the SQL compiler has already been loaded
- ** into the database handle. This block copies the error message
+ /* This case occurs after failing to recompile an sql statement.
+ ** The error message from the SQL compiler has already been loaded
+ ** into the database handle. This block copies the error message
** from the database handle into the statement and sets the statement
- ** program counter to 0 to ensure that when the statement is
+ ** program counter to 0 to ensure that when the statement is
** finalized or reset the parser error message is available via
** sqlite3_errmsg() and sqlite3_errcode().
*/
- const char *zErr = (const char *)sqlite3_value_text(db->pErr);
+ const char *zErr = (const char *)sqlite3_value_text(db->pErr);
sqlite3DbFree(db, v->zErrMsg);
if( !db->mallocFailed ){
v->zErrMsg = sqlite3DbStrDup(db, zErr);
@@ -51831,6 +62066,12 @@ SQLITE_API void *sqlite3_user_data(sqlite3_context *p){
/*
** Extract the user data from a sqlite3_context structure and return a
** pointer to it.
+**
+** IMPLEMENTATION-OF: R-46798-50301 The sqlite3_context_db_handle() interface
+** returns a copy of the pointer to the database connection (the 1st
+** parameter) of the sqlite3_create_function() and
+** sqlite3_create_function16() routines that originally registered the
+** application defined function.
*/
SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
assert( p && p->pFunc );
@@ -51908,9 +62149,9 @@ SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
** deleted by calling the delete function specified when it was set.
*/
SQLITE_API void sqlite3_set_auxdata(
- sqlite3_context *pCtx,
- int iArg,
- void *pAux,
+ sqlite3_context *pCtx,
+ int iArg,
+ void *pAux,
void (*xDelete)(void*)
){
struct AuxData *pAuxData;
@@ -51948,7 +62189,7 @@ failed:
#ifndef SQLITE_OMIT_DEPRECATED
/*
-** Return the number of times the Step function of a aggregate has been
+** Return the number of times the Step function of a aggregate has been
** called.
**
** This function is deprecated. Do not use it for new code. It is
@@ -51989,13 +62230,11 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt){
*/
static Mem *columnMem(sqlite3_stmt *pStmt, int i){
Vdbe *pVm;
- int vals;
Mem *pOut;
pVm = (Vdbe *)pStmt;
if( pVm && pVm->pResultSet!=0 && inResColumn && i>=0 ){
sqlite3_mutex_enter(pVm->db->mutex);
- vals = sqlite3_data_count(pStmt);
pOut = &pVm->pResultSet[i];
}else{
/* If the value passed as the second argument is out of range, return
@@ -52009,11 +62248,15 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
** this assert() from failing, when building with SQLITE_DEBUG defined
** using gcc, force nullMem to be 8-byte aligned using the magical
** __attribute__((aligned(8))) macro. */
- static const Mem nullMem
+ static const Mem nullMem
#if defined(SQLITE_DEBUG) && defined(__GNUC__)
- __attribute__((aligned(8)))
+ __attribute__((aligned(8)))
#endif
- = {{0}, (double)0, 0, "", 0, MEM_Null, SQLITE_NULL, 0, 0, 0 };
+ = {0, "", (double)0, {0}, 0, MEM_Null, SQLITE_NULL, 0,
+#ifdef SQLITE_DEBUG
+ 0, 0, /* pScopyFrom, pFiller */
+#endif
+ 0, 0 };
if( pVm && ALWAYS(pVm->db) ){
sqlite3_mutex_enter(pVm->db->mutex);
@@ -52025,9 +62268,9 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
}
/*
-** This function is called after invoking an sqlite3_value_XXX function on a
+** This function is called after invoking an sqlite3_value_XXX function on a
** column value (i.e. a value returned by evaluating an SQL expression in the
-** select list of a SELECT statement) that may cause a malloc() failure. If
+** select list of a SELECT statement) that may cause a malloc() failure. If
** malloc() has failed, the threads mallocFailed flag is cleared and the result
** code of statement pStmt set to SQLITE_NOMEM.
**
@@ -52040,8 +62283,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
** sqlite3_column_real()
** sqlite3_column_bytes()
** sqlite3_column_bytes16()
-**
-** But not for sqlite3_column_blob(), which never calls malloc().
+** sqiite3_column_blob()
*/
static void columnMallocFailure(sqlite3_stmt *pStmt)
{
@@ -52065,8 +62307,8 @@ SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
const void *val;
val = sqlite3_value_blob( columnMem(pStmt,i) );
/* Even though there is no encoding conversion, value_blob() might
- ** need to call malloc() to expand the result of a zeroblob()
- ** expression.
+ ** need to call malloc() to expand the result of a zeroblob()
+ ** expression.
*/
columnMallocFailure(pStmt);
return val;
@@ -52156,7 +62398,7 @@ static const void *columnName(
Vdbe *p = (Vdbe *)pStmt;
int n;
sqlite3 *db = p->db;
-
+
assert( db!=0 );
n = sqlite3_column_count(pStmt);
if( N=0 ){
@@ -52269,11 +62511,11 @@ SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
/******************************* sqlite3_bind_ ***************************
-**
+**
** Routines used to attach values to wildcards in a compiled SQL statement.
*/
/*
-** Unbind the value bound to variable i in virtual machine p. This is the
+** Unbind the value bound to variable i in virtual machine p. This is the
** the same as binding a NULL value to the column. If the "i" parameter is
** out of range, then SQLITE_RANGE is returned. Othewise SQLITE_OK.
**
@@ -52292,7 +62534,7 @@ static int vdbeUnbind(Vdbe *p, int i){
if( p->magic!=VDBE_MAGIC_RUN || p->pc>=0 ){
sqlite3Error(p->db, SQLITE_MISUSE, 0);
sqlite3_mutex_leave(p->db->mutex);
- sqlite3_log(SQLITE_MISUSE,
+ sqlite3_log(SQLITE_MISUSE,
"bind on a busy prepared statement: [%s]", p->zSql);
return SQLITE_MISUSE_BKPT;
}
@@ -52307,8 +62549,14 @@ static int vdbeUnbind(Vdbe *p, int i){
pVar->flags = MEM_Null;
sqlite3Error(p->db, SQLITE_OK, 0);
- /* If the bit corresponding to this variable in Vdbe.expmask is set, then
+ /* If the bit corresponding to this variable in Vdbe.expmask is set, then
** binding a new value to this variable invalidates the current query plan.
+ **
+ ** IMPLEMENTATION-OF: R-48440-37595 If the specific value bound to host
+ ** parameter in the WHERE clause might influence the choice of query plan
+ ** for a statement, then the statement will be automatically recompiled,
+ ** as if there had been a schema change, on the first sqlite3_step() call
+ ** following any change to the bindings of that parameter.
*/
if( p->isPrepareV2 &&
((i<32 && p->expmask & ((u32)1 << i)) || p->expmask==0xffffffff)
@@ -52345,6 +62593,8 @@ static int bindText(
rc = sqlite3ApiExit(p->db, rc);
}
sqlite3_mutex_leave(p->db->mutex);
+ }else if( xDel!=SQLITE_STATIC && xDel!=SQLITE_TRANSIENT ){
+ xDel((void*)zData);
}
return rc;
}
@@ -52354,10 +62604,10 @@ static int bindText(
** Bind a blob value to an SQL statement variable.
*/
SQLITE_API int sqlite3_bind_blob(
- sqlite3_stmt *pStmt,
- int i,
- const void *zData,
- int nData,
+ sqlite3_stmt *pStmt,
+ int i,
+ const void *zData,
+ int nData,
void (*xDel)(void*)
){
return bindText(pStmt, i, zData, nData, xDel, 0);
@@ -52394,21 +62644,21 @@ SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
}
return rc;
}
-SQLITE_API int sqlite3_bind_text(
- sqlite3_stmt *pStmt,
- int i,
- const char *zData,
- int nData,
+SQLITE_API int sqlite3_bind_text(
+ sqlite3_stmt *pStmt,
+ int i,
+ const char *zData,
+ int nData,
void (*xDel)(void*)
){
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8);
}
#ifndef SQLITE_OMIT_UTF16
SQLITE_API int sqlite3_bind_text16(
- sqlite3_stmt *pStmt,
- int i,
- const void *zData,
- int nData,
+ sqlite3_stmt *pStmt,
+ int i,
+ const void *zData,
+ int nData,
void (*xDel)(void*)
){
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
@@ -52458,39 +62708,13 @@ SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
/*
** Return the number of wildcards that can be potentially bound to.
-** This routine is added to support DBD::SQLite.
+** This routine is added to support DBD::SQLite.
*/
SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe*)pStmt;
return p ? p->nVar : 0;
}
-/*
-** Create a mapping from variable numbers to variable names
-** in the Vdbe.azVar[] array, if such a mapping does not already
-** exist.
-*/
-static void createVarMap(Vdbe *p){
- if( !p->okVar ){
- int j;
- Op *pOp;
- sqlite3_mutex_enter(p->db->mutex);
- /* The race condition here is harmless. If two threads call this
- ** routine on the same Vdbe at the same time, they both might end
- ** up initializing the Vdbe.azVar[] array. That is a little extra
- ** work but it results in the same answer.
- */
- for(j=0, pOp=p->aOp; jnOp; j++, pOp++){
- if( pOp->opcode==OP_Variable ){
- assert( pOp->p1>0 && pOp->p1<=p->nVar );
- p->azVar[pOp->p1-1] = pOp->p4.z;
- }
- }
- p->okVar = 1;
- sqlite3_mutex_leave(p->db->mutex);
- }
-}
-
/*
** Return the name of a wildcard parameter. Return NULL if the index
** is out of range or if the wildcard is unnamed.
@@ -52499,10 +62723,9 @@ static void createVarMap(Vdbe *p){
*/
SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){
Vdbe *p = (Vdbe*)pStmt;
- if( p==0 || i<1 || i>p->nVar ){
+ if( p==0 || i<1 || i>p->nzVar ){
return 0;
}
- createVarMap(p);
return p->azVar[i-1];
}
@@ -52516,9 +62739,8 @@ SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nNa
if( p==0 ){
return 0;
}
- createVarMap(p);
if( zName ){
- for(i=0; inVar; i++){
+ for(i=0; inzVar; i++){
const char *z = p->azVar[i];
if( z && memcmp(z,zName,nName)==0 && z[nName]==0 ){
return i+1;
@@ -52587,6 +62809,14 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){
return pStmt ? ((Vdbe*)pStmt)->db : 0;
}
+/*
+** Return true if the prepared statement is guaranteed to not modify the
+** database.
+*/
+SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){
+ return pStmt ? ((Vdbe*)pStmt)->readOnly : 1;
+}
+
/*
** Return a pointer to the next prepared statement after pStmt associated
** with database connection pDb. If pStmt is NULL, return the first
@@ -52661,9 +62891,12 @@ static int findNextHostParameter(const char *zSql, int *pnToken){
}
/*
-** Return a pointer to a string in memory obtained form sqlite3DbMalloc() which
-** holds a copy of zRawSql but with host parameters expanded to their
-** current bindings.
+** This function returns a pointer to a nul-terminated string in memory
+** obtained from sqlite3DbMalloc(). If sqlite3.vdbeExecCnt is 1, then the
+** string contains a copy of zRawSql but with host parameters expanded to
+** their current bindings. Or, if sqlite3.vdbeExecCnt is greater than 1,
+** then the returned string holds a copy of zRawSql with "-- " prepended
+** to each line of text.
**
** The calling function is responsible for making sure the memory returned
** is eventually freed.
@@ -52691,66 +62924,75 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
char zBase[100]; /* Initial working space */
db = p->db;
- sqlite3StrAccumInit(&out, zBase, sizeof(zBase),
+ sqlite3StrAccumInit(&out, zBase, sizeof(zBase),
db->aLimit[SQLITE_LIMIT_LENGTH]);
out.db = db;
- while( zRawSql[0] ){
- n = findNextHostParameter(zRawSql, &nToken);
- assert( n>0 );
- sqlite3StrAccumAppend(&out, zRawSql, n);
- zRawSql += n;
- assert( zRawSql[0] || nToken==0 );
- if( nToken==0 ) break;
- if( zRawSql[0]=='?' ){
- if( nToken>1 ){
- assert( sqlite3Isdigit(zRawSql[1]) );
- sqlite3GetInt32(&zRawSql[1], &idx);
- }else{
- idx = nextIndex;
- }
- }else{
- assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' );
- testcase( zRawSql[0]==':' );
- testcase( zRawSql[0]=='$' );
- testcase( zRawSql[0]=='@' );
- idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken);
- assert( idx>0 );
+ if( db->vdbeExecCnt>1 ){
+ while( *zRawSql ){
+ const char *zStart = zRawSql;
+ while( *(zRawSql++)!='\n' && *zRawSql );
+ sqlite3StrAccumAppend(&out, "-- ", 3);
+ sqlite3StrAccumAppend(&out, zStart, (int)(zRawSql-zStart));
}
- zRawSql += nToken;
- nextIndex = idx + 1;
- assert( idx>0 && idx<=p->nVar );
- pVar = &p->aVar[idx-1];
- if( pVar->flags & MEM_Null ){
- sqlite3StrAccumAppend(&out, "NULL", 4);
- }else if( pVar->flags & MEM_Int ){
- sqlite3XPrintf(&out, "%lld", pVar->u.i);
- }else if( pVar->flags & MEM_Real ){
- sqlite3XPrintf(&out, "%!.15g", pVar->r);
- }else if( pVar->flags & MEM_Str ){
+ }else{
+ while( zRawSql[0] ){
+ n = findNextHostParameter(zRawSql, &nToken);
+ assert( n>0 );
+ sqlite3StrAccumAppend(&out, zRawSql, n);
+ zRawSql += n;
+ assert( zRawSql[0] || nToken==0 );
+ if( nToken==0 ) break;
+ if( zRawSql[0]=='?' ){
+ if( nToken>1 ){
+ assert( sqlite3Isdigit(zRawSql[1]) );
+ sqlite3GetInt32(&zRawSql[1], &idx);
+ }else{
+ idx = nextIndex;
+ }
+ }else{
+ assert( zRawSql[0]==':' || zRawSql[0]=='$' || zRawSql[0]=='@' );
+ testcase( zRawSql[0]==':' );
+ testcase( zRawSql[0]=='$' );
+ testcase( zRawSql[0]=='@' );
+ idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken);
+ assert( idx>0 );
+ }
+ zRawSql += nToken;
+ nextIndex = idx + 1;
+ assert( idx>0 && idx<=p->nVar );
+ pVar = &p->aVar[idx-1];
+ if( pVar->flags & MEM_Null ){
+ sqlite3StrAccumAppend(&out, "NULL", 4);
+ }else if( pVar->flags & MEM_Int ){
+ sqlite3XPrintf(&out, "%lld", pVar->u.i);
+ }else if( pVar->flags & MEM_Real ){
+ sqlite3XPrintf(&out, "%!.15g", pVar->r);
+ }else if( pVar->flags & MEM_Str ){
#ifndef SQLITE_OMIT_UTF16
- u8 enc = ENC(db);
- 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
+ u8 enc = ENC(db);
+ 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
#endif
- {
- sqlite3XPrintf(&out, "'%.*q'", pVar->n, pVar->z);
+ {
+ sqlite3XPrintf(&out, "'%.*q'", pVar->n, pVar->z);
+ }
+ }else if( pVar->flags & MEM_Zero ){
+ sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
+ }else{
+ assert( pVar->flags & MEM_Blob );
+ sqlite3StrAccumAppend(&out, "x'", 2);
+ for(i=0; in; i++){
+ sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
+ }
+ sqlite3StrAccumAppend(&out, "'", 1);
}
- }else if( pVar->flags & MEM_Zero ){
- sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
- }else{
- assert( pVar->flags & MEM_Blob );
- sqlite3StrAccumAppend(&out, "x'", 2);
- for(i=0; in; i++){
- sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
- }
- sqlite3StrAccumAppend(&out, "'", 1);
}
}
return sqlite3StrAccumFinish(&out);
@@ -52771,7 +63013,7 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
** May you share freely, never taking more than you give.
**
*************************************************************************
-** The code in this file implements execution method of the
+** The code in this file implements execution method of the
** Virtual Database Engine (VDBE). A separate file ("vdbeaux.c")
** handles housekeeping details such as creating and deleting
** VDBE instances. This file is solely interested in executing
@@ -52781,10 +63023,10 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
** to a VDBE.
**
** The SQL parser generates a program which is then executed by
-** the VDBE to do the work of the SQL statement. VDBE programs are
+** the VDBE to do the work of the SQL statement. VDBE programs are
** similar in form to assembly language. The program consists of
-** a linear sequence of operations. Each operation has an opcode
-** and 5 operands. Operands P1, P2, and P3 are integers. Operand P4
+** a linear sequence of operations. Each operation has an opcode
+** and 5 operands. Operands P1, P2, and P3 are integers. Operand P4
** is a null-terminated string. Operand P5 is an unsigned character.
** Few opcodes use all 5 operands.
**
@@ -52793,7 +63035,7 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
** either an integer, a null-terminated string, a floating point
** number, or the SQL "NULL" value. An implicit conversion from one
** type to the other occurs as necessary.
-**
+**
** Most of the code in this file is taken up by the sqlite3VdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
@@ -52806,6 +63048,17 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
** commenting and indentation practices when changing or adding code.
*/
+/*
+** Invoke this macro on memory cells just prior to changing the
+** value of the cell. This macro verifies that shallow copies are
+** not misused.
+*/
+#ifdef SQLITE_DEBUG
+# define memAboutToChange(P,M) sqlite3VdbeMemPrepareToChange(P,M)
+#else
+# define memAboutToChange(P,M)
+#endif
+
/*
** The following global variable is incremented every time a cursor
** moves, either by the OP_SeekXX, OP_Next, or OP_Prev opcodes. The test
@@ -52906,10 +63159,17 @@ SQLITE_API int sqlite3_found_count = 0;
*/
#define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0)
+/* 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
** user-defined function or returned to the user as the result of a query.
-** This routine sets the pMem->type variable used by the sqlite3_value_*()
+** This routine sets the pMem->type variable used by the sqlite3_value_*()
** routines.
*/
SQLITE_PRIVATE void sqlite3VdbeMemStoreType(Mem *pMem){
@@ -52942,7 +63202,7 @@ static VdbeCursor *allocateCursor(
int isBtreeCursor /* True for B-Tree. False for pseudo-table or vtab */
){
/* Find the memory cell that will be used to store the blob of memory
- ** required for this VdbeCursor structure. It is convenient to use a
+ ** required for this VdbeCursor structure. It is convenient to use a
** vdbe memory cell to manage the memory allocation required for a
** VdbeCursor structure for the following reasons:
**
@@ -52963,9 +63223,9 @@ static VdbeCursor *allocateCursor(
int nByte;
VdbeCursor *pCx = 0;
- nByte =
- ROUND8(sizeof(VdbeCursor)) +
- (isBtreeCursor?sqlite3BtreeCursorSize():0) +
+ nByte =
+ ROUND8(sizeof(VdbeCursor)) +
+ (isBtreeCursor?sqlite3BtreeCursorSize():0) +
2*nField*sizeof(u32);
assert( iCurnCursor );
@@ -52998,31 +63258,17 @@ static VdbeCursor *allocateCursor(
*/
static void applyNumericAffinity(Mem *pRec){
if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){
- int realnum;
+ double rValue;
+ i64 iValue;
u8 enc = pRec->enc;
- sqlite3VdbeMemNulTerminate(pRec);
- if( (pRec->flags&MEM_Str) && sqlite3IsNumber(pRec->z, &realnum, enc) ){
- i64 value;
- char *zUtf8 = pRec->z;
-#ifndef SQLITE_OMIT_UTF16
- if( enc!=SQLITE_UTF8 ){
- assert( pRec->db );
- zUtf8 = sqlite3Utf16to8(pRec->db, pRec->z, pRec->n, enc);
- if( !zUtf8 ) return;
- }
-#endif
- if( !realnum && sqlite3Atoi64(zUtf8, &value) ){
- pRec->u.i = value;
- MemSetTypeFlag(pRec, MEM_Int);
- }else{
- sqlite3AtoF(zUtf8, &pRec->r);
- MemSetTypeFlag(pRec, MEM_Real);
- }
-#ifndef SQLITE_OMIT_UTF16
- if( enc!=SQLITE_UTF8 ){
- sqlite3DbFree(pRec->db, zUtf8);
- }
-#endif
+ if( (pRec->flags&MEM_Str)==0 ) return;
+ if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return;
+ if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){
+ pRec->u.i = iValue;
+ pRec->flags |= MEM_Int;
+ }else{
+ pRec->r = rValue;
+ pRec->flags |= MEM_Real;
}
}
}
@@ -53033,7 +63279,7 @@ static void applyNumericAffinity(Mem *pRec){
** SQLITE_AFF_INTEGER:
** SQLITE_AFF_REAL:
** SQLITE_AFF_NUMERIC:
-** Try to convert pRec to an integer representation or a
+** Try to convert pRec to an integer representation or a
** floating-point representation if an integer representation
** is not possible. Note that the integer representation is
** always preferred, even if the affinity is REAL, because
@@ -53074,23 +63320,23 @@ static void applyAffinity(
** into a numeric representation. Use either INTEGER or REAL whichever
** is appropriate. But only do the conversion if it is possible without
** loss of information and return the revised type of the argument.
-**
-** This is an EXPERIMENTAL api and is subject to change or removal.
*/
SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){
Mem *pMem = (Mem*)pVal;
- applyNumericAffinity(pMem);
- sqlite3VdbeMemStoreType(pMem);
+ if( pMem->type==SQLITE_TEXT ){
+ applyNumericAffinity(pMem);
+ sqlite3VdbeMemStoreType(pMem);
+ }
return pMem->type;
}
/*
-** Exported version of applyAffinity(). This one works on sqlite3_value*,
+** Exported version of applyAffinity(). This one works on sqlite3_value*,
** not the internal Mem* type.
*/
SQLITE_PRIVATE void sqlite3ValueApplyAffinity(
- sqlite3_value *pVal,
- u8 affinity,
+ sqlite3_value *pVal,
+ u8 affinity,
u8 enc
){
applyAffinity((Mem *)pVal, affinity, enc);
@@ -53219,8 +63465,8 @@ static void registerTrace(FILE *out, int iReg, Mem *p){
#ifdef VDBE_PROFILE
-/*
-** hwtime.h contains inline assembler code for implementing
+/*
+** hwtime.h contains inline assembler code for implementing
** high-performance timing routines.
*/
/************** Include hwtime.h in the middle of vdbe.c *********************/
@@ -53278,7 +63524,7 @@ static void registerTrace(FILE *out, int iReg, Mem *p){
__asm__ __volatile__ ("rdtsc" : "=A" (val));
return val;
}
-
+
#elif (defined(__GNUC__) && defined(__ppc__))
__inline__ sqlite_uint64 sqlite3Hwtime(void){
@@ -53329,30 +63575,14 @@ SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
#define CHECK_FOR_INTERRUPT \
if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
-#ifdef SQLITE_DEBUG
-static int fileExists(sqlite3 *db, const char *zFile){
- int res = 0;
- int rc = SQLITE_OK;
-#ifdef SQLITE_TEST
- /* If we are currently testing IO errors, then do not call OsAccess() to
- ** test for the presence of zFile. This is because any IO error that
- ** occurs here will not be reported, causing the test to fail.
- */
- extern int sqlite3_io_error_pending;
- if( sqlite3_io_error_pending<=0 )
-#endif
- rc = sqlite3OsAccess(db->pVfs, zFile, SQLITE_ACCESS_EXISTS, &res);
- return (res && rc==SQLITE_OK);
-}
-#endif
#ifndef NDEBUG
/*
** This function is only called from within an assert() expression. It
** checks that the sqlite3.nTransaction variable is correctly set to
-** the number of non-transaction savepoints currently in the
+** the number of non-transaction savepoints currently in the
** linked list starting at sqlite3.pSavepoint.
-**
+**
** Usage:
**
** assert( checkSavepointCount(db) );
@@ -53366,6 +63596,20 @@ static int checkSavepointCount(sqlite3 *db){
}
#endif
+/*
+** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored
+** in memory obtained from sqlite3_malloc) into a Vdbe.zErrMsg (text stored
+** in memory obtained from sqlite3DbMalloc).
+*/
+static void importVtabErrMsg(Vdbe *p, sqlite3_vtab *pVtab){
+ sqlite3 *db = p->db;
+ sqlite3DbFree(db, p->zErrMsg);
+ p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
+ sqlite3_free(pVtab->zErrMsg);
+ pVtab->zErrMsg = 0;
+}
+
+
/*
** Execute as much of a VDBE program as we can then return.
**
@@ -53405,7 +63649,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
Op *pOp; /* Current operation */
int rc = SQLITE_OK; /* Value to return */
sqlite3 *db = p->db; /* The database */
- u8 resetSchemaOnFault = 0; /* Reset schema after an error if true */
+ u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */
u8 encoding = ENC(db); /* The database encoding */
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
int checkProgress; /* True if progress callbacks are enabled */
@@ -53418,6 +63662,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
Mem *pOut = 0; /* Output operand */
int iCompare = 0; /* Result of last OP_Compare operation */
int *aPermute = 0; /* Permutation of columns for OP_Compare */
+ i64 lastRowid = db->lastRowid; /* Saved value of the last insert ROWID */
#ifdef VDBE_PROFILE
u64 start; /* CPU clock count at start of opcode */
int origPc; /* Program counter at start of opcode */
@@ -53435,9 +63680,6 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
int pcDest;
} aa;
struct OP_Variable_stack_vars {
- int p1; /* Variable to copy from */
- int p2; /* Register to copy to */
- int n; /* Number of values left to copy */
Mem *pVar; /* Value being transferred */
} ab;
struct OP_Move_stack_vars {
@@ -53468,8 +63710,10 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
int n;
} ag;
struct OP_ShiftRight_stack_vars {
- i64 a;
- i64 b;
+ i64 iA;
+ u64 uA;
+ i64 iB;
+ u8 op;
} ah;
struct OP_Ge_stack_vars {
int res; /* Result of the comparison of pIn1 against pIn3 */
@@ -53516,6 +63760,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
u32 szField; /* Number of bytes in the content of a field */
int szHdr; /* Size of the header size field at start of record */
int avail; /* Number of bytes of available data */
+ u32 t; /* A type code from the record header */
Mem *pReg; /* PseudoTable input register */
} am;
struct OP_Affinity_stack_vars {
@@ -53571,6 +63816,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
} au;
struct OP_VerifyCookie_stack_vars {
int iMeta;
+ int iGen;
Btree *pBt;
} av;
struct OP_OpenWrite_stack_vars {
@@ -53586,9 +63832,12 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
struct OP_OpenEphemeral_stack_vars {
VdbeCursor *pCx;
} ax;
- struct OP_OpenPseudo_stack_vars {
+ struct OP_SorterOpen_stack_vars {
VdbeCursor *pCx;
} ay;
+ struct OP_OpenPseudo_stack_vars {
+ VdbeCursor *pCx;
+ } az;
struct OP_SeekGt_stack_vars {
int res;
int oc;
@@ -53596,18 +63845,19 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
UnpackedRecord r;
int nField;
i64 iKey; /* The rowid we are to seek to */
- } az;
+ } ba;
struct OP_Seek_stack_vars {
VdbeCursor *pC;
- } ba;
+ } bb;
struct OP_Found_stack_vars {
int alreadyExists;
VdbeCursor *pC;
int res;
+ char *pFree;
UnpackedRecord *pIdxKey;
UnpackedRecord r;
char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*3 + 7];
- } bb;
+ } bc;
struct OP_IsUnique_stack_vars {
u16 ii;
VdbeCursor *pCx;
@@ -53616,13 +63866,13 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
Mem *aMx;
UnpackedRecord r; /* B-Tree index search key */
i64 R; /* Rowid stored in register P3 */
- } bc;
+ } bd;
struct OP_NotExists_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
u64 iKey;
- } bd;
+ } be;
struct OP_NewRowid_stack_vars {
i64 v; /* The new rowid */
VdbeCursor *pC; /* Cursor of table to get the new rowid */
@@ -53630,7 +63880,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 */
- } be;
+ } bf;
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 */
@@ -53641,83 +63891,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 */
- } bf;
+ } bg;
struct OP_Delete_stack_vars {
i64 iKey;
VdbeCursor *pC;
- } bg;
+ } bh;
+ struct OP_SorterCompare_stack_vars {
+ VdbeCursor *pC;
+ int res;
+ } bi;
+ struct OP_SorterData_stack_vars {
+ VdbeCursor *pC;
+ } bj;
struct OP_RowData_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
u32 n;
i64 n64;
- } bh;
+ } bk;
struct OP_Rowid_stack_vars {
VdbeCursor *pC;
i64 v;
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
- } bi;
+ } bl;
struct OP_NullRow_stack_vars {
VdbeCursor *pC;
- } bj;
+ } bm;
struct OP_Last_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
- } bk;
+ } bn;
struct OP_Rewind_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
- } bl;
+ } bo;
struct OP_Next_stack_vars {
VdbeCursor *pC;
- BtCursor *pCrsr;
int res;
- } bm;
+ } bp;
struct OP_IdxInsert_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int nKey;
const char *zKey;
- } bn;
+ } bq;
struct OP_IdxDelete_stack_vars {
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
UnpackedRecord r;
- } bo;
+ } br;
struct OP_IdxRowid_stack_vars {
BtCursor *pCrsr;
VdbeCursor *pC;
i64 rowid;
- } bp;
+ } bs;
struct OP_IdxGE_stack_vars {
VdbeCursor *pC;
int res;
UnpackedRecord r;
- } bq;
+ } bt;
struct OP_Destroy_stack_vars {
int iMoved;
int iCnt;
Vdbe *pVdbe;
int iDb;
- } br;
+ } bu;
struct OP_Clear_stack_vars {
int nChange;
- } bs;
+ } bv;
struct OP_CreateTable_stack_vars {
int pgno;
int flags;
Db *pDb;
- } bt;
+ } bw;
struct OP_ParseSchema_stack_vars {
int iDb;
const char *zMaster;
char *zSql;
InitData initData;
- } bu;
+ } bx;
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 */
@@ -53725,14 +63981,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 */
- } bv;
+ } by;
struct OP_RowSetRead_stack_vars {
i64 val;
- } bw;
+ } bz;
struct OP_RowSetTest_stack_vars {
int iSet;
int exists;
- } bx;
+ } ca;
struct OP_Program_stack_vars {
int nMem; /* Number of memory registers for sub-program */
int nByte; /* Bytes of runtime space required for sub-program */
@@ -53742,15 +63998,15 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
VdbeFrame *pFrame; /* New vdbe frame to execute in */
SubProgram *pProgram; /* Sub-program to execute */
void *t; /* Token identifying trigger */
- } by;
+ } cb;
struct OP_Param_stack_vars {
VdbeFrame *pFrame;
Mem *pIn;
- } bz;
+ } cc;
struct OP_MemMax_stack_vars {
Mem *pIn1;
VdbeFrame *pFrame;
- } ca;
+ } cd;
struct OP_AggStep_stack_vars {
int n;
int i;
@@ -53758,22 +64014,34 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
Mem *pRec;
sqlite3_context ctx;
sqlite3_value **apVal;
- } cb;
+ } ce;
struct OP_AggFinal_stack_vars {
Mem *pMem;
- } cc;
+ } cf;
+ struct OP_Checkpoint_stack_vars {
+ int i; /* Loop counter */
+ int aRes[3]; /* Results */
+ Mem *pMem; /* Write results here */
+ } cg;
+ 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 */
+ const char *zFilename; /* Name of database file for pPager */
+ } ch;
struct OP_IncrVacuum_stack_vars {
Btree *pBt;
- } cd;
+ } ci;
struct OP_VBegin_stack_vars {
VTable *pVTab;
- } ce;
+ } cj;
struct OP_VOpen_stack_vars {
VdbeCursor *pCur;
sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
- } cf;
+ } ck;
struct OP_VFilter_stack_vars {
int nArg;
int iQuery;
@@ -53786,23 +64054,23 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
int res;
int i;
Mem **apArg;
- } cg;
+ } cl;
struct OP_VColumn_stack_vars {
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
Mem *pDest;
sqlite3_context sContext;
- } ch;
+ } cm;
struct OP_VNext_stack_vars {
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
int res;
VdbeCursor *pCur;
- } ci;
+ } cn;
struct OP_VRename_stack_vars {
sqlite3_vtab *pVtab;
Mem *pName;
- } cj;
+ } co;
struct OP_VUpdate_stack_vars {
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
@@ -53811,21 +64079,17 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
sqlite_int64 rowid;
Mem **apArg;
Mem *pX;
- } ck;
- struct OP_Pagecount_stack_vars {
- int p1;
- int nPage;
- Pager *pPager;
- } cl;
+ } cp;
struct OP_Trace_stack_vars {
char *zTrace;
- } cm;
+ char *z;
+ } cq;
} u;
/* End automatically generated code
********************************************************************/
assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */
- sqlite3VdbeMutexArrayEnter(p);
+ sqlite3VdbeEnter(p);
if( p->rc==SQLITE_NOMEM ){
/* This happens if a malloc() inside a call to sqlite3_column_text() or
** sqlite3_column_text16() failed. */
@@ -53843,9 +64107,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
#endif
#ifdef SQLITE_DEBUG
sqlite3BeginBenignMalloc();
- if( p->pc==0
- && ((p->db->flags & SQLITE_VdbeListing) || fileExists(db, "vdbe_explain"))
- ){
+ if( p->pc==0 && (p->db->flags & SQLITE_VdbeListing)!=0 ){
int i;
printf("VDBE Program Listing:\n");
sqlite3VdbePrintSql(p);
@@ -53853,9 +64115,6 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
sqlite3VdbePrintOp(stdout, i, &aOp[i]);
}
}
- if( fileExists(db, "vdbe_trace") ){
- p->trace = stdout;
- }
sqlite3EndBenignMalloc();
#endif
for(pc=p->pc; rc==SQLITE_OK; pc++){
@@ -53877,15 +64136,8 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
}
sqlite3VdbePrintOp(p->trace, pc, pOp);
}
- if( p->trace==0 && pc==0 ){
- sqlite3BeginBenignMalloc();
- if( fileExists(db, "vdbe_sqltrace") ){
- sqlite3VdbePrintSql(p);
- }
- sqlite3EndBenignMalloc();
- }
#endif
-
+
/* Check to see if we need to simulate an interrupt. This only happens
** if we have a special test build.
@@ -53930,7 +64182,8 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
assert( pOp->p2>0 );
assert( pOp->p2<=p->nMem );
pOut = &aMem[pOp->p2];
- sqlite3VdbeMemReleaseExternal(pOut);
+ memAboutToChange(p, pOut);
+ MemReleaseExt(pOut);
pOut->flags = MEM_Int;
}
@@ -53939,28 +64192,33 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
if( (pOp->opflags & OPFLG_IN1)!=0 ){
assert( pOp->p1>0 );
assert( pOp->p1<=p->nMem );
+ assert( memIsValid(&aMem[pOp->p1]) );
REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]);
}
if( (pOp->opflags & OPFLG_IN2)!=0 ){
assert( pOp->p2>0 );
assert( pOp->p2<=p->nMem );
+ assert( memIsValid(&aMem[pOp->p2]) );
REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]);
}
if( (pOp->opflags & OPFLG_IN3)!=0 ){
assert( pOp->p3>0 );
assert( pOp->p3<=p->nMem );
+ assert( memIsValid(&aMem[pOp->p3]) );
REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]);
}
if( (pOp->opflags & OPFLG_OUT2)!=0 ){
assert( pOp->p2>0 );
assert( pOp->p2<=p->nMem );
+ memAboutToChange(p, &aMem[pOp->p2]);
}
if( (pOp->opflags & OPFLG_OUT3)!=0 ){
assert( pOp->p3>0 );
assert( pOp->p3<=p->nMem );
+ memAboutToChange(p, &aMem[pOp->p3]);
}
#endif
-
+
switch( pOp->opcode ){
/*****************************************************************************
@@ -54001,7 +64259,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
/* Opcode: Goto * P2 * * *
**
** An unconditional jump to address P2.
-** The next instruction executed will be
+** The next instruction executed will be
** the one at index P2 from the beginning of
** the program.
*/
@@ -54019,6 +64277,7 @@ case OP_Goto: { /* jump */
case OP_Gosub: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( (pIn1->flags & MEM_Dyn)==0 );
+ memAboutToChange(p, pIn1);
pIn1->flags = MEM_Int;
pIn1->u.i = pc;
REGISTER_TRACE(pOp->p1, pIn1);
@@ -54057,7 +64316,7 @@ case OP_Yield: { /* in1 */
/* Opcode: HaltIfNull P1 P2 P3 P4 *
**
-** Check the value in register P3. If is is NULL then Halt using
+** Check the value in register P3. If it is NULL then Halt using
** parameter P1, P2, and P4 as if this were a Halt instruction. If the
** value in register P3 is not NULL, then this routine is a no-op.
*/
@@ -54078,7 +64337,7 @@ case OP_HaltIfNull: { /* in3 */
** whether or not to rollback the current transaction. Do not rollback
** if P2==OE_Fail. Do the rollback if P2==OE_Rollback. If P2==OE_Abort,
** then back out all changes that have occurred during this execution of the
-** VDBE, but do not rollback the transaction.
+** VDBE, but do not rollback the transaction.
**
** If P4 is not null then it is an error message string.
**
@@ -54094,8 +64353,9 @@ case OP_Halt: {
p->nFrame--;
sqlite3VdbeSetChanges(db, p->nChange);
pc = sqlite3VdbeFrameRestore(pFrame);
+ lastRowid = db->lastRowid;
if( pOp->p2==OE_Ignore ){
- /* Instruction pc is the OP_Program that invoked the sub-program
+ /* Instruction pc is the OP_Program that invoked the sub-program
** currently being halted. If the p2 instruction of this OP_Halt
** instruction is set to OE_Ignore, then the sub-program is throwing
** an IGNORE exception. In this case jump to the address specified
@@ -54167,7 +64427,7 @@ case OP_Real: { /* same as TK_FLOAT, out2-prerelease */
/* Opcode: String8 * P2 * P4 *
**
-** P4 points to a nul terminated UTF-8 string. This opcode is transformed
+** P4 points to a nul terminated UTF-8 string. This opcode is transformed
** into an OP_String before it is executed for the first time.
*/
case OP_String8: { /* same as TK_STRING, out2-prerelease */
@@ -54198,7 +64458,7 @@ case OP_String8: { /* same as TK_STRING, out2-prerelease */
}
/* Fall through to the next case, OP_String */
}
-
+
/* Opcode: String P1 P2 * P4 *
**
** The string value P4 of length P1 (bytes) is stored in register P2.
@@ -54226,11 +64486,7 @@ case OP_Null: { /* out2-prerelease */
/* Opcode: Blob P1 P2 * P4
**
** P4 points to a blob of data P1 bytes long. Store this
-** blob in register P2. This instruction is not coded directly
-** by the compiler. Instead, the compiler layer specifies
-** an OP_HexBlob opcode, with the hex string representation of
-** the blob as P4. This opcode is transformed to an OP_Blob
-** the first time it is executed.
+** blob in register P2.
*/
case OP_Blob: { /* out2-prerelease */
assert( pOp->p1 <= SQLITE_MAX_LENGTH );
@@ -54240,40 +64496,26 @@ case OP_Blob: { /* out2-prerelease */
break;
}
-/* Opcode: Variable P1 P2 P3 P4 *
+/* Opcode: Variable P1 P2 * P4 *
**
-** Transfer the values of bound parameters P1..P1+P3-1 into registers
-** P2..P2+P3-1.
+** Transfer the values of bound parameter P1 into register P2
**
** If the parameter is named, then its name appears in P4 and P3==1.
** The P4 value is used by sqlite3_bind_parameter_name().
*/
-case OP_Variable: {
+case OP_Variable: { /* out2-prerelease */
#if 0 /* local variables moved into u.ab */
- int p1; /* Variable to copy from */
- int p2; /* Register to copy to */
- int n; /* Number of values left to copy */
Mem *pVar; /* Value being transferred */
#endif /* local variables moved into u.ab */
- u.ab.p1 = pOp->p1 - 1;
- u.ab.p2 = pOp->p2;
- u.ab.n = pOp->p3;
- assert( u.ab.p1>=0 && u.ab.p1+u.ab.n<=p->nVar );
- assert( u.ab.p2>=1 && u.ab.p2+u.ab.n-1<=p->nMem );
- assert( pOp->p4.z==0 || pOp->p3==1 || pOp->p3==0 );
-
- while( u.ab.n-- > 0 ){
- u.ab.pVar = &p->aVar[u.ab.p1++];
- if( sqlite3VdbeMemTooBig(u.ab.pVar) ){
- goto too_big;
- }
- pOut = &aMem[u.ab.p2++];
- sqlite3VdbeMemReleaseExternal(pOut);
- pOut->flags = MEM_Null;
- sqlite3VdbeMemShallowCopy(pOut, u.ab.pVar, MEM_Static);
- UPDATE_MAX_BLOBSIZE(pOut);
+ assert( pOp->p1>0 && pOp->p1<=p->nVar );
+ assert( pOp->p4.z==0 || pOp->p4.z==p->azVar[pOp->p1-1] );
+ u.ab.pVar = &p->aVar[pOp->p1 - 1];
+ if( sqlite3VdbeMemTooBig(u.ab.pVar) ){
+ goto too_big;
}
+ sqlite3VdbeMemShallowCopy(pOut, u.ab.pVar, MEM_Static);
+ UPDATE_MAX_BLOBSIZE(pOut);
break;
}
@@ -54303,9 +64545,16 @@ case OP_Move: {
while( u.ac.n-- ){
assert( pOut<=&aMem[p->nMem] );
assert( pIn1<=&aMem[p->nMem] );
+ assert( memIsValid(pIn1) );
+ memAboutToChange(p, pOut);
u.ac.zMalloc = pOut->zMalloc;
pOut->zMalloc = 0;
sqlite3VdbeMemMove(pOut, pIn1);
+#ifdef SQLITE_DEBUG
+ if( pOut->pScopyFrom>=&aMem[u.ac.p1] && pOut->pScopyFrom<&aMem[u.ac.p1+pOp->p3] ){
+ pOut->pScopyFrom += u.ac.p1 - pOp->p2;
+ }
+#endif
pIn1->zMalloc = u.ac.zMalloc;
REGISTER_TRACE(u.ac.p2++, pOut);
pIn1++;
@@ -54348,6 +64597,9 @@ case OP_SCopy: { /* in1, out2 */
pOut = &aMem[pOp->p2];
assert( pOut!=pIn1 );
sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem);
+#ifdef SQLITE_DEBUG
+ if( pOut->pScopyFrom==0 ) pOut->pScopyFrom = pIn1;
+#endif
REGISTER_TRACE(pOp->p2, pOut);
break;
}
@@ -54408,6 +64660,10 @@ case OP_ResultRow: {
*/
u.ad.pMem = p->pResultSet = &aMem[pOp->p1];
for(u.ad.i=0; u.ad.ip2; u.ad.i++){
+ assert( memIsValid(&u.ad.pMem[u.ad.i]) );
+ Deephemeralize(&u.ad.pMem[u.ad.i]);
+ assert( (u.ad.pMem[u.ad.i].flags & MEM_Ephem)==0
+ || (u.ad.pMem[u.ad.i].flags & (MEM_Str|MEM_Blob))==0 );
sqlite3VdbeMemNulTerminate(&u.ad.pMem[u.ad.i]);
sqlite3VdbeMemStoreType(&u.ad.pMem[u.ad.i]);
REGISTER_TRACE(pOp->p1+u.ad.i, &u.ad.pMem[u.ad.i]);
@@ -54492,14 +64748,14 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
/* Opcode: Divide P1 P2 P3 * *
**
** Divide the value in register P1 by the value in register P2
-** and store the result in register P3 (P3=P2/P1). If the value in
-** register P1 is zero, then the result is NULL. If either input is
+** and store the result in register P3 (P3=P2/P1). If the value in
+** register P1 is zero, then the result is NULL. If either input is
** NULL, the result is NULL.
*/
/* Opcode: Remainder P1 P2 P3 * *
**
** Compute the remainder after integer division of the value in
-** register P1 by the value in register P2 and store the result in P3.
+** register P1 by the value in register P2 and store the result in P3.
** If the value in register P2 is zero the result is NULL.
** If either operand is NULL, the result is NULL.
*/
@@ -54527,19 +64783,12 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
u.af.iA = pIn1->u.i;
u.af.iB = pIn2->u.i;
switch( pOp->opcode ){
- case OP_Add: u.af.iB += u.af.iA; break;
- case OP_Subtract: u.af.iB -= u.af.iA; break;
- case OP_Multiply: u.af.iB *= u.af.iA; break;
+ case OP_Add: if( sqlite3AddInt64(&u.af.iB,u.af.iA) ) goto fp_math; break;
+ case OP_Subtract: if( sqlite3SubInt64(&u.af.iB,u.af.iA) ) goto fp_math; break;
+ case OP_Multiply: if( sqlite3MulInt64(&u.af.iB,u.af.iA) ) goto fp_math; break;
case OP_Divide: {
if( u.af.iA==0 ) goto arithmetic_result_is_null;
- /* Dividing the largest possible negative 64-bit integer (1<<63) by
- ** -1 returns an integer too large to store in a 64-bit data-type. On
- ** some architectures, the value overflows to (1<<63). On others,
- ** a SIGFPE is issued. The following statement normalizes this
- ** behavior so that all architectures behave as if integer
- ** overflow occurred.
- */
- if( u.af.iA==-1 && u.af.iB==SMALLEST_INT64 ) u.af.iA = 1;
+ if( u.af.iA==-1 && u.af.iB==SMALLEST_INT64 ) goto fp_math;
u.af.iB /= u.af.iA;
break;
}
@@ -54553,6 +64802,7 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
pOut->u.i = u.af.iB;
MemSetTypeFlag(pOut, MEM_Int);
}else{
+fp_math:
u.af.rA = sqlite3VdbeRealValue(pIn1);
u.af.rB = sqlite3VdbeRealValue(pIn2);
switch( pOp->opcode ){
@@ -54618,7 +64868,7 @@ case OP_CollSeq: {
** successors. The result of the function is stored in register P3.
** Register P3 must not be one of the function inputs.
**
-** P1 is a 32-bit bitmask indicating whether or not each argument to the
+** P1 is a 32-bit bitmask indicating whether or not each argument to the
** function was determined to be constant at compile time. If the first
** argument was constant then bit 0 of P1 is set. This is used to determine
** whether meta data associated with a user function argument using the
@@ -54639,14 +64889,19 @@ case OP_Function: {
u.ag.n = pOp->p5;
u.ag.apVal = p->apArg;
assert( u.ag.apVal || u.ag.n==0 );
+ assert( pOp->p3>0 && pOp->p3<=p->nMem );
+ pOut = &aMem[pOp->p3];
+ memAboutToChange(p, pOut);
assert( u.ag.n==0 || (pOp->p2>0 && pOp->p2+u.ag.n<=p->nMem+1) );
assert( pOp->p3p2 || pOp->p3>=pOp->p2+u.ag.n );
u.ag.pArg = &aMem[pOp->p2];
for(u.ag.i=0; u.ag.ip2, u.ag.pArg);
+ REGISTER_TRACE(pOp->p2+u.ag.i, u.ag.pArg);
}
assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC );
@@ -54658,8 +64913,6 @@ case OP_Function: {
u.ag.ctx.pFunc = u.ag.ctx.pVdbeFunc->pFunc;
}
- assert( pOp->p3>0 && pOp->p3<=p->nMem );
- pOut = &aMem[pOp->p3];
u.ag.ctx.s.flags = MEM_Null;
u.ag.ctx.s.db = db;
u.ag.ctx.s.xDel = 0;
@@ -54679,16 +64932,9 @@ case OP_Function: {
assert( pOp[-1].opcode==OP_CollSeq );
u.ag.ctx.pColl = pOp[-1].p4.pColl;
}
- (*u.ag.ctx.pFunc->xFunc)(&u.ag.ctx, u.ag.n, u.ag.apVal);
- if( db->mallocFailed ){
- /* Even though a malloc() has failed, the implementation of the
- ** user function may have called an sqlite3_result_XXX() function
- ** to return a value. The following call releases any resources
- ** associated with such a value.
- */
- sqlite3VdbeMemRelease(&u.ag.ctx.s);
- goto no_mem;
- }
+ db->lastRowid = lastRowid;
+ (*u.ag.ctx.pFunc->xFunc)(&u.ag.ctx, u.ag.n, u.ag.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.
@@ -54699,6 +64945,16 @@ case OP_Function: {
pOp->p4type = P4_VDBEFUNC;
}
+ if( db->mallocFailed ){
+ /* Even though a malloc() has failed, the implementation of the
+ ** user function may have called an sqlite3_result_XXX() function
+ ** to return a value. The following call releases any resources
+ ** associated with such a value.
+ */
+ sqlite3VdbeMemRelease(&u.ag.ctx.s);
+ goto no_mem;
+ }
+
/* If the function returned an error, throw an exception */
if( u.ag.ctx.isError ){
sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.ag.ctx.s));
@@ -54711,6 +64967,15 @@ case OP_Function: {
if( sqlite3VdbeMemTooBig(pOut) ){
goto too_big;
}
+
+#if 0
+ /* The app-defined function has done something that as caused this
+ ** statement to expire. (Perhaps the function called sqlite3_exec()
+ ** with a CREATE TABLE statement.)
+ */
+ if( p->expired ) rc = SQLITE_ABORT;
+#endif
+
REGISTER_TRACE(pOp->p3, pOut);
UPDATE_MAX_BLOBSIZE(pOut);
break;
@@ -54731,7 +64996,7 @@ case OP_Function: {
/* Opcode: ShiftLeft P1 P2 P3 * *
**
** Shift the integer value in register P2 to the left by the
-** number of bits specified by the integer in regiser P1.
+** number of bits specified by the integer in register P1.
** Store the result in register P3.
** If either input is NULL, the result is NULL.
*/
@@ -54747,8 +65012,10 @@ 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.ah */
- i64 a;
- i64 b;
+ i64 iA;
+ u64 uA;
+ i64 iB;
+ u8 op;
#endif /* local variables moved into u.ah */
pIn1 = &aMem[pOp->p1];
@@ -54758,22 +65025,44 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */
sqlite3VdbeMemSetNull(pOut);
break;
}
- u.ah.a = sqlite3VdbeIntValue(pIn2);
- u.ah.b = sqlite3VdbeIntValue(pIn1);
- switch( pOp->opcode ){
- case OP_BitAnd: u.ah.a &= u.ah.b; break;
- case OP_BitOr: u.ah.a |= u.ah.b; break;
- case OP_ShiftLeft: u.ah.a <<= u.ah.b; break;
- default: assert( pOp->opcode==OP_ShiftRight );
- u.ah.a >>= u.ah.b; break;
+ u.ah.iA = sqlite3VdbeIntValue(pIn2);
+ u.ah.iB = sqlite3VdbeIntValue(pIn1);
+ u.ah.op = pOp->opcode;
+ if( u.ah.op==OP_BitAnd ){
+ u.ah.iA &= u.ah.iB;
+ }else if( u.ah.op==OP_BitOr ){
+ u.ah.iA |= u.ah.iB;
+ }else if( u.ah.iB!=0 ){
+ assert( u.ah.op==OP_ShiftRight || u.ah.op==OP_ShiftLeft );
+
+ /* If shifting by a negative amount, shift in the other direction */
+ if( u.ah.iB<0 ){
+ assert( OP_ShiftRight==OP_ShiftLeft+1 );
+ u.ah.op = 2*OP_ShiftLeft + 1 - u.ah.op;
+ u.ah.iB = u.ah.iB>(-64) ? -u.ah.iB : 64;
+ }
+
+ if( u.ah.iB>=64 ){
+ u.ah.iA = (u.ah.iA>=0 || u.ah.op==OP_ShiftLeft) ? 0 : -1;
+ }else{
+ memcpy(&u.ah.uA, &u.ah.iA, sizeof(u.ah.uA));
+ if( u.ah.op==OP_ShiftLeft ){
+ u.ah.uA <<= u.ah.iB;
+ }else{
+ u.ah.uA >>= u.ah.iB;
+ /* Sign-extend on a right shift of a negative number */
+ if( u.ah.iA<0 ) u.ah.uA |= ((((u64)0xffffffff)<<32)|0xffffffff) << (64-u.ah.iB);
+ }
+ memcpy(&u.ah.iA, &u.ah.uA, sizeof(u.ah.iA));
+ }
}
- pOut->u.i = u.ah.a;
+ pOut->u.i = u.ah.iA;
MemSetTypeFlag(pOut, MEM_Int);
break;
}
/* Opcode: AddImm P1 P2 * * *
-**
+**
** Add the constant P2 to the value in register P1.
** The result is always an integer.
**
@@ -54781,13 +65070,14 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */
*/
case OP_AddImm: { /* in1 */
pIn1 = &aMem[pOp->p1];
+ memAboutToChange(p, pIn1);
sqlite3VdbeMemIntegerify(pIn1);
pIn1->u.i += pOp->p2;
break;
}
/* Opcode: MustBeInt P1 P2 * * *
-**
+**
** Force the value in register P1 to be an integer. If the value
** in P1 is not an integer and cannot be converted into an integer
** without data loss, then jump immediately to P2, or if P2==0
@@ -54840,6 +65130,7 @@ case OP_RealAffinity: { /* in1 */
*/
case OP_ToText: { /* same as TK_TO_TEXT, in1 */
pIn1 = &aMem[pOp->p1];
+ memAboutToChange(p, pIn1);
if( pIn1->flags & MEM_Null ) break;
assert( MEM_Str==(MEM_Blob>>3) );
pIn1->flags |= (pIn1->flags&MEM_Blob)>>3;
@@ -54879,23 +65170,21 @@ case OP_ToBlob: { /* same as TK_TO_BLOB, in1 */
** Force the value in register P1 to be numeric (either an
** integer or a floating-point number.)
** If the value is text or blob, try to convert it to an using the
-** equivalent of atoi() or atof() and store 0 if no such conversion
+** equivalent of atoi() or atof() and store 0 if no such conversion
** is possible.
**
** A NULL value is not changed by this routine. It remains NULL.
*/
case OP_ToNumeric: { /* same as TK_TO_NUMERIC, in1 */
pIn1 = &aMem[pOp->p1];
- if( (pIn1->flags & (MEM_Null|MEM_Int|MEM_Real))==0 ){
- sqlite3VdbeMemNumerify(pIn1);
- }
+ sqlite3VdbeMemNumerify(pIn1);
break;
}
#endif /* SQLITE_OMIT_CAST */
/* Opcode: ToInt P1 * * * *
**
-** Force the value in register P1 be an integer. If
+** Force the value in register P1 to be an integer. If
** The value is currently a real number, drop its fractional part.
** If the value is text or blob, try to convert it to an integer using the
** equivalent of atoi() and store 0 if no such conversion is possible.
@@ -54922,6 +65211,7 @@ case OP_ToInt: { /* same as TK_TO_INT, in1 */
*/
case OP_ToReal: { /* same as TK_TO_REAL, in1 */
pIn1 = &aMem[pOp->p1];
+ memAboutToChange(p, pIn1);
if( (pIn1->flags & MEM_Null)==0 ){
sqlite3VdbeMemRealify(pIn1);
}
@@ -54932,21 +65222,21 @@ case OP_ToReal: { /* same as TK_TO_REAL, in1 */
/* Opcode: Lt P1 P2 P3 P4 P5
**
** Compare the values in register P1 and P3. If reg(P3)p3];
u.ai.flags1 = pIn1->flags;
u.ai.flags3 = pIn3->flags;
- if( (pIn1->flags | pIn3->flags)&MEM_Null ){
+ if( (u.ai.flags1 | u.ai.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
@@ -55026,7 +65316,7 @@ 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.ai.res = (pIn1->flags & pIn3->flags & MEM_Null)==0;
+ u.ai.res = (u.ai.flags1 & u.ai.flags3 & MEM_Null)==0;
}else{
/* SQLITE_NULLEQ is clear and at least one operand is NULL,
** then the result is always NULL.
@@ -55066,6 +65356,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
if( pOp->p5 & SQLITE_STOREP2 ){
pOut = &aMem[pOp->p2];
+ memAboutToChange(p, pOut);
MemSetTypeFlag(pOut, MEM_Int);
pOut->u.i = u.ai.res;
REGISTER_TRACE(pOp->p2, pOut);
@@ -55097,8 +65388,8 @@ case OP_Permutation: {
/* Opcode: Compare P1 P2 P3 P4 *
**
-** Compare to vectors of registers in reg(P1)..reg(P1+P3-1) (all this
-** one "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of
+** 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.
**
** P4 is a KeyInfo structure that defines collating sequences and sort
@@ -55140,6 +65431,8 @@ case OP_Compare: {
#endif /* SQLITE_DEBUG */
for(u.aj.i=0; u.aj.inField );
@@ -55229,7 +65522,7 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */
/* Opcode: Not P1 P2 * * *
**
** Interpret the value in register P1 as a boolean value. Store the
-** boolean complement in register P2. If the value in register P1 is
+** boolean complement in register P2. If the value in register P1 is
** NULL, then a NULL is stored in P2.
*/
case OP_Not: { /* same as TK_NOT, in1, out2 */
@@ -55260,18 +65553,29 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
break;
}
+/* Opcode: Once P1 P2 * * *
+**
+** Jump to P2 if the value in register P1 is a not null or zero. If
+** the value is NULL or zero, fall through and change the P1 register
+** to an integer 1.
+**
+** When P1 is not used otherwise in a program, this opcode falls through
+** once and jumps on all subsequent invocations. It is the equivalent
+** of "OP_If P1 P2", followed by "OP_Integer 1 P1".
+*/
/* Opcode: If P1 P2 P3 * *
**
-** Jump to P2 if the value in register P1 is true. The value is
+** Jump to P2 if the value in register P1 is true. The value
** is considered true if it is numeric and non-zero. If the value
** in P1 is NULL then take the jump if P3 is true.
*/
/* Opcode: IfNot P1 P2 P3 * *
**
-** Jump to P2 if the value in register P1 is False. The value is
+** Jump to P2 if the value in register P1 is False. The value
** is considered true if it has a numeric value of zero. If the value
** in P1 is NULL then take the jump if P3 is true.
*/
+case OP_Once: /* jump, in1 */
case OP_If: /* jump, in1 */
case OP_IfNot: { /* jump, in1 */
#if 0 /* local variables moved into u.al */
@@ -55290,6 +65594,12 @@ case OP_IfNot: { /* jump, in1 */
}
if( u.al.c ){
pc = pOp->p2-1;
+ }else if( pOp->opcode==OP_Once ){
+ assert( (pIn1->flags & (MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))==0 );
+ memAboutToChange(p, pIn1);
+ pIn1->flags = MEM_Int;
+ pIn1->u.i = 1;
+ REGISTER_TRACE(pOp->p1, pIn1);
}
break;
}
@@ -55308,7 +65618,7 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */
/* Opcode: NotNull P1 P2 * * *
**
-** Jump to P2 if the value in register P1 is not NULL.
+** Jump to P2 if the value in register P1 is not NULL.
*/
case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
pIn1 = &aMem[pOp->p1];
@@ -55323,7 +65633,7 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
** Interpret the data that cursor P1 points to as a structure built using
** the MakeRecord instruction. (See the MakeRecord opcode for additional
** information about the format of the data.) Extract the P2-th column
-** from this record. If there are less that (P2+1)
+** from this record. If there are less that (P2+1)
** values in the record, extract a NULL.
**
** The value extracted is stored in register P3.
@@ -55360,6 +65670,7 @@ case OP_Column: {
u32 szField; /* Number of bytes in the content of a field */
int szHdr; /* Size of the header size field at start of record */
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.am */
@@ -55371,7 +65682,7 @@ case OP_Column: {
assert( u.am.p1nCursor );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
u.am.pDest = &aMem[pOp->p3];
- MemSetTypeFlag(u.am.pDest, MEM_Null);
+ memAboutToChange(p, u.am.pDest);
u.am.zRec = 0;
/* This block sets the variable u.am.payloadSize to be the total number of
@@ -55415,9 +65726,10 @@ case OP_Column: {
rc = sqlite3BtreeDataSize(u.am.pCrsr, &u.am.payloadSize);
assert( rc==SQLITE_OK ); /* DataSize() cannot fail */
}
- }else if( u.am.pC->pseudoTableReg>0 ){
+ }else if( ALWAYS(u.am.pC->pseudoTableReg>0) ){
u.am.pReg = &aMem[u.am.pC->pseudoTableReg];
assert( u.am.pReg->flags & MEM_Blob );
+ assert( memIsValid(u.am.pReg) );
u.am.payloadSize = u.am.pReg->n;
u.am.zRec = u.am.pReg->z;
u.am.pC->cacheStatus = (pOp->p5&OPFLAG_CLEARCACHE) ? CACHE_STALE : p->cacheCtr;
@@ -55427,9 +65739,10 @@ case OP_Column: {
u.am.payloadSize = 0;
}
- /* If u.am.payloadSize is 0, then just store a NULL */
+ /* If u.am.payloadSize is 0, then just store a NULL. This can happen because of
+ ** nullRow or because of a corrupt database. */
if( u.am.payloadSize==0 ){
- assert( u.am.pDest->flags&MEM_Null );
+ MemSetTypeFlag(u.am.pDest, MEM_Null);
goto op_column_out;
}
assert( db->aLimit[SQLITE_LIMIT_LENGTH]>=0 );
@@ -55536,8 +65849,14 @@ case OP_Column: {
for(u.am.i=0; u.am.ip4type==P4_MEM ){
sqlite3VdbeMemShallowCopy(u.am.pDest, pOp->p4.pMem, MEM_Static);
}else{
- assert( u.am.pDest->flags&MEM_Null );
+ MemSetTypeFlag(u.am.pDest, MEM_Null);
}
}
@@ -55642,6 +65961,7 @@ case OP_Affinity: {
pIn1 = &aMem[pOp->p1];
while( (u.an.cAff = *(u.an.zAffinity++))!=0 ){
assert( pIn1 <= &p->aMem[p->nMem] );
+ assert( memIsValid(pIn1) );
ExpandBlob(pIn1);
applyAffinity(pIn1, u.an.cAff, encoding);
pIn1++;
@@ -55651,12 +65971,9 @@ case OP_Affinity: {
/* Opcode: MakeRecord P1 P2 P3 P4 *
**
-** Convert P2 registers beginning with P1 into a single entry
-** suitable for use as a data record in a database table or as a key
-** in an index. The details of the format are irrelevant as long as
-** the OP_Column opcode can decode the record later.
-** Refer to source code comments for the details of the record
-** format.
+** Convert P2 registers beginning with P1 into the [record format]
+** use as a data record in a database table or as a key
+** in an index. The OP_Column opcode can decode the record later.
**
** P4 may be a string that is P2 characters long. The nth character of the
** string indicates the column affinity that should be used for the nth
@@ -55703,7 +66020,6 @@ case OP_MakeRecord: {
*/
u.ao.nData = 0; /* Number of bytes of data space */
u.ao.nHdr = 0; /* Number of bytes of header space */
- u.ao.nByte = 0; /* Data space required for this record */
u.ao.nZero = 0; /* Number of zero bytes at the end of the record */
u.ao.nField = pOp->p1;
u.ao.zAffinity = pOp->p4.z;
@@ -55713,10 +66029,16 @@ case OP_MakeRecord: {
u.ao.pLast = &u.ao.pData0[u.ao.nField-1];
u.ao.file_format = p->minWriteFileFormat;
+ /* Identify the output register */
+ assert( pOp->p3p1 || pOp->p3>=pOp->p1+pOp->p2 );
+ pOut = &aMem[pOp->p3];
+ memAboutToChange(p, pOut);
+
/* Loop through the elements that will make up the record to figure
** out how much space is required for the new record.
*/
for(u.ao.pRec=u.ao.pData0; u.ao.pRec<=u.ao.pLast; u.ao.pRec++){
+ assert( memIsValid(u.ao.pRec) );
if( u.ao.zAffinity ){
applyAffinity(u.ao.pRec, u.ao.zAffinity[u.ao.pRec-u.ao.pData0], encoding);
}
@@ -55751,8 +66073,6 @@ case OP_MakeRecord: {
** be one of the input registers (because the following call to
** sqlite3VdbeMemGrow() could clobber the value before it is used).
*/
- assert( pOp->p3p1 || pOp->p3>=pOp->p1+pOp->p2 );
- pOut = &aMem[pOp->p3];
if( sqlite3VdbeMemGrow(pOut, (int)u.ao.nByte, 0) ){
goto no_mem;
}
@@ -55785,7 +66105,7 @@ case OP_MakeRecord: {
/* Opcode: Count P1 P2 * * *
**
-** Store the number of entries (an integer value) in the table or index
+** Store the number of entries (an integer value) in the table or index
** opened by cursor P1 in register P2
*/
#ifndef SQLITE_OMIT_BTREECOUNT
@@ -55796,7 +66116,7 @@ case OP_Count: { /* out2-prerelease */
#endif /* local variables moved into u.ap */
u.ap.pCrsr = p->apCsr[pOp->p1]->pCursor;
- if( u.ap.pCrsr ){
+ if( ALWAYS(u.ap.pCrsr) ){
rc = sqlite3BtreeCount(u.ap.pCrsr, &u.ap.nEntry);
}else{
u.ap.nEntry = 0;
@@ -55846,6 +66166,17 @@ case OP_Savepoint: {
}else{
u.aq.nName = sqlite3Strlen30(u.aq.zName);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ /* This call is Ok even if this savepoint is actually a transaction
+ ** savepoint (and therefore should not prompt xSavepoint()) callbacks.
+ ** If this is a transaction savepoint being opened, it is guaranteed
+ ** that the db->aVTrans[] array is empty. */
+ assert( db->autoCommit==0 || db->nVTrans==0 );
+ rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN,
+ db->nStatement+db->nSavepoint);
+ if( rc!=SQLITE_OK ) goto abort_due_to_error;
+#endif
+
/* Create a new savepoint structure. */
u.aq.pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+u.aq.nName+1);
if( u.aq.pNew ){
@@ -55924,7 +66255,8 @@ case OP_Savepoint: {
}
if( u.aq.p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){
sqlite3ExpirePreparedStatements(db);
- sqlite3ResetInternalSchema(db, 0);
+ sqlite3ResetInternalSchema(db, -1);
+ db->flags = (db->flags | SQLITE_InternChanges);
}
}
@@ -55951,6 +66283,11 @@ case OP_Savepoint: {
}else{
db->nDeferredCons = u.aq.pSavepoint->nDeferredCons;
}
+
+ if( !isTransaction ){
+ rc = sqlite3VtabSavepoint(db, u.aq.p1, u.aq.iSavepoint);
+ if( rc!=SQLITE_OK ) goto abort_due_to_error;
+ }
}
}
@@ -56067,7 +66404,7 @@ case OP_Transaction: {
#endif /* local variables moved into u.as */
assert( pOp->p1>=0 && pOp->p1nDb );
- assert( (p->btreeMask & (1<p1))!=0 );
+ assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 );
u.as.pBt = db->aDb[pOp->p1].pBt;
if( u.as.pBt ){
@@ -56090,7 +66427,11 @@ case OP_Transaction: {
db->nStatement++;
p->iStatement = db->nSavepoint + db->nStatement;
}
- rc = sqlite3BtreeBeginStmt(u.as.pBt, p->iStatement);
+
+ rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, p->iStatement-1);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3BtreeBeginStmt(u.as.pBt, p->iStatement);
+ }
/* Store the current value of the database handles deferred constraint
** counter. If the statement transaction needs to be rolled back,
@@ -56125,7 +66466,7 @@ case OP_ReadCookie: { /* out2-prerelease */
assert( pOp->p3=0 && u.at.iDbnDb );
assert( db->aDb[u.at.iDb].pBt!=0 );
- assert( (p->btreeMask & (1<btreeMask & (((yDbMask)1)<