summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorU-Andreas-PC\Andreas <abaumann@yahoo.com>2011-03-21 13:33:36 +0100
committerU-Andreas-PC\Andreas <abaumann@yahoo.com>2011-03-21 13:33:36 +0100
commit59c7bbb7bb618a770a4534a91e748de53203dd7a (patch)
treeb0104835b42efaafb4c08fec3cf0f248b9b1b57e
parentc441e797bc791a5c4d0935129dee42f2801cb794 (diff)
downloadsqlitexx-59c7bbb7bb618a770a4534a91e748de53203dd7a.tar.gz
sqlitexx-59c7bbb7bb618a770a4534a91e748de53203dd7a.tar.bz2
updated bundled sqlite for Windows to 3.7.5, tested on Windows 7
-rw-r--r--makefiles/nmake/config.mk5
-rw-r--r--sqlite-3.7.5/Makefile.W32 (renamed from sqlite-3.7.2/Makefile.W32)0
-rw-r--r--sqlite-3.7.5/sqlite3.c (renamed from sqlite-3.7.2/sqlite3.c)9311
-rw-r--r--sqlite-3.7.5/sqlite3.h (renamed from sqlite-3.7.2/sqlite3.h)922
-rw-r--r--sqlite-3.7.5/sqlite3ext.h (renamed from sqlite-3.7.2/sqlite3ext.h)42
5 files changed, 7181 insertions, 3099 deletions
diff --git a/makefiles/nmake/config.mk b/makefiles/nmake/config.mk
index c1b048c..5386cb3 100644
--- a/makefiles/nmake/config.mk
+++ b/makefiles/nmake/config.mk
@@ -14,11 +14,12 @@
# some versions of Visual Studio miss the mc.exe binary
#PLATFORM_SDK_DIR = C:\Program Files\Microsoft Platform SDK for Windows Server 2003 R2
-PLATFORM_SDK_DIR = C:\Programme\Microsoft Platform SDK for Windows Server 2003 R2
+#PLATFORM_SDK_DIR = C:\Programme\Microsoft Platform SDK for Windows Server 2003 R2
+PLATFORM_SDK_DIR = C:\Program Files\Microsoft SDKs\Windows\v7.0
# version of sqlite3
####################
# version of the sqlite3 library (amalgamation, is included as subdir)
-SQLITE_VERSION=3.7.2
+SQLITE_VERSION=3.7.5
diff --git a/sqlite-3.7.2/Makefile.W32 b/sqlite-3.7.5/Makefile.W32
index 5bb8070..5bb8070 100644
--- a/sqlite-3.7.2/Makefile.W32
+++ b/sqlite-3.7.5/Makefile.W32
diff --git a/sqlite-3.7.2/sqlite3.c b/sqlite-3.7.5/sqlite3.c
index 695de18..1083311 100644
--- a/sqlite-3.7.2/sqlite3.c
+++ b/sqlite-3.7.5/sqlite3.c
@@ -1,10 +1,10 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.7.2. By combining all the individual C code files into this
+** version 3.7.5. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a one 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
@@ -354,15 +354,21 @@
#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
@@ -644,9 +650,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.7.2"
-#define SQLITE_VERSION_NUMBER 3007002
-#define SQLITE_SOURCE_ID "2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3"
+#define SQLITE_VERSION "3.7.5"
+#define SQLITE_VERSION_NUMBER 3007005
+#define SQLITE_SOURCE_ID "2011-01-28 17:03:50 ed759d5a9edb3bba5f48f243df47be29e3fe8cd7"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -927,7 +933,7 @@ 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 /* Database lock protocol error */
@@ -1079,6 +1085,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
@@ -1147,7 +1165,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
@@ -1240,6 +1260,21 @@ struct sqlite3_io_methods {
** 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 specilized VFSes
+** that do require it.
*/
#define SQLITE_FCNTL_LOCKSTATE 1
#define SQLITE_GET_LOCKPROXYFILE 2
@@ -1247,6 +1282,9 @@ struct sqlite3_io_methods {
#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
+
/*
** CAPI3REF: Mutex Handle
@@ -1294,15 +1332,19 @@ 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
+** ^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].
**
@@ -1313,7 +1355,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
** 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:
**
** <ul>
@@ -1324,7 +1366,8 @@ typedef struct sqlite3_mutex sqlite3_mutex;
** <li> [SQLITE_OPEN_TRANSIENT_DB]
** <li> [SQLITE_OPEN_SUBJOURNAL]
** <li> [SQLITE_OPEN_MASTER_JOURNAL]
-** </ul>
+** <li> [SQLITE_OPEN_WAL]
+** </ul>)^
**
** The file I/O implementation can use the object type flags to
** change the way it deals with files. For example, an application
@@ -1343,10 +1386,11 @@ typedef struct sqlite3_mutex sqlite3_mutex;
** </ul>
**
** 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
@@ -1355,7 +1399,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
** It is <i>not</i> 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
@@ -1365,13 +1409,13 @@ 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]
+** ^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
@@ -1385,10 +1429,10 @@ typedef struct sqlite3_mutex sqlite3_mutex;
** 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()
+** 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
+** ^The xCurrentTimeInt64() method returns, as an integer, the Julian
** Day Number multipled by 86400000 (the number of milliseconds in
** a 24-hour day).
** ^SQLite will use the xCurrentTimeInt64() method to get the current
@@ -1785,7 +1829,7 @@ struct sqlite3_mem_methods {
** <ul>
** <li> [sqlite3_memory_used()]
** <li> [sqlite3_memory_highwater()]
-** <li> [sqlite3_soft_heap_limit()]
+** <li> [sqlite3_soft_heap_limit64()]
** <li> [sqlite3_status()]
** </ul>)^
** ^Memory allocation statistics are enabled by default unless SQLite is
@@ -1799,15 +1843,14 @@ struct sqlite3_mem_methods {
** aligned memory buffer from which the scrach 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.</dd>
**
** <dt>SQLITE_CONFIG_PAGECACHE</dt>
@@ -1827,8 +1870,7 @@ 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.</dd>
**
@@ -1957,8 +1999,14 @@ 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]</dd>
+** 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].)^</dd>
**
** </dl>
*/
@@ -2263,6 +2311,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 <b>result table</b> is memory data structure created by the
** [sqlite3_get_table()] interface. A result table records the
** complete query results from one or more queries.
@@ -2283,7 +2334,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:
**
** <blockquote><pre>
@@ -2307,7 +2358,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
** azResult&#91;5] = "28";
** azResult&#91;6] = "Cindy";
** azResult&#91;7] = "21";
-** </pre></blockquote>
+** </pre></blockquote>)^
**
** ^The sqlite3_get_table() function evaluates one or more
** semicolon-separated SQL statements in the zero-terminated UTF-8
@@ -2315,19 +2366,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 */
@@ -2352,7 +2403,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
@@ -2371,6 +2422,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
@@ -2434,6 +2487,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
@@ -2479,7 +2533,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
@@ -2737,17 +2793,28 @@ SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
/*
** 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.
@@ -2798,7 +2865,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** case the database must already exist, otherwise an error is returned.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt>
-** <dd>The database is opened for reading and writing, and is creates it if
+** <dd>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().</dd>)^
** </dl>
@@ -2806,7 +2873,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** 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,
+** [SQLITE_OPEN_SHAREDCACHE] and/or [SQLITE_OPEN_PRIVATECACHE] flags,
** then the behavior is undefined.
**
** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection
@@ -2931,17 +2998,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_<i>NAME</i> 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_<i>NAME</i>].
** (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
@@ -2970,7 +3042,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
**
** <dl>
** ^(<dt>SQLITE_LIMIT_LENGTH</dt>
-** <dd>The maximum size of any string or BLOB or table row.<dd>)^
+** <dd>The maximum size of any string or BLOB or table row, in bytes.<dd>)^
**
** ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt>
** <dd>The maximum length of an SQL statement, in bytes.</dd>)^
@@ -2988,7 +3060,9 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
**
** ^(<dt>SQLITE_LIMIT_VDBE_OP</dt>
** <dd>The maximum number of instructions in a virtual machine program
-** used to implement an SQL statement.</dd>)^
+** used to implement an SQL statement. This limit is not currently
+** enforced, though that might be added in some future release of
+** SQLite.</dd>)^
**
** ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt>
** <dd>The maximum number of arguments on a function.</dd>)^
@@ -3001,8 +3075,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** [GLOB] operators.</dd>)^
**
** ^(<dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt>
-** <dd>The maximum number of variables in an SQL statement that can
-** be bound.</dd>)^
+** <dd>The maximum index number of any [parameter] in an SQL statement.)^
**
** ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt>
** <dd>The maximum depth of recursion for triggers.</dd>)^
@@ -3074,12 +3147,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** <li>
** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it
** always used to do, [sqlite3_step()] will automatically recompile the SQL
-** statement and try to run it again. ^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.
** </li>
**
** <li>
@@ -3092,11 +3160,16 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** </li>
**
** <li>
-** ^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
** </li>
** </ol>
*/
@@ -3139,6 +3212,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:
+**
+** <blockquote><pre>
+** SELECT eval('DELETE FROM t1') FROM t2;
+** </pre></blockquote>
+**
+** 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}
**
@@ -3163,7 +3267,7 @@ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
** 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
@@ -3237,7 +3341,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
@@ -3358,6 +3465,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);
@@ -3523,13 +3632,17 @@ 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, it was required
-** after sqlite3_step() returned anything other than [SQLITE_ROW] that
-** [sqlite3_reset()] be called before any subsequent invocation of
-** sqlite3_step(). Failure to invoke [sqlite3_reset()] in this way 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].
+** 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.
**
** <b>Goofy Interface Alert:</b> In the legacy interface, the sqlite3_step()
** API always returns a generic error code, [SQLITE_ERROR], following any
@@ -3548,8 +3661,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);
@@ -3629,18 +3748,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
@@ -3685,10 +3812,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:
**
** <ul>
@@ -3701,22 +3828,22 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** <li> 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.</li>
-** </ul>)^
+** </ul>
**
** ^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:
**
** <ul>
** <li>sqlite3_column_text() followed by sqlite3_column_bytes()</li>
** <li>sqlite3_column_blob() followed by sqlite3_column_bytes()</li>
** <li>sqlite3_column_text16() followed by sqlite3_column_bytes16()</li>
-** </ul>)^
+** </ul>
**
** In other words, you should call sqlite3_column_text(),
** sqlite3_column_blob(), or sqlite3_column_text16() first to force the result
@@ -3754,17 +3881,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.
-**
-** ^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].
+** ^If the most recent evaluation of the statement encountered no errors or
+** 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].
+**
+** ^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);
@@ -3800,23 +3936,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 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
@@ -3826,10 +3964,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.
@@ -3841,13 +3979,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 poiners 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
@@ -3863,11 +4012,6 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** 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
@@ -3894,6 +4038,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
@@ -3937,7 +4092,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.
@@ -4240,46 +4395,79 @@ 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.
-**
-** ^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.
-**
-** 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 any more).
-** ^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 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).
+** 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 (eTextRep) must be one of the constants:
+** <ul>
+** <li> [SQLITE_UTF8],
+** <li> [SQLITE_UTF16LE],
+** <li> [SQLITE_UTF16BE],
+** <li> [SQLITE_UTF16], or
+** <li> [SQLITE_UTF16_ALIGNED].
+** </ul>)^
+** ^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.
+**
+** ^The fourth argument, pArg, is a application data pointer that is passed
+** through as the first argument to the collating function callback.
+**
+** ^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 alway 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:
+**
+** <ol>
+** <li> If A==B then B==A.
+** <li> If A==B and B==C then A==C.
+** <li> If A&lt;B THEN B&gt;A.
+** <li> If A&lt;B and B&lt;C then A&lt;C.
+** </ol>
+**
+** 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 <u>not</u> 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()].
*/
@@ -4287,14 +4475,14 @@ SQLITE_API int sqlite3_create_collation(
sqlite3*,
const char *zName,
int eTextRep,
- void*,
+ 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*,
+ void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*),
void(*xDestroy)(void*)
);
@@ -4302,7 +4490,7 @@ SQLITE_API int sqlite3_create_collation16(
sqlite3*,
const void *zName,
int eTextRep,
- void*,
+ void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*)
);
@@ -4391,16 +4579,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);
@@ -4622,40 +4813,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 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.
**
-** ^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.
+** ^If the argument N is zero then the soft heap limit is disabled.
**
-** ^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.
+** ^(The soft heap limit is not enforced in the current implementation
+** if one or more of following conditions are true:
**
-** ^(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.
+** <ul>
+** <li> The soft heap limit is set to zero.
+** <li> 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.
+** <li> An alternative page cache implementation is specifed using
+** [sqlite3_config]([SQLITE_CONFIG_PCACHE],...).
+** <li> The page cache allocates from its own memory pool supplied
+** by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than
+** from the heap.
+** </ul>)^
+**
+** 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 sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
+
+/*
+** CAPI3REF: Deprecated Soft Heap Limit Interface
+** DEPRECATED
**
-** 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.
+** 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 void sqlite3_soft_heap_limit(int);
+SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
+
/*
** CAPI3REF: Extract Metadata About A Column Of A Table
@@ -4779,34 +5003,47 @@ 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.
+** <blockquote><pre>
+** &nbsp; int xEntryPoint(
+** &nbsp; sqlite3 *db,
+** &nbsp; const char **pzErrMsg,
+** &nbsp; const struct sqlite3_api_routines *pThunk
+** &nbsp; );
+** </pre></blockquote>)^
+**
+** 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);
@@ -4986,7 +5223,9 @@ 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.
*/
@@ -5170,6 +5409,30 @@ SQLITE_API int sqlite3_blob_open(
);
/*
+** 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
**
** ^Closes an open [BLOB handle].
@@ -5445,7 +5708,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
@@ -5557,7 +5820,8 @@ 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
@@ -5576,7 +5840,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
@@ -5586,6 +5850,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()]
@@ -5642,7 +5912,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16
#define SQLITE_TESTCTRL_PGHDRSZ 17
-#define SQLITE_TESTCTRL_LAST 17
+#define SQLITE_TESTCTRL_SCRATCHMALLOC 18
+#define SQLITE_TESTCTRL_LAST 18
/*
** CAPI3REF: SQLite Runtime Status
@@ -5661,7 +5932,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
@@ -5701,7 +5972,8 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
** The value written into the *pCurrent parameter is undefined.</dd>)^
**
** ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt>
-** <dd>This parameter records the number of separate memory allocations.</dd>)^
+** <dd>This parameter records the number of separate memory allocations
+** currently checked out.</dd>)^
**
** ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt>
** <dd>This parameter returns the number of pages used out of the
@@ -5711,7 +5983,7 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
**
** ^(<dt>SQLITE_STATUS_PAGECACHE_OVERFLOW</dt>
** <dd>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
@@ -5734,7 +6006,7 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
**
** ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
** <dd>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
@@ -5783,6 +6055,9 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
** 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 int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
@@ -5804,6 +6079,28 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** <dd>This parameter returns the number of lookaside memory slots currently
** checked out.</dd>)^
**
+** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
+** <dd>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.
+** checked out.</dd>)^
+**
+** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt>
+** <dd>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.
+** checked out.</dd>)^
+**
+** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt>
+** <dd>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.
+** checked out.</dd>)^
+**
** ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
** <dd>This parameter returns the approximate number of of bytes of heap
** memory used by all pager caches associated with the database connection.)^
@@ -5826,11 +6123,14 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** </dd>
** </dl>
*/
-#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_MAX 3 /* Largest defined DBSTATUS */
+#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 */
/*
@@ -5909,32 +6209,42 @@ typedef struct sqlite3_pcache sqlite3_pcache;
**
** ^(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
+** 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() 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
+** 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() 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.
@@ -5942,47 +6252,52 @@ 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,
+** ^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() 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 xPagecount() method must return the number of pages currently
+** stored in the cache, both pinned and unpinned.
**
-** ^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 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
+** mimimum 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:
**
** <table border=1 width=85% align=center>
** <tr><th> createFlag <th> Behaviour when page is not already in cache
@@ -5991,36 +6306,35 @@ typedef struct sqlite3_pcache sqlite3_pcache;
** Otherwise return NULL.
** <tr><td> 2 <td> Make every effort to allocate a new page. Only return
** NULL if allocating a new page is effectively impossible.
-** </table>)^
+** </table>
**
-** 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.
**
** ^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
+** 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().)^
+** 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() 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.
**
@@ -6066,11 +6380,12 @@ typedef struct sqlite3_backup sqlite3_backup;
**
** 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:
@@ -6097,11 +6412,11 @@ typedef struct sqlite3_backup sqlite3_backup;
** 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
@@ -6118,7 +6433,7 @@ typedef struct sqlite3_backup sqlite3_backup;
** the source and destination databases specified by [sqlite3_backup] object B.
** ^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),
@@ -6132,7 +6447,7 @@ typedef struct sqlite3_backup sqlite3_backup;
** <li> the destination database was opened read-only, or
** <li> the destination database is using write-ahead-log journaling
** and the destination and source page sizes differ, or
-** <li> The destination database is an in-memory database and the
+** <li> the destination database is an in-memory database and the
** destination and source page sizes differ.
** </ol>)^
**
@@ -6463,7 +6778,8 @@ SQLITE_API void *sqlite3_wal_hook(
** from SQL.
**
** ^Every new [database connection] defaults to having the auto-checkpoint
-** enabled with a threshold of 1000 pages. The use of this interface
+** 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.
*/
@@ -6498,6 +6814,62 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
#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 <rtree> WHERE <rtree col> 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 ******************/
@@ -7068,6 +7440,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;
@@ -7174,16 +7547,15 @@ 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*);
@@ -7215,11 +7587,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*);
@@ -7661,12 +8039,12 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_VRename 132
#define OP_VUpdate 133
#define OP_Pagecount 134
-#define OP_Trace 135
-#define OP_Noop 136
-#define OP_Explain 137
+#define OP_MaxPgcnt 135
+#define OP_Trace 136
+#define OP_Noop 137
+#define OP_Explain 138
/* The following opcode values are never used */
-#define OP_NotUsed_138 138
#define OP_NotUsed_139 139
#define OP_NotUsed_140 140
@@ -7699,7 +8077,7 @@ typedef struct VdbeOpList VdbeOpList;
/* 104 */ 0x00, 0x0c, 0x45, 0x15, 0x01, 0x02, 0x00, 0x01,\
/* 112 */ 0x08, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x02,\
/* 120 */ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 128 */ 0x01, 0x00, 0x02, 0x01, 0x00, 0x00, 0x02, 0x00,\
+/* 128 */ 0x01, 0x00, 0x02, 0x01, 0x00, 0x00, 0x02, 0x02,\
/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04,\
/* 144 */ 0x04, 0x04,}
@@ -7840,6 +8218,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().
@@ -7883,7 +8262,7 @@ SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);
SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int);
SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
-SQLITE_PRIVATE void sqlite3PagerSetSafetyLevel(Pager*,int,int);
+SQLITE_PRIVATE void sqlite3PagerSetSafetyLevel(Pager*,int,int,int);
SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int);
SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int);
SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*);
@@ -8474,8 +8853,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()
@@ -8571,6 +8950,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 */
@@ -8649,6 +9029,7 @@ 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 */
@@ -8748,13 +9129,14 @@ struct sqlite3 {
#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 */
/*
** Bits of the sqlite3.flags field that are used by the
@@ -8767,6 +9149,7 @@ struct sqlite3 {
#define SQLITE_IndexSearch 0x08 /* Disable indexes for searching */
#define SQLITE_IndexCover 0x10 /* Disable index covering table */
#define SQLITE_GroupByOrder 0x20 /* Disable GROUPBY cover of ORDERBY */
+#define SQLITE_FactorOutConst 0x40 /* Disable factoring out constants */
#define SQLITE_OptMask 0xff /* Mask of all disablable opts */
/*
@@ -8797,6 +9180,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;
};
/*
@@ -8837,15 +9241,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
@@ -9065,6 +9469,7 @@ struct 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 */
@@ -9633,6 +10038,9 @@ struct SrcList {
u8 isPopulated; /* Temporary table associated with SELECT is populated */
u8 jointype; /* Type of join between this able and the previous */
u8 notIndexed; /* True if there is a NOT INDEXED clause */
+#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 */
@@ -9671,6 +10079,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 */
@@ -9755,6 +10164,7 @@ struct WhereInfo {
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 */
};
@@ -9830,6 +10240,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 */
};
/*
@@ -10025,6 +10436,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
@@ -10319,7 +10735,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
@@ -10343,7 +10758,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
@@ -10514,7 +10929,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);
@@ -10634,17 +11048,15 @@ 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**);
@@ -10690,7 +11102,7 @@ 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 int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
@@ -10761,7 +11173,9 @@ SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *);
SQLITE_PRIVATE KeyInfo *sqlite3IndexKeyinfo(Parse *, Index *);
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 *);
@@ -11388,6 +11802,9 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_OMIT_AUTOMATIC_INDEX
"OMIT_AUTOMATIC_INDEX",
#endif
+#ifdef SQLITE_OMIT_AUTORESET
+ "OMIT_AUTORESET",
+#endif
#ifdef SQLITE_OMIT_AUTOVACUUM
"OMIT_AUTOVACUUM",
#endif
@@ -11663,16 +12080,14 @@ typedef unsigned char Bool;
**
** 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 */
+ 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) */
- i64 lastRowid; /* Last rowid from a Next or NextIdx operation */
+ 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 */
@@ -11681,14 +12096,12 @@ struct VdbeCursor {
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 */
+ Bool isOrdered; /* True if the underlying table is BTREE_UNORDERED */
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 */
/* Result of last sqlite3BtreeMoveto() done by an OP_NotExists or
** OP_IsUnique opcode on this cursor. */
@@ -11720,26 +12133,34 @@ typedef struct VdbeCursor VdbeCursor;
** 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.
+** 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 */
- Op *aOp; /* Program instructions */
+ 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 */
+ Mem *aMem; /* Array of memory cells for parent frame */
int nMem; /* Number of entries in aMem */
- VdbeCursor **apCsr; /* Element of Vdbe cursors */
+ 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 */
+ VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */
};
#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
@@ -11752,29 +12173,27 @@ struct VdbeFrame {
/*
** 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.
+** 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. */
+ 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;
- 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 */
+#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() */
};
@@ -11790,9 +12209,6 @@ struct Mem {
** 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 */
@@ -11801,6 +12217,7 @@ struct Mem {
#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
@@ -11814,19 +12231,25 @@ struct Mem {
#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
@@ -11869,22 +12292,10 @@ struct sqlite3_context {
};
/*
-** 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()
+** 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
@@ -11897,31 +12308,31 @@ struct Set {
*/
struct Vdbe {
sqlite3 *db; /* The database connection that owns this statement */
- Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
+ 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[] */
- 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[] */
+ 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 */
- 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 */
+ ynVar nVar; /* Number of entries in aVar[] */
u32 cacheCtr; /* VdbeCursor row cache generation counter */
int pc; /* The program counter */
int rc; /* Value to return */
- char *zErrMsg; /* Error message written here */
+ u8 errorAction; /* Recovery action to do in case of an error */
+ u8 okVar; /* True if azVar[] has been initialized */
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 */
@@ -11933,18 +12344,21 @@ struct Vdbe {
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 iStatement; /* Statement number (or 0 if has not opened stmt) */
int aCounter[3]; /* Counters used by sqlite3_stmt_status() */
- char *zSql; /* Text of the SQL statement that generated this */
- void *pFree; /* Free this when deleting the vdbe */
+ BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
+#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 */
- int iStatement; /* Statement number (or 0 if has not opened stmt) */
+ 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 */
@@ -12015,6 +12429,10 @@ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*);
SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
SQLITE_PRIVATE void sqlite3VdbeMemStoreType(Mem *pMem);
+#ifdef SQLITE_DEBUG
+SQLITE_PRIVATE void sqlite3VdbeMemPrepareToChange(Vdbe*,Mem*);
+#endif
+
#ifndef SQLITE_OMIT_FOREIGN_KEY
SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *, int);
#else
@@ -12145,6 +12563,22 @@ 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
@@ -12372,12 +12806,6 @@ end_getDigits:
}
/*
-** 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:
**
@@ -12578,7 +13006,7 @@ static int parseDateOrTime(
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 ){
@@ -12586,9 +13014,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;
@@ -12809,8 +13235,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;
@@ -12865,8 +13292,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
@@ -13520,6 +13950,12 @@ SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
}
SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
int rc;
+ /* IMPLEMENTATION-OF: R-49045-42493 SQLite will use the xCurrentTimeInt64()
+ ** method to get the current date and time if that method is available
+ ** (if iVersion is 2 or greater and the function pointer is not NULL) and
+ ** will fall back to xCurrentTime() if xCurrentTimeInt64() is
+ ** unavailable.
+ */
if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){
rc = pVfs->xCurrentTimeInt64(pVfs, pTimeOut);
}else{
@@ -13903,7 +14339,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 ){
@@ -14309,6 +14745,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 ){
@@ -15578,7 +16015,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;
@@ -16500,7 +16937,7 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
** <li> SQLITE_MUTEX_STATIC_MEM2
** <li> SQLITE_MUTEX_STATIC_PRNG
** <li> SQLITE_MUTEX_STATIC_LRU
-** <li> SQLITE_MUTEX_STATIC_LRU2
+** <li> SQLITE_MUTEX_STATIC_PMEM
** </ul>
**
** The first two constants cause sqlite3_mutex_alloc() to create
@@ -16910,7 +17347,7 @@ static int winMutexEnd(void){
** <li> SQLITE_MUTEX_STATIC_MEM2
** <li> SQLITE_MUTEX_STATIC_PRNG
** <li> SQLITE_MUTEX_STATIC_LRU
-** <li> SQLITE_MUTEX_STATIC_LRU2
+** <li> SQLITE_MUTEX_STATIC_PMEM
** </ul>
**
** The first two constants cause sqlite3_mutex_alloc() to create
@@ -17103,69 +17540,34 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
*/
/*
-** 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);
- }
-}
-
-/*
** Attempt to release up to n bytes of non-essential memory currently
** held by SQLite. An example of non-essential memory is memory used to
** cache database pages that are not currently in use.
*/
SQLITE_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 */
/*
@@ -17179,17 +17581,100 @@ 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.
*/
SQLITE_PRIVATE int sqlite3MallocInit(void){
@@ -17201,37 +17686,46 @@ 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; i<sqlite3GlobalConfig.nScratch; i++){ mem0.aScratchFree[i] = i; }
- mem0.nScratchFree = sqlite3GlobalConfig.nScratch;
+ && sqlite3GlobalConfig.nScratch>0 ){
+ int i, n, sz;
+ ScratchFreeslot *pSlot;
+ sz = ROUNDDOWN8(sqlite3GlobalConfig.szScratch);
+ sqlite3GlobalConfig.szScratch = sz;
+ pSlot = (ScratchFreeslot*)sqlite3GlobalConfig.pScratch;
+ n = sqlite3GlobalConfig.nScratch;
+ mem0.pScratchFree = pSlot;
+ mem0.nScratchFree = n;
+ for(i=0; i<n-1; i++){
+ pSlot->pNext = (ScratchFreeslot*)(sz+(char*)pSlot);
+ pSlot = pSlot->pNext;
+ }
+ pSlot->pNext = 0;
+ mem0.pScratchEnd = (void*)&pSlot[1];
}else{
+ mem0.pScratchEnd = 0;
sqlite3GlobalConfig.pScratch = 0;
sqlite3GlobalConfig.szScratch = 0;
+ sqlite3GlobalConfig.nScratch = 0;
}
- 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<sqlite3GlobalConfig.nPage; i++){ mem0.aPageFree[i] = i; }
- mem0.nPageFree = sqlite3GlobalConfig.nPage;
- }else{
+ if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512
+ || sqlite3GlobalConfig.nPage<1 ){
sqlite3GlobalConfig.pPage = 0;
sqlite3GlobalConfig.szPage = 0;
+ sqlite3GlobalConfig.nPage = 0;
}
return sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData);
}
/*
+** Return true if the heap is currently under memory pressure - in other
+** words if the amount of heap used is close to the limit set by
+** sqlite3_soft_heap_limit().
+*/
+SQLITE_PRIVATE int sqlite3HeapNearlyFull(void){
+ return mem0.nearlyFull;
+}
+
+/*
** Deinitialize the memory allocation subsystem.
*/
SQLITE_PRIVATE void sqlite3MallocEnd(void){
@@ -17266,36 +17760,6 @@ SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
}
/*
-** Change the alarm callback
-*/
-SQLITE_PRIVATE int sqlite3MemoryAlarm(
- void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
- void *pArg,
- sqlite3_int64 iThreshold
-){
- sqlite3_mutex_enter(mem0.mutex);
- mem0.alarmCallback = xCallback;
- mem0.alarmArg = pArg;
- mem0.alarmThreshold = iThreshold;
- 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
-
-/*
** Trigger the alarm
*/
static void sqlite3MallocAlarm(int nByte){
@@ -17327,14 +17791,19 @@ static int mallocWithAlarm(int n, void **pp){
if( mem0.alarmCallback!=0 ){
int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
if( nUsed+nFull >= mem0.alarmThreshold ){
+ 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);
@@ -17350,7 +17819,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
@@ -17364,6 +17835,7 @@ SQLITE_PRIVATE void *sqlite3Malloc(int n){
}else{
p = sqlite3GlobalConfig.m.xMalloc(n);
}
+ assert( EIGHT_BYTE_ALIGNMENT(p) ); /* IMP: R-04675-44850 */
return p;
}
@@ -17402,59 +17874,65 @@ SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){
void *p;
assert( n>0 );
-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
- /* Verify that no more than two scratch allocation per thread
- ** is outstanding at one time. (This is only checked in the
- ** single-threaded case since checking in the multi-threaded case
- ** would be much more complicated.) */
- assert( scratchAllocOut<=1 );
-#endif
-
- if( sqlite3GlobalConfig.szScratch<n ){
- goto scratch_overflow;
- }else{
- sqlite3_mutex_enter(mem0.mutex);
- if( mem0.nScratchFree==0 ){
+ sqlite3_mutex_enter(mem0.mutex);
+ if( mem0.nScratchFree && sqlite3GlobalConfig.szScratch>=n ){
+ p = mem0.pScratchFree;
+ mem0.pScratchFree = mem0.pScratchFree->pNext;
+ mem0.nScratchFree--;
+ sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, 1);
+ sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n);
+ sqlite3_mutex_leave(mem0.mutex);
+ }else{
+ if( sqlite3GlobalConfig.bMemstat ){
+ sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n);
+ n = mallocWithAlarm(n, &p);
+ if( p ) sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, n);
sqlite3_mutex_leave(mem0.mutex);
- goto scratch_overflow;
}else{
- int i;
- i = mem0.aScratchFree[--mem0.nScratchFree];
- i *= sqlite3GlobalConfig.szScratch;
- sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, 1);
- sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n);
sqlite3_mutex_leave(mem0.mutex);
- p = (void*)&((char*)sqlite3GlobalConfig.pScratch)[i];
- assert( (((u8*)p - (u8*)0) & 7)==0 );
+ p = sqlite3GlobalConfig.m.xMalloc(n);
}
+ sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
}
-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
- scratchAllocOut = p!=0;
-#endif
+ assert( sqlite3_mutex_notheld(mem0.mutex) );
- return p;
-scratch_overflow:
- if( sqlite3GlobalConfig.bMemstat ){
- sqlite3_mutex_enter(mem0.mutex);
- 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);
- }
- sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
#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;
+
+ return p;
}
SQLITE_PRIVATE void sqlite3ScratchFree(void *p){
if( p ){
- if( sqlite3GlobalConfig.pScratch==0
- || p<sqlite3GlobalConfig.pScratch
- || p>=(void*)mem0.aScratchFree ){
+
+#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
+ /* Verify that no more than two scratch allocation per thread
+ ** is outstanding at one time. (This is only checked in the
+ ** single-threaded case since checking in the multi-threaded case
+ ** would be much more complicated.) */
+ assert( scratchAllocOut>=1 && scratchAllocOut<=2 );
+ scratchAllocOut--;
+#endif
+
+ if( p>=sqlite3GlobalConfig.pScratch && p<mem0.pScratchEnd ){
+ /* Release memory from the SQLITE_CONFIG_SCRATCH allocation */
+ ScratchFreeslot *pSlot;
+ pSlot = (ScratchFreeslot*)p;
+ sqlite3_mutex_enter(mem0.mutex);
+ pSlot->pNext = mem0.pScratchFree;
+ mem0.pScratchFree = pSlot;
+ mem0.nScratchFree++;
+ assert( mem0.nScratchFree<=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);
@@ -17469,26 +17947,6 @@ SQLITE_PRIVATE void sqlite3ScratchFree(void *p){
}else{
sqlite3GlobalConfig.m.xFree(p);
}
- }else{
- int i;
- i = (int)((u8*)p - (u8*)sqlite3GlobalConfig.pScratch);
- i /= sqlite3GlobalConfig.szScratch;
- assert( i>=0 && i<sqlite3GlobalConfig.nScratch );
- sqlite3_mutex_enter(mem0.mutex);
- assert( mem0.nScratchFree<(u32)sqlite3GlobalConfig.nScratch );
- mem0.aScratchFree[mem0.nScratchFree++] = i;
- sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, -1);
- sqlite3_mutex_leave(mem0.mutex);
-
-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
- /* Verify that no more than two scratch allocation per thread
- ** is outstanding at one time. (This is only checked in the
- ** single-threaded case since checking in the multi-threaded case
- ** would be much more complicated.) */
- assert( scratchAllocOut>=1 && scratchAllocOut<=2 );
- scratchAllocOut = 0;
-#endif
-
}
}
}
@@ -17529,7 +17987,7 @@ 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 ){
@@ -17576,10 +18034,10 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){
int nOld, nNew;
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 ){
@@ -17587,6 +18045,9 @@ 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;
@@ -17612,6 +18073,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;
}
@@ -17678,14 +18140,20 @@ SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, int n){
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
@@ -18597,6 +19065,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 ){
@@ -18607,13 +19076,12 @@ SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
p->nAlloc = (int)szNew;
}
if( p->useMalloc==1 ){
- zNew = sqlite3DbMallocRaw(p->db, p->nAlloc );
+ zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
}else{
- zNew = sqlite3_malloc(p->nAlloc);
+ 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;
@@ -18768,21 +19236,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_snprintf(int n, char *zBuf, const char *zFormat, ...){
- char *z;
- va_list ap;
+SQLITE_API char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){
StrAccum acc;
-
- if( n<=0 ){
- return zBuf;
- }
+ if( n<=0 ) return zBuf;
sqlite3StrAccumInit(&acc, zBuf, n, 0);
acc.useMalloc = 0;
- va_start(ap,zFormat);
sqlite3VXPrintf(&acc, 0, zFormat, ap);
+ return sqlite3StrAccumFinish(&acc);
+}
+SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
+ char *z;
+ va_list ap;
+ va_start(ap,zFormat);
+ z = sqlite3_vsnprintf(n, zBuf, zFormat, ap);
va_end(ap);
- z = sqlite3StrAccumFinish(&acc);
return z;
}
@@ -19775,6 +20250,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;
@@ -19792,121 +20273,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.
-*/
-SQLITE_PRIVATE int sqlite3IsNumber(const char *z, int *realnum, u8 enc){
- 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.
+** 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]
**
-** This routine assumes that z[] really is a valid number. If it
-** is not, the result is undefined.
+** Leading and trailing whitespace is ignored for the purpose of determining
+** validity.
**
-** 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.
+** If some prefix of the input string is a valid number, this routine
+** returns FALSE but it still converts the prefix and writes the result
+** into *pResult.
*/
-SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult){
+SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){
#ifndef SQLITE_OMIT_FLOATING_POINT
- const char *zBegin = z;
+ int incr = (enc==SQLITE_UTF8?1:2);
+ 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 && sqlite3Isspace(*z) ) z+=incr;
+ if( 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 && z[0]=='0' ) z+=incr, nDigits++;
/* copy max significant digits to significand */
- while( sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
+ while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
s = s*10 + (*z - '0');
- z++, nDigits++;
+ z+=incr, nDigits++;
}
+
/* skip non-significant significand digits
** (increase exponent by d to shift decimal left) */
- while( sqlite3Isdigit(*z) ) z++, nDigits++, d++;
+ while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++, d++;
+ if( 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 && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
s = s*10 + (*z - '0');
- z++, nDigits++, d--;
+ z+=incr, nDigits++, d--;
}
/* skip non-significant digits */
- while( sqlite3Isdigit(*z) ) z++, nDigits++;
+ while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++;
}
+ if( z>=zEnd ) goto do_atof_calc;
/* if exponent is present */
if( *z=='e' || *z=='E' ){
- z++;
+ 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( z<zEnd && sqlite3Isdigit(*z) ){
e = e*10 + (*z - '0');
- z++;
+ z+=incr;
+ eValid = 1;
}
}
+ /* skip trailing spaces */
+ if( nDigits && eValid ){
+ while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
+ }
+
+do_atof_calc:
/* adjust exponent by d, and update sign */
e = (e*esign) + d;
if( e<0 ) {
@@ -19965,10 +20436,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 */
}
@@ -19976,20 +20447,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) );
@@ -19999,94 +20476,60 @@ 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 and write
+** the value of the integer into *pNum.
+** If zNum is exactly 9223372036854665808, return 2.
+** This is a special case as the context will determine
+** if it is too big (used as a negative).
+** If zNum is not an integer or is an integer that
+** is too large to be expressed with 64 bits,
+** then return 1. Otherwise return 0.
**
-** 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.
+** 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){
+SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
+ int incr = (enc==SQLITE_UTF8?1:2);
i64 v = 0;
- int neg;
- int i, c;
+ int neg = 0; /* assume positive */
+ int i;
+ int c = 0;
const char *zStart;
- while( sqlite3Isspace(*zNum) ) zNum++;
+ const char *zEnd = zNum + length;
+ if( enc==SQLITE_UTF16BE ) zNum++;
+ while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr;
+ if( zNum>=zEnd ) goto do_atoi_calc;
if( *zNum=='-' ){
neg = 1;
- zNum++;
+ zNum+=incr;
}else if( *zNum=='+' ){
- neg = 0;
- zNum++;
- }else{
- neg = 0;
+ zNum+=incr;
}
+do_atoi_calc:
zStart = zNum;
- while( zNum[0]=='0' ){ zNum++; } /* Skip over leading zeros. Ticket #2454 */
- for(i=0; (c=zNum[i])>='0' && c<='9'; i++){
+ while( zNum<zEnd && zNum[0]=='0' ){ zNum+=incr; } /* Skip leading zeros. */
+ for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){
v = v*10 + c - '0';
}
*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]<zEnd) || (i==0 && zStart==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 ){
- /* Less than 19 digits, so we know that it fits in 64 bits */
+ ** 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 0;
}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)<neg;
- }
-}
-
-/*
-** The string zNum represents an unsigned integer. The zNum string
-** consists of one or more digit characters and is terminated by
-** a zero character. Any stray characters in zNum result in undefined
-** behavior.
-**
-** If the unsigned integer that zNum represents will fit in a
-** 64-bit signed integer, return TRUE. Otherwise return FALSE.
-**
-** If the negFlag parameter is true, that means that zNum really represents
-** a negative number. (The leading "-" is omitted from zNum.) This
-** parameter is needed to determine a boundary case. A string
-** of "9223373036854775808" returns false if negFlag is false or true
-** if negFlag is true.
-**
-** Leading zeros are ignored.
-*/
-SQLITE_PRIVATE int sqlite3FitsIn64Bits(const char *zNum, int negFlag){
- int i;
- int neg = 0;
-
- assert( zNum[0]>='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 */
- return 0;
- }else{
- /* Compare against 2^63. */
- return compare2pow63(zNum)<neg;
+ ** is 2^63. Return 1 if to large */
+ c=compare2pow63(zNum, incr);
+ if( c==0 && neg==0 ) return 2; /* too big, exactly 9223372036854665808 */
+ return c<neg ? 0 : 1;
}
}
@@ -20134,6 +20577,16 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){
}
/*
+** 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:
**
** KEY:
@@ -21062,10 +21515,10 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 132 */ "VRename",
/* 133 */ "VUpdate",
/* 134 */ "Pagecount",
- /* 135 */ "Trace",
- /* 136 */ "Noop",
- /* 137 */ "Explain",
- /* 138 */ "NotUsed_138",
+ /* 135 */ "MaxPgcnt",
+ /* 136 */ "Trace",
+ /* 137 */ "Noop",
+ /* 138 */ "Explain",
/* 139 */ "NotUsed_139",
/* 140 */ "NotUsed_140",
/* 141 */ "ToText",
@@ -21819,7 +22272,7 @@ static int os2FileControl(sqlite3_file *id, int op, void *pArg){
return SQLITE_OK;
}
}
- return SQLITE_ERROR;
+ return SQLITE_NOTFOUND;
}
/*
@@ -22535,7 +22988,9 @@ SQLITE_API int sqlite3_os_end(void){
#include <unistd.h>
#include <sys/time.h>
#include <errno.h>
+#ifndef SQLITE_OMIT_WAL
#include <sys/mman.h>
+#endif
#if SQLITE_ENABLE_LOCKING_STYLE
# include <sys/ioctl.h>
@@ -25753,8 +26208,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;
}
/*
@@ -26179,7 +26637,7 @@ static int unixShmMap(
pShmNode->apRegion = apNew;
while(pShmNode->nRegion<=iRegion){
void *pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE,
- MAP_SHARED, pShmNode->h, iRegion*szRegion
+ MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion
);
if( pMem==MAP_FAILED ){
rc = SQLITE_IOERR;
@@ -26697,11 +27155,21 @@ static int fillInUnixFile(
*/
UNUSED_PARAMETER(isDelete);
+ /* 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;
pNew->fileFlags = 0;
- assert( zFilename==0 || zFilename[0]=='/' ); /* Never a relative pathname */
pNew->zPath = zFilename;
#if OS_VXWORKS
@@ -27041,9 +27509,24 @@ static int findCreateFileMode(
int nDb; /* Number of valid bytes in zDb */
struct stat sStat; /* Output of stat() on database file */
- nDb = sqlite3Strlen30(zPath) - ((flags & SQLITE_OPEN_WAL) ? 4 : 8);
+ /* zPath is a path to a WAL or journal file. The following block derives
+ ** the path to the associated database file from zPath. This block handles
+ ** the following naming conventions:
+ **
+ ** "<path to db>-journal"
+ ** "<path to db>-wal"
+ ** "<path to db>-journal-NNNN"
+ ** "<path to db>-wal-NNNN"
+ **
+ ** where NNNN is a 4 digit decimal number. The NNNN naming schemes are
+ ** used by the test_multiplex.c module.
+ */
+ nDb = sqlite3Strlen30(zPath) - 1;
+ while( nDb>0 && zPath[nDb]!='l' ) nDb--;
+ nDb -= ((flags & SQLITE_OPEN_WAL) ? 3 : 7);
memcpy(zDb, zPath, nDb);
zDb[nDb] = '\0';
+
if( 0==stat(zDb, &sStat) ){
*pMode = sStat.st_mode & 0777;
}else{
@@ -27458,7 +27941,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();
@@ -27595,7 +28078,7 @@ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
#if defined(NO_GETTOD)
time_t t;
time(&t);
- *piNow = ((sqlite3_int64)i)*1000 + unixEpoch;
+ *piNow = ((sqlite3_int64)t)*1000 + unixEpoch;
#elif OS_VXWORKS
struct timespec sNow;
clock_gettime(CLOCK_REALTIME, &sNow);
@@ -27998,17 +28481,21 @@ extern int gethostuuid(uuid_t id, const struct timespec *wait);
** 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;
}
+#endif
#ifdef SQLITE_TEST
/* simulate multiple hosts by creating unique hostid file paths */
if( sqlite3_hostid_num != 0){
@@ -28049,27 +28536,27 @@ static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){
pathLen = strlcpy(tPath, cPath, MAXPATHLEN);
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);
if( readLen<PROXY_PATHINDEX ){
- sprintf(errmsg, "read error (len %d)", (int)readLen);
+ sqlite3_snprintf(sizeof(errmsg),errmsg,"read error (len %d)",(int)readLen);
goto end_breaklock;
}
/* write it out to the temporary break file */
fd = open(tPath, (O_RDWR|O_CREAT|O_EXCL), SQLITE_DEFAULT_FILE_PERMISSIONS);
if( fd<0 ){
- sprintf(errmsg, "create failed (%d)", errno);
+ sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)", errno);
goto end_breaklock;
}
if( pwrite(fd, buf, readLen, 0) != (ssize_t)readLen ){
- sprintf(errmsg, "write failed (%d)", errno);
+ sqlite3_snprintf(sizeof(errmsg), errmsg, "write failed (%d)", errno);
goto end_breaklock;
}
if( rename(tPath, cPath) ){
- sprintf(errmsg, "rename failed (%d)", errno);
+ sqlite3_snprintf(sizeof(errmsg), errmsg, "rename failed (%d)", errno);
goto end_breaklock;
}
rc = 0;
@@ -30312,8 +30799,11 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
SimulateIOErrorBenign(0);
return SQLITE_OK;
}
+ case SQLITE_FCNTL_SYNC_OMITTED: {
+ return SQLITE_OK;
+ }
}
- return SQLITE_ERROR;
+ return SQLITE_NOTFOUND;
}
/*
@@ -30341,6 +30831,14 @@ static int winDeviceCharacteristics(sqlite3_file *id){
#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
@@ -30509,6 +31007,7 @@ static int winDelete(sqlite3_vfs *,const char*,int);
static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
winShmNode **pp;
winShmNode *p;
+ BOOL bRc;
assert( winShmMutexHeld() );
pp = &winShmNodeList;
while( (p = *pp)!=0 ){
@@ -30516,8 +31015,14 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
int i;
if( p->mutex ) sqlite3_mutex_free(p->mutex);
for(i=0; i<p->nRegion; i++){
- UnmapViewOfFile(p->aRegion[i].pMap);
- CloseHandle(p->aRegion[i].hMap);
+ 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);
@@ -30594,10 +31099,11 @@ static int winOpenSharedMemory(winFile *pDbFd){
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_READWRITE | SQLITE_OPEN_CREATE, /* Mode flags */
+ SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, /* Mode flags */
0);
if( SQLITE_OK!=rc ){
rc = SQLITE_CANTOPEN_BKPT;
@@ -30905,10 +31411,18 @@ static int winShmMap(
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, 0, nByte
+ 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();
@@ -30925,8 +31439,10 @@ static int winShmMap(
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[iRegion*szRegion];
+ *pp = (void *)&p[iOffsetShift];
}else{
*pp = 0;
}
@@ -31153,9 +31669,60 @@ 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 */
+
+ /* 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);
@@ -31166,7 +31733,8 @@ static int winOpen(
** 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;
}
@@ -31179,29 +31747,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"
** 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;
@@ -31218,6 +31788,7 @@ static int winOpen(
#if SQLITE_OS_WINCE
dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
#endif
+
if( isNT() ){
h = CreateFileW((WCHAR*)zConverted,
dwDesiredAccess,
@@ -31243,26 +31814,30 @@ static int winOpen(
);
#endif
}
+
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();
free(zConverted);
- if( flags & SQLITE_OPEN_READWRITE ){
+ if( isReadWrite ){
return winOpen(pVfs, zName, id,
- ((flags|SQLITE_OPEN_READONLY)&~SQLITE_OPEN_READWRITE), pOutFlags);
+ ((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;
@@ -31271,9 +31846,9 @@ static int winOpen(
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);
@@ -31287,8 +31862,9 @@ static int winOpen(
{
free(zConverted);
}
+
OpenCounter(+1);
- return SQLITE_OK;
+ return rc;
}
/*
@@ -31807,6 +32383,13 @@ SQLITE_API int sqlite3_os_init(void){
winCurrentTimeInt64, /* xCurrentTimeInt64 */
};
+#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;
}
@@ -32371,12 +32954,16 @@ static void pcacheUnpin(PgHdr *p){
*/
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);
}
}
@@ -32836,24 +33423,62 @@ 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;
+
+/* 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 */
+};
-/* Pointers to structures of this type are cast and returned as
-** opaque sqlite3_pcache* handles
+/* 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
** 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 */
@@ -32889,18 +33514,27 @@ struct PgFreeslot {
** Global data used by this cache.
*/
static SQLITE_WSD struct PCacheGlobal {
- sqlite3_mutex *mutex; /* static mutex MUTEX_STATIC_LRU */
-
- 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 */
+ PGroup grp; /* The global PGroup for mode (2) */
+
+ /* Variables related to SQLITE_CONFIG_PAGECACHE settings. The
+ ** szSlot, nSlot, pStart, pEnd, nReserve, and isInit values are all
+ ** fixed at sqlite3_initialize() time and do not require mutex protection.
+ ** The nFreeSlot and pFree values do require mutex protection.
+ */
+ int isInit; /* True if initialized */
+ int szSlot; /* Size of each free slot */
+ int nSlot; /* The number of pcache slots */
+ int nReserve; /* Try to keep nFreeSlot above this */
+ void *pStart, *pEnd; /* Bounds of pagecache malloc range */
+ /* Above requires no mutex. Use mutex below for variable that follow. */
+ sqlite3_mutex *mutex; /* Mutex for accessing the following: */
+ 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;
/*
@@ -32926,10 +33560,10 @@ 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.
+** Macros to enter and leave the PCache LRU mutex.
*/
-#define pcache1EnterMutex() sqlite3_mutex_enter(pcache1.mutex)
-#define pcache1LeaveMutex() sqlite3_mutex_leave(pcache1.mutex)
+#define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex)
+#define pcache1LeaveMutex(X) sqlite3_mutex_leave((X)->mutex)
/******************************************************************************/
/******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/
@@ -32939,14 +33573,20 @@ static SQLITE_WSD struct PCacheGlobal {
** 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;
@@ -32962,30 +33602,36 @@ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
** 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) );
+ void *p = 0;
+ assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
- if( nByte<=pcache1.szSlot && pcache1.pFree ){
- assert( pcache1.isInit );
+ if( nByte<=pcache1.szSlot ){
+ sqlite3_mutex_enter(pcache1.mutex);
p = (PgHdr1 *)pcache1.pFree;
- pcache1.pFree = pcache1.pFree->pNext;
- 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<pcache1.nReserve;
+ assert( pcache1.nFreeSlot>=0 );
+ sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
+ }
+ sqlite3_mutex_leave(pcache1.mutex);
+ }
+ if( p==0 ){
+ /* Memory is not available in the SQLITE_CONFIG_PAGECACHE pool. Get
+ ** it from sqlite3Malloc instead.
*/
- 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);
}
@@ -32996,30 +33642,35 @@ 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 && p<pcache1.pEnd ){
PgFreeslot *pSlot;
+ sqlite3_mutex_enter(pcache1.mutex);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, -1);
pSlot = (PgFreeslot*)p;
pSlot->pNext = pcache1.pFree;
pcache1.pFree = pSlot;
+ pcache1.nFreeSlot++;
+ pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
+ assert( pcache1.nFreeSlot<=pcache1.nSlot );
+ sqlite3_mutex_leave(pcache1.mutex);
}else{
int iSize;
assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
iSize = sqlite3MallocSize(p);
+ sqlite3_mutex_enter(pcache1.mutex);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize);
+ sqlite3_mutex_leave(pcache1.mutex);
sqlite3_free(p);
}
}
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/*
-** Return the size of a pache allocation
+** Return the size of a pcache allocation
*/
static int pcache1MemSize(void *p){
- assert( sqlite3_mutex_held(pcache1.mutex) );
if( p>=pcache1.pStart && p<pcache1.pEnd ){
return pcache1.szSlot;
}else{
@@ -33043,7 +33694,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
if( pPg ){
p = PAGE_TO_PGHDR1(pCache, pPg);
if( pCache->bPurgeable ){
- pcache1.nCurrentPage++;
+ pCache->pGroup->nCurrentPage++;
}
}else{
p = 0;
@@ -33060,8 +33711,9 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
*/
static void pcache1FreePage(PgHdr1 *p){
if( ALWAYS(p) ){
- if( p->pCache->bPurgeable ){
- pcache1.nCurrentPage--;
+ PCache1 *pCache = p->pCache;
+ if( pCache->bPurgeable ){
+ pCache->pGroup->nCurrentPage--;
}
pcache1Free(PGHDR1_TO_PAGE(p));
}
@@ -33073,20 +33725,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();
+ }
}
/******************************************************************************/
@@ -33096,25 +33767,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; i<p->nHash; i++){
@@ -33137,25 +33808,33 @@ 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
+** 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;
@@ -33168,13 +33847,14 @@ static void pcache1PinPage(PgHdr1 *pPage){
** 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;
@@ -33183,13 +33863,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);
@@ -33201,15 +33882,15 @@ static void pcache1EnforceMaxPage(void){
** 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; h<pCache->nHash; h++){
PgHdr1 **pp = &pCache->apHash[h];
PgHdr1 *pPage;
@@ -33239,8 +33920,10 @@ 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;
}
@@ -33262,18 +33945,47 @@ 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 */
+
+ /*
+ ** 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
- pCache = (PCache1 *)sqlite3_malloc(sizeof(PCache1));
+ 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_g.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;
@@ -33287,11 +33999,14 @@ static sqlite3_pcache *pcache1Create(int szPage, int bPurgeable){
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);
}
}
@@ -33300,9 +34015,10 @@ static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
*/
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;
}
@@ -33330,14 +34046,16 @@ static int pcache1Pagecount(sqlite3_pcache *p){
** 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.
+** 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:
@@ -33349,6 +34067,9 @@ static int pcache1Pagecount(sqlite3_pcache *p){
** 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.
@@ -33356,30 +34077,50 @@ static int pcache1Pagecount(sqlite3_pcache *p){
** 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;
}
@@ -33388,18 +34129,22 @@ 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);
}
}
@@ -33407,7 +34152,11 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
** attempt to allocate a new one.
*/
if( !pPage ){
+ if( createFlag==1 ) sqlite3BeginBenignMalloc();
+ pcache1LeaveMutex(pGroup);
pPage = pcache1AllocPage(pCache);
+ pcache1EnterMutex(pGroup);
+ if( createFlag==1 ) sqlite3EndBenignMalloc();
}
if( pPage ){
@@ -33426,8 +34175,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);
}
@@ -33440,37 +34188,34 @@ 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.
+ ** 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);
}
/*
@@ -33489,7 +34234,7 @@ static void pcache1Rekey(
assert( pPage->iKey==iOld );
assert( pPage->pCache==pCache );
- pcache1EnterMutex();
+ pcache1EnterMutex(pCache->pGroup);
h = iOld%pCache->nHash;
pp = &pCache->apHash[h];
@@ -33506,7 +34251,7 @@ static void pcache1Rekey(
pCache->iMaxKey = iNew;
}
- pcache1LeaveMutex();
+ pcache1LeaveMutex(pCache->pGroup);
}
/*
@@ -33518,12 +34263,12 @@ 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);
}
/*
@@ -33533,12 +34278,15 @@ static void pcache1Truncate(sqlite3_pcache *p, unsigned int iLimit){
*/
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);
}
@@ -33577,16 +34325,18 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void){
*/
SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
int nFree = 0;
+ assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
+ assert( sqlite3_mutex_notheld(pcache1.mutex) );
if( pcache1.pStart==0 ){
PgHdr1 *p;
- pcache1EnterMutex();
- while( (nReq<0 || nFree<nReq) && (p=pcache1.pLruTail) ){
+ pcache1EnterMutex(&pcache1.grp);
+ while( (nReq<0 || nFree<nReq) && ((p=pcache1.grp.pLruTail)!=0) ){
nFree += pcache1MemSize(PGHDR1_TO_PAGE(p));
pcache1PinPage(p);
pcache1RemoveFromHash(p);
pcache1FreePage(p);
}
- pcache1LeaveMutex();
+ pcache1LeaveMutex(&pcache1.grp);
}
return nFree;
}
@@ -33605,12 +34355,12 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
){
PgHdr1 *p;
int nRecyclable = 0;
- for(p=pcache1.pLruHead; p; p=p->pLruNext){
+ 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
@@ -34100,6 +34850,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 i
# define sqlite3WalCheckpoint(u,v,w,x) 0
# define sqlite3WalCallback(z) 0
# define sqlite3WalExclusiveMode(y,z) 0
+# define sqlite3WalHeapMemory(z) 0
#else
#define WAL_SAVEPOINT_NDATA 4
@@ -34110,7 +34861,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 i
typedef struct Wal Wal;
/* Open and close a connection to a write-ahead log. */
-SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *zName, Wal**);
+SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *zName, int, Wal**);
SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
/* Used by readers to open (lock) and close (unlock) a snapshot. A
@@ -34167,6 +34918,12 @@ SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal);
*/
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_ */
@@ -34766,7 +35523,8 @@ struct Pager {
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 */
@@ -35077,7 +35835,9 @@ static int assert_pager_state(Pager *p){
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
@@ -35201,7 +35961,7 @@ static int write32bits(sqlite3_file *fd, i64 offset, u32 val){
static int pagerUnlockDb(Pager *pPager, int eLock){
int rc = SQLITE_OK;
- assert( !pPager->exclusiveMode );
+ assert( !pPager->exclusiveMode || pPager->eLock==eLock );
assert( eLock==NO_LOCK || eLock==SHARED_LOCK );
assert( eLock!=NO_LOCK || pagerUseWal(pPager)==0 );
if( isOpen(pPager->fd) ){
@@ -35448,7 +36208,7 @@ 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
@@ -36625,15 +37385,21 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
&& (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, &currentSize);
- 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;
@@ -36897,10 +37663,10 @@ end_playback:
rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
testcase( rc!=SQLITE_OK );
}
- if( rc==SQLITE_OK && !pPager->noSync
+ if( rc==SQLITE_OK
&& (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
){
- rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
+ rc = sqlite3PagerSync(pPager);
}
if( rc==SQLITE_OK ){
rc = pager_end_transaction(pPager, zMaster[0]!='\0');
@@ -37063,24 +37829,61 @@ static int pagerRollbackWal(Pager *pPager){
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);
+}
+
/*
** 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.
+** 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 sync_flags /* Flags to pass to OsSync() (or 0) */
+ 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( pList->pgno==1 ) pager_write_changecounter(pList);
rc = sqlite3WalFrames(pPager->pWal,
- pPager->pageSize, pList, nTruncate, isCommit, sync_flags
+ pPager->pageSize, pList, nTruncate, isCommit, syncFlags
);
if( rc==SQLITE_OK && pPager->pBackup ){
PgHdr *p;
@@ -37090,9 +37893,8 @@ static int pagerWalFrames(
}
#ifdef SQLITE_CHECK_PAGES
- {
- PgHdr *p;
- for(p=pList; p; p=p->pDirty) pager_set_pagehash(p);
+ for(p=pList; p; p=p->pDirty){
+ pager_set_pagehash(p);
}
#endif
@@ -37122,12 +37924,13 @@ static int pagerBeginReadTransaction(Pager *pPager){
sqlite3WalEndReadTransaction(pPager->pWal);
rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed);
- if( rc==SQLITE_OK && changed ){
+ if( rc!=SQLITE_OK || changed ){
pager_reset(pPager);
}
return rc;
}
+#endif
/*
** This function is called as part of the transition from PAGER_OPEN
@@ -37184,7 +37987,7 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
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
@@ -37409,14 +38212,49 @@ 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->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
@@ -37595,9 +38433,8 @@ SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
if( mxPage>0 ){
pPager->mxPgno = mxPage;
}
- if( pPager->eState!=PAGER_OPEN && pPager->mxPgno<pPager->dbSize ){
- pPager->mxPgno = pPager->dbSize;
- }
+ assert( pPager->eState!=PAGER_OPEN ); /* Called only by OP_MaxPgcnt */
+ assert( pPager->mxPgno>=pPager->dbSize ); /* OP_MaxPgcnt enforces this */
return pPager->mxPgno;
}
@@ -37802,10 +38639,7 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){
/* pPager->errCode = 0; */
pPager->exclusiveMode = 0;
#ifndef SQLITE_OMIT_WAL
- sqlite3WalClose(pPager->pWal,
- (pPager->noSync ? 0 : pPager->sync_flags),
- pPager->pageSize, pTmp
- );
+ sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, pTmp);
pPager->pWal = 0;
#endif
pager_reset(pPager);
@@ -37971,7 +38805,7 @@ static int syncJournal(Pager *pPager, int newHdr){
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));
@@ -37983,8 +38817,8 @@ static int syncJournal(Pager *pPager, int newHdr){
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;
}
@@ -38085,6 +38919,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
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);
@@ -38377,6 +39212,13 @@ 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.
@@ -38387,17 +39229,8 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
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);
if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){
/* This branch is taken when the journal path required by
@@ -38452,19 +39285,15 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
/* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */
if( zPathname ){
+ assert( nPathname>0 );
pPager->zJournal = (char*)(pPtr += nPathname + 1);
memcpy(pPager->zFilename, zPathname, nPathname);
memcpy(pPager->zJournal, zPathname, nPathname);
memcpy(&pPager->zJournal[nPathname], "-journal", 8);
- if( pPager->zFilename[0]==0 ){
- pPager->zJournal[0] = 0;
- }
#ifndef SQLITE_OMIT_WAL
- else{
- pPager->zWal = &pPager->zJournal[nPathname+8+1];
- memcpy(pPager->zWal, zPathname, nPathname);
- memcpy(&pPager->zWal[nPathname], "-wal", 4);
- }
+ pPager->zWal = &pPager->zJournal[nPathname+8+1];
+ memcpy(pPager->zWal, zPathname, nPathname);
+ memcpy(&pPager->zWal[nPathname], "-wal", 4);
#endif
sqlite3_free(zPathname);
}
@@ -38473,9 +39302,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,
@@ -38579,7 +39409,8 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
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; */
@@ -38679,7 +39510,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
sqlite3BeginBenignMalloc();
if( pagerLockDb(pPager, RESERVED_LOCK)==SQLITE_OK ){
sqlite3OsDelete(pVfs, pPager->zJournal, 0);
- pagerUnlockDb(pPager, SHARED_LOCK);
+ if( !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK);
}
sqlite3EndBenignMalloc();
}else{
@@ -38929,7 +39760,9 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
** 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) ){
@@ -39358,29 +40191,29 @@ static int pager_write(PgHdr *pPg){
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) ){
assert( !pagerUseWal(pPager) );
- assert( pPager->eState>=PAGER_WRITER_CACHEMOD );
}else{
-
- /* If we get this far, it means that the page needs to be
- ** written to the transaction journal or the checkpoint journal
- ** or both.
- **
- ** 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.
- */
- 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) );
/* The transaction journal now exists and we have a RESERVED or an
** EXCLUSIVE lock on the main database file. Write the current page to
@@ -39607,7 +40440,13 @@ SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *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.
+** byte offset 24 of the pager file. The secondary change counter at
+** 92 is also updated, as is the SQLite version number at offset 96.
+**
+** But this only happens if the pPager->changeCountDone flag is false.
+** To avoid excess churning of page 1, the update only happens once.
+** See also the pager_write_changecounter() routine that does an
+** unconditional update of the change counters.
**
** If the isDirectMode flag is zero, then this is done by calling
** sqlite3PagerWrite() on page 1, then modifying the contents of the
@@ -39648,7 +40487,6 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
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) );
@@ -39666,16 +40504,8 @@ 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);
-
- /* 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*)pPgHdr->pData)+92, change_counter);
- put32bits(((char*)pPgHdr->pData)+96, SQLITE_VERSION_NUMBER);
+ /* 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 ){
@@ -39700,19 +40530,20 @@ 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;
}
@@ -39801,7 +40632,7 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
if( pList ){
rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1,
- (pPager->fullSync ? pPager->sync_flags : 0)
+ (pPager->fullSync ? pPager->syncFlags : 0)
);
}
if( rc==SQLITE_OK ){
@@ -39931,8 +40762,8 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
}
/* Finally, sync the database file. */
- if( !pPager->noSync && !noSync ){
- rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
+ if( !noSync ){
+ rc = sqlite3PagerSync(pPager);
}
IOTRACE(("DBSYNC %p\n", pPager))
}
@@ -40044,7 +40875,17 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
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;
+ }
}else{
rc = pager_playback(pPager, 0);
}
@@ -40503,7 +41344,8 @@ 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;
@@ -40672,10 +41514,8 @@ SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager){
int rc = SQLITE_OK;
if( pPager->pWal ){
u8 *zBuf = (u8 *)pPager->pTmpSpace;
- rc = sqlite3WalCheckpoint(pPager->pWal,
- (pPager->noSync ? 0 : pPager->sync_flags),
- pPager->pageSize, zBuf
- );
+ rc = sqlite3WalCheckpoint(pPager->pWal, pPager->ckptSyncFlags,
+ pPager->pageSize, zBuf);
}
return rc;
}
@@ -40690,10 +41530,62 @@ SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
*/
SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){
const sqlite3_io_methods *pMethods = pPager->fd->pMethods;
- return pMethods->iVersion>=2 && pMethods->xShmMap!=0;
+ 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 pending lock failed, release the
+ ** exclusive 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->pWal
+ );
+ }
+
+ return rc;
+}
+
+
+/*
** The caller must be holding a SHARED lock on the database file to call
** this function.
**
@@ -40726,11 +41618,7 @@ SQLITE_PRIVATE int sqlite3PagerOpenWal(
/* Close any rollback journal previously open */
sqlite3OsClose(pPager->jfd);
- /* Open the connection to the log file. If this operation fails,
- ** (e.g. due to malloc() failure), unlock the database file and
- ** return an error code.
- */
- rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, &pPager->pWal);
+ rc = pagerOpenWal(pPager);
if( rc==SQLITE_OK ){
pPager->journalMode = PAGER_JOURNALMODE_WAL;
pPager->eState = PAGER_OPEN;
@@ -40769,8 +41657,7 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
);
}
if( rc==SQLITE_OK && logexists ){
- rc = sqlite3WalOpen(pPager->pVfs, pPager->fd,
- pPager->zWal, &pPager->pWal);
+ rc = pagerOpenWal(pPager);
}
}
@@ -40778,17 +41665,11 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
** the database file, the log and log-summary files will be deleted.
*/
if( rc==SQLITE_OK && pPager->pWal ){
- rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
+ rc = pagerExclusiveLock(pPager);
if( rc==SQLITE_OK ){
- rc = sqlite3WalClose(pPager->pWal,
- (pPager->noSync ? 0 : pPager->sync_flags),
- pPager->pageSize, (u8*)pPager->pTmpSpace
- );
+ rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags,
+ pPager->pageSize, (u8*)pPager->pTmpSpace);
pPager->pWal = 0;
- }else{
- /* If we cannot get an EXCLUSIVE lock, downgrade the PENDING lock
- ** that we did get back to SHARED. */
- pagerUnlockDb(pPager, SQLITE_LOCK_SHARED);
}
}
return rc;
@@ -41245,6 +42126,13 @@ struct Wal {
};
/*
+** Candidate values for Wal.exclusiveMode.
+*/
+#define WAL_NORMAL_MODE 0
+#define WAL_EXCLUSIVE_MODE 1
+#define WAL_HEAPMEMORY_MODE 2
+
+/*
** Each page of the wal-index mapping contains a hash-table made up of
** an array of HASHTABLE_NSLOT elements of the following type.
*/
@@ -41267,14 +42155,14 @@ typedef u16 ht_slot;
*/
struct WalIterator {
int iPrior; /* Last result returned from the iterator */
- int nSegment; /* Size of the aSegment[] array */
+ 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; /* Max size of aPgno[] and aIndex[] arrays */
+ 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 */
+ } aSegment[1]; /* One for every 32KB page in the wal-index */
};
/*
@@ -41330,9 +42218,14 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
/* Request a pointer to the required page from the VFS */
if( pWal->apWiData[iPage]==0 ){
- rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
- pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
- );
+ 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]
+ );
+ }
}
*ppPage = pWal->apWiData[iPage];
@@ -41415,6 +42308,12 @@ static void walChecksumBytes(
aOut[1] = s2;
}
+static void walShmBarrier(Wal *pWal){
+ if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
+ sqlite3OsShmBarrier(pWal->pDbFd);
+ }
+}
+
/*
** Write the header information in pWal->hdr into the wal-index.
**
@@ -41429,7 +42328,7 @@ static void walIndexWriteHdr(Wal *pWal){
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));
- sqlite3OsShmBarrier(pWal->pDbFd);
+ walShmBarrier(pWal);
memcpy((void *)&aHdr[0], (void *)&pWal->hdr, sizeof(WalIndexHdr));
}
@@ -42001,7 +42900,15 @@ recovery_error:
** Close an open wal-index.
*/
static void walIndexClose(Wal *pWal, int isDelete){
- sqlite3OsShmUnmap(pWal->pDbFd, isDelete);
+ if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
+ int i;
+ for(i=0; i<pWal->nWiData; i++){
+ sqlite3_free((void *)pWal->apWiData[i]);
+ pWal->apWiData[i] = 0;
+ }
+ }else{
+ sqlite3OsShmUnmap(pWal->pDbFd, isDelete);
+ }
}
/*
@@ -42023,6 +42930,7 @@ 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 */
Wal **ppWal /* OUT: Allocated Wal handle */
){
int rc; /* Return Code */
@@ -42056,6 +42964,7 @@ SQLITE_PRIVATE int sqlite3WalOpen(
pRet->pDbFd = pDbFd;
pRet->readLock = -1;
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);
@@ -42117,9 +43026,29 @@ static int walIteratorNext(
/*
** This function merges two sorted lists into a single sorted list.
+**
+** aLeft[] and aRight[] are arrays of indices. The sort key is
+** aContent[aLeft[]] and aContent[aRight[]]. Upon entry, the following
+** is guaranteed for all J<K:
+**
+** aContent[aLeft[J]] < aContent[aLeft[K]]
+** aContent[aRight[J]] < aContent[aRight[K]]
+**
+** This routine overwrites aRight[] with a new (probably longer) sequence
+** of indices such that the aRight[] contains every index that appears in
+** either aLeft[] or the old aRight[] and such that the second condition
+** above is still met.
+**
+** The aContent[aLeft[X]] values will be unique for all X. And the
+** aContent[aRight[X]] values will be unique too. But there might be
+** one or more combinations of X and Y such that
+**
+** aLeft[X]!=aRight[Y] && aContent[aLeft[X]] == aContent[aRight[Y]]
+**
+** When that happens, omit the aLeft[X] and use the aRight[Y] index.
*/
static void walMerge(
- u32 *aContent, /* Pages in wal */
+ const u32 *aContent, /* Pages in wal - keys for the sort */
ht_slot *aLeft, /* IN: Left hand input list */
int nLeft, /* IN: Elements in array *paLeft */
ht_slot **paRight, /* IN/OUT: Right hand input list */
@@ -42159,10 +43088,24 @@ static void walMerge(
}
/*
-** Sort the elements in list aList, removing any duplicates.
+** Sort the elements in list aList using aContent[] as the sort key.
+** Remove elements with duplicate keys, preferring to keep the
+** larger aList[] values.
+**
+** The aList[] entries are indices into aContent[]. The values in
+** aList[] are to be sorted so that for all J<K:
+**
+** aContent[aList[J]] < aContent[aList[K]]
+**
+** For any X and Y such that
+**
+** aContent[aList[X]] == aContent[aList[Y]]
+**
+** Keep the larger of the two values aList[X] and aList[Y] and discard
+** the smaller.
*/
static void walMergesort(
- u32 *aContent, /* Pages in wal */
+ const u32 *aContent, /* Pages in wal */
ht_slot *aBuffer, /* Buffer of at least *pnList items to use */
ht_slot *aList, /* IN/OUT: List to sort */
int *pnList /* IN/OUT: Number of elements in aList[] */
@@ -42227,6 +43170,7 @@ static void walIteratorFree(WalIterator *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
@@ -42361,7 +43305,8 @@ static int walCheckpoint(
szPage = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
testcase( szPage<=32768 );
testcase( szPage>=65536 );
- if( pWal->hdr.mxFrame==0 ) return SQLITE_OK;
+ pInfo = walCkptInfo(pWal);
+ if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
/* Allocate the iterator */
rc = walIteratorInit(pWal, &pIter);
@@ -42383,7 +43328,6 @@ static int walCheckpoint(
*/
mxSafeFrame = pWal->hdr.mxFrame;
mxPage = pWal->hdr.nPage;
- pInfo = walCkptInfo(pWal);
for(i=1; i<WAL_NREADER; i++){
u32 y = pInfo->aReadMark[i];
if( mxSafeFrame>=y ){
@@ -42489,7 +43433,9 @@ SQLITE_PRIVATE int sqlite3WalClose(
*/
rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
if( rc==SQLITE_OK ){
- pWal->exclusiveMode = 1;
+ if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
+ pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
+ }
rc = sqlite3WalCheckpoint(pWal, sync_flags, nBuf, zBuf);
if( rc==SQLITE_OK ){
isDelete = 1;
@@ -42545,7 +43491,7 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){
*/
aHdr = walIndexHdr(pWal);
memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
- sqlite3OsShmBarrier(pWal->pDbFd);
+ walShmBarrier(pWal);
memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
@@ -42746,7 +43692,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
** and can be safely ignored.
*/
rc = walLockShared(pWal, WAL_READ_LOCK(0));
- sqlite3OsShmBarrier(pWal->pDbFd);
+ 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
@@ -42840,7 +43786,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
** log-wrap (either of which would require an exclusive lock on
** WAL_READ_LOCK(mxI)) has not occurred since the snapshot was valid.
*/
- sqlite3OsShmBarrier(pWal->pDbFd);
+ walShmBarrier(pWal);
if( pInfo->aReadMark[mxI]!=mxReadMark
|| memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
){
@@ -43182,7 +44128,7 @@ SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
**
** 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 some error
+** if an error occurs.
*/
static int walRestartLog(Wal *pWal){
int rc = SQLITE_OK;
@@ -43215,6 +44161,8 @@ static int walRestartLog(Wal *pWal){
for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
assert( pInfo->aReadMark[0]==0 );
walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
+ }else if( rc!=SQLITE_BUSY ){
+ return rc;
}
}
walUnlockShared(pWal, WAL_READ_LOCK(0));
@@ -43294,7 +44242,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
return rc;
}
}
- assert( pWal->szPage==szPage );
+ assert( (int)pWal->szPage==szPage );
/* Write the log file. */
for(p=pList; p; p=p->pDirty){
@@ -43481,13 +44429,14 @@ SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){
** 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
+** 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
@@ -43521,6 +44470,15 @@ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
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 *************************************************/
@@ -43954,16 +44912,17 @@ struct BtShared {
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
+ 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 */
- u8 doNotUseWAL; /* If true, do not open write-ahead-log file */
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) */
@@ -43990,8 +44949,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 */
@@ -44033,20 +44992,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 */
};
/*
@@ -45450,14 +46409,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
@@ -46204,11 +47158,20 @@ 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
@@ -46230,22 +47193,38 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
u8 nReserve; /* Byte of unused space on each page */
unsigned char zDbHeader[100]; /* Database header content */
+ /* 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. This symbol is only required if
- ** either of the shared-data or autovacuum features are compiled
- ** into the library.
+ ** 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( sqlite3_mutex_held(db->mutex) );
+ assert( (flags&0xff)==flags ); /* flags fit in 8 bits */
+
+ /* 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;
+ }
pVfs = db->pVfs;
p = sqlite3MallocZero(sizeof(Btree));
if( !p ){
@@ -46263,7 +47242,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);
@@ -46338,6 +47317,7 @@ 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;
@@ -46442,6 +47422,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) );
@@ -46599,11 +47587,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;
}
@@ -46878,7 +47872,7 @@ static int lockBtree(BtShared *pBt){
pageSize-usableSize);
return rc;
}
- if( nPageHeader>nPageFile ){
+ if( (pBt->db->flags & SQLITE_RecoveryMode)==0 && nPageHeader>nPageFile ){
rc = SQLITE_CORRUPT_BKPT;
goto page1_init_failed;
}
@@ -47661,8 +48655,8 @@ static void btreeEndTransaction(Btree *p){
** are no active cursors, it also releases the read lock.
*/
SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p){
- BtShared *pBt = p->pBt;
+ if( p->inTrans==TRANS_NONE ) return SQLITE_OK;
sqlite3BtreeEnter(p);
btreeIntegrity(p);
@@ -47671,6 +48665,7 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p){
*/
if( p->inTrans==TRANS_WRITE ){
int rc;
+ BtShared *pBt = p->pBt;
assert( pBt->inTransaction==TRANS_WRITE );
assert( pBt->nTransaction>0 );
rc = sqlite3PagerCommitPhaseTwo(pBt->pPager);
@@ -51392,11 +52387,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 );
@@ -51515,8 +52511,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;
}
@@ -52582,8 +53584,7 @@ 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
@@ -52744,6 +53745,16 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
}
/*
+** 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
** a pointer to the new sqlite3_backup object.
@@ -52776,7 +53787,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);
@@ -52793,10 +53807,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;
@@ -53053,32 +54068,46 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
*/
const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
+ i64 iOff;
+ i64 iEnd;
assert( pFile );
assert( (i64)nDestTruncate*(i64)pgszDest >= iSize || (
nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
&& iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
));
- if( SQLITE_OK==(rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1))
- && SQLITE_OK==(rc = backupTruncateFile(pFile, iSize))
- && SQLITE_OK==(rc = sqlite3PagerSync(pDestPager))
+
+ /* 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+pgszSrc;
+ rc==SQLITE_OK && iOff<iEnd;
+ iOff+=pgszSrc
){
- i64 iOff;
- i64 iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
- for(
- iOff=PENDING_BYTE+pgszSrc;
- rc==SQLITE_OK && iOff<iEnd;
- iOff+=pgszSrc
- ){
- PgHdr *pSrcPg = 0;
- const Pgno iSrcPg = (Pgno)((iOff/pgszSrc)+1);
- rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
- if( rc==SQLITE_OK ){
- u8 *zData = sqlite3PagerGetData(pSrcPg);
- rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
- }
- sqlite3PagerUnref(pSrcPg);
+ PgHdr *pSrcPg = 0;
+ const Pgno iSrcPg = (Pgno)((iOff/pgszSrc)+1);
+ rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
+ if( rc==SQLITE_OK ){
+ u8 *zData = sqlite3PagerGetData(pSrcPg);
+ rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
}
+ sqlite3PagerUnref(pSrcPg);
+ }
+ if( rc==SQLITE_OK ){
+ rc = backupTruncateFile(pFile, iSize);
+ }
+
+ /* Sync the database file to disk. */
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerSync(pDestPager);
}
}else{
rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0);
@@ -53159,6 +54188,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);
@@ -53410,6 +54442,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;
@@ -53530,7 +54565,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));
@@ -53643,13 +54678,9 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){
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);
+ assert( pMem->z || pMem->n==0 );
+ testcase( pMem->z==0 );
+ sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
return value;
}else{
return 0;
@@ -53672,14 +54703,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... */
@@ -53752,21 +54776,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;
}
@@ -53775,7 +54797,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);
@@ -53871,6 +54895,28 @@ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){
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.
*/
@@ -54239,7 +55285,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);
@@ -54287,6 +55333,8 @@ SQLITE_PRIVATE int sqlite3ValueFromExpr(
int op;
char *zVal = 0;
sqlite3_value *pVal = 0;
+ int negInt = 1;
+ const char *zNeg = "";
if( !pExpr ){
*ppVal = 0;
@@ -54304,13 +55352,24 @@ SQLITE_PRIVATE int sqlite3ValueFromExpr(
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;
@@ -54320,14 +55379,18 @@ 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) ){
+ sqlite3VdbeMemNumerify(pVal);
pVal->u.i = -1 * pVal->u.i;
/* (double)-1 In case of SQLITE_OMIT_FLOATING_POINT... */
pVal->r = (double)-1 * pVal->r;
+ sqlite3ValueApplyAffinity(pVal, affinity, enc);
}
}
#ifndef SQLITE_OMIT_BLOB_LITERAL
@@ -54807,7 +55870,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 ){
@@ -55581,12 +56644,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 );
@@ -55631,7 +56692,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;
}
@@ -55938,6 +56999,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);
+ }
}
/*
@@ -56154,9 +57220,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;
}
@@ -57620,6 +58687,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;
@@ -57696,7 +58765,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);
}
@@ -57898,11 +58967,30 @@ static int sqlite3Step(Vdbe *p){
assert(p);
if( p->magic!=VDBE_MAGIC_RUN ){
/* We used to require that sqlite3_reset() be called before retrying
- ** sqlite3_step() after any error. But after 3.6.23, we changed this
- ** so that sqlite3_reset() would be called automatically instead of
- ** throwing the error.
+ ** 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. */
@@ -57944,7 +59032,9 @@ static int sqlite3Step(Vdbe *p){
}else
#endif /* SQLITE_OMIT_EXPLAIN */
{
+ db->vdbeExecCnt++;
rc = sqlite3VdbeExec(p);
+ db->vdbeExecCnt--;
}
#ifndef SQLITE_OMIT_TRACE
@@ -58050,6 +59140,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 );
@@ -58232,7 +59328,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
#if defined(SQLITE_DEBUG) && defined(__GNUC__)
__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, 0, 0 };
if( pVm && ALWAYS(pVm->db) ){
sqlite3_mutex_enter(pVm->db->mutex);
@@ -58259,8 +59355,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)
{
@@ -58528,6 +59623,12 @@ static int vdbeUnbind(Vdbe *p, int i){
/* 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)
@@ -58564,6 +59665,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;
}
@@ -58807,6 +59910,14 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){
}
/*
+** Return true if the prepared statement is guaranteed to not modify the
+** database.
+*/
+SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){
+ 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
** prepared statement for the database connection. Return NULL if there
@@ -58880,9 +59991,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.
@@ -58913,63 +60027,72 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
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);
+ if( db->vdbeExecCnt>1 ){
+ while( *zRawSql ){
+ const char *zStart = zRawSql;
+ while( *(zRawSql++)!='\n' && *zRawSql );
+ sqlite3StrAccumAppend(&out, "-- ", 3);
+ sqlite3StrAccumAppend(&out, zStart, zRawSql-zStart);
+ }
+ }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{
- 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 ){
+ 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);
- }
- }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; i<pVar->n; i++){
- sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
+ {
+ 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; i<pVar->n; i++){
+ sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
+ }
+ sqlite3StrAccumAppend(&out, "'", 1);
}
- sqlite3StrAccumAppend(&out, "'", 1);
}
}
return sqlite3StrAccumFinish(&out);
@@ -59026,6 +60149,17 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
*/
/*
+** 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
** procedures use this information to make sure that indices are
@@ -59217,31 +60351,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;
}
}
}
@@ -59293,13 +60413,13 @@ 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;
}
@@ -60134,6 +61254,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
assert( pOp->p2>0 );
assert( pOp->p2<=p->nMem );
pOut = &aMem[pOp->p2];
+ memAboutToChange(p, pOut);
sqlite3VdbeMemReleaseExternal(pOut);
pOut->flags = MEM_Int;
}
@@ -60143,25 +61264,30 @@ 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
@@ -60223,6 +61349,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);
@@ -60430,11 +61557,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 );
@@ -60492,6 +61615,8 @@ 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);
@@ -60537,6 +61662,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;
}
@@ -60597,6 +61725,10 @@ case OP_ResultRow: {
*/
u.ad.pMem = p->pResultSet = &aMem[pOp->p1];
for(u.ad.i=0; u.ad.i<pOp->p2; 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]);
@@ -60828,12 +61960,17 @@ 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->p3<pOp->p2 || pOp->p3>=pOp->p2+u.ag.n );
u.ag.pArg = &aMem[pOp->p2];
for(u.ag.i=0; u.ag.i<u.ag.n; u.ag.i++, u.ag.pArg++){
+ assert( memIsValid(u.ag.pArg) );
u.ag.apVal[u.ag.i] = u.ag.pArg;
+ Deephemeralize(u.ag.pArg);
sqlite3VdbeMemStoreType(u.ag.pArg);
REGISTER_TRACE(pOp->p2+u.ag.i, u.ag.pArg);
}
@@ -60847,8 +61984,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;
@@ -60868,7 +62003,7 @@ 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);
+ (*u.ag.ctx.pFunc->xFunc)(&u.ag.ctx, u.ag.n, u.ag.apVal); /* IMP: R-24505-23230 */
if( db->mallocFailed ){
/* Even though a malloc() has failed, the implementation of the
** user function may have called an sqlite3_result_XXX() function
@@ -60920,7 +62055,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.
*/
@@ -60970,6 +62105,7 @@ 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;
@@ -61029,6 +62165,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;
@@ -61075,16 +62212,14 @@ case OP_ToBlob: { /* same as TK_TO_BLOB, in1 */
*/
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.
@@ -61111,6 +62246,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);
}
@@ -61125,7 +62261,7 @@ case OP_ToReal: { /* same as TK_TO_REAL, in1 */
**
** If the SQLITE_JUMPIFNULL bit of P5 is set and either reg(P1) or
** reg(P3) is NULL then take the jump. If the SQLITE_JUMPIFNULL
-** bit is clear then fall thru if either operand is NULL.
+** bit is clear then fall through if either operand is NULL.
**
** The SQLITE_AFF_MASK portion of P5 must be an affinity character -
** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made
@@ -61255,6 +62391,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);
@@ -61286,8 +62423,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
@@ -61329,6 +62466,8 @@ case OP_Compare: {
#endif /* SQLITE_DEBUG */
for(u.aj.i=0; u.aj.i<u.aj.n; u.aj.i++){
u.aj.idx = aPermute ? aPermute[u.aj.i] : u.aj.i;
+ assert( memIsValid(&aMem[u.aj.p1+u.aj.idx]) );
+ assert( memIsValid(&aMem[u.aj.p2+u.aj.idx]) );
REGISTER_TRACE(u.aj.p1+u.aj.idx, &aMem[u.aj.p1+u.aj.idx]);
REGISTER_TRACE(u.aj.p2+u.aj.idx, &aMem[u.aj.p2+u.aj.idx]);
assert( u.aj.i<u.aj.pKeyInfo->nField );
@@ -61560,6 +62699,7 @@ case OP_Column: {
assert( u.am.p1<p->nCursor );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
u.am.pDest = &aMem[pOp->p3];
+ memAboutToChange(p, u.am.pDest);
MemSetTypeFlag(u.am.pDest, MEM_Null);
u.am.zRec = 0;
@@ -61607,6 +62747,7 @@ case OP_Column: {
}else if( 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;
@@ -61831,6 +62972,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++;
@@ -61840,12 +62982,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
@@ -61902,10 +63041,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->p3<pOp->p1 || 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);
}
@@ -61940,8 +63085,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->p3<pOp->p1 || pOp->p3>=pOp->p1+pOp->p2 );
- pOut = &aMem[pOp->p3];
if( sqlite3VdbeMemGrow(pOut, (int)u.ao.nByte, 0) ){
goto no_mem;
}
@@ -62114,6 +63257,7 @@ case OP_Savepoint: {
if( u.aq.p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){
sqlite3ExpirePreparedStatements(db);
sqlite3ResetInternalSchema(db, 0);
+ db->flags = (db->flags | SQLITE_InternChanges);
}
}
@@ -62504,6 +63648,8 @@ case OP_OpenWrite: {
assert( u.aw.p2>0 );
assert( u.aw.p2<=p->nMem );
pIn2 = &aMem[u.aw.p2];
+ assert( memIsValid(pIn2) );
+ assert( (pIn2->flags & MEM_Int)!=0 );
sqlite3VdbeMemIntegerify(pIn2);
u.aw.p2 = (int)pIn2->u.i;
/* The u.aw.p2 value always comes from a prior OP_CreateTable opcode and
@@ -62526,6 +63672,7 @@ case OP_OpenWrite: {
u.aw.pCur = allocateCursor(p, pOp->p1, u.aw.nField, u.aw.iDb, 1);
if( u.aw.pCur==0 ) goto no_mem;
u.aw.pCur->nullRow = 1;
+ u.aw.pCur->isOrdered = 1;
rc = sqlite3BtreeCursor(u.aw.pX, u.aw.p2, u.aw.wrFlag, u.aw.pKeyInfo, u.aw.pCur->pCursor);
u.aw.pCur->pKeyInfo = u.aw.pKeyInfo;
@@ -62578,7 +63725,7 @@ case OP_OpenEphemeral: {
#if 0 /* local variables moved into u.ax */
VdbeCursor *pCx;
#endif /* local variables moved into u.ax */
- static const int openFlags =
+ static const int vfsFlags =
SQLITE_OPEN_READWRITE |
SQLITE_OPEN_CREATE |
SQLITE_OPEN_EXCLUSIVE |
@@ -62589,21 +63736,21 @@ case OP_OpenEphemeral: {
u.ax.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
if( u.ax.pCx==0 ) goto no_mem;
u.ax.pCx->nullRow = 1;
- rc = sqlite3BtreeFactory(db, 0, 1, SQLITE_DEFAULT_TEMP_CACHE_SIZE, openFlags,
- &u.ax.pCx->pBt);
+ rc = sqlite3BtreeOpen(0, db, &u.ax.pCx->pBt,
+ BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
if( rc==SQLITE_OK ){
rc = sqlite3BtreeBeginTrans(u.ax.pCx->pBt, 1);
}
if( rc==SQLITE_OK ){
/* If a transient index is required, create it by calling
- ** sqlite3BtreeCreateTable() with the BTREE_ZERODATA flag before
+ ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before
** opening it. If a transient table is required, just use the
- ** automatically created table with root-page 1 (an INTKEY table).
+ ** automatically created table with root-page 1 (an BLOB_INTKEY table).
*/
if( pOp->p4.pKeyInfo ){
int pgno;
assert( pOp->p4type==P4_KEYINFO );
- rc = sqlite3BtreeCreateTable(u.ax.pCx->pBt, &pgno, BTREE_ZERODATA);
+ rc = sqlite3BtreeCreateTable(u.ax.pCx->pBt, &pgno, BTREE_BLOBKEY);
if( rc==SQLITE_OK ){
assert( pgno==MASTER_ROOT+1 );
rc = sqlite3BtreeCursor(u.ax.pCx->pBt, pgno, 1,
@@ -62617,6 +63764,7 @@ case OP_OpenEphemeral: {
u.ax.pCx->isTable = 1;
}
}
+ u.ax.pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
u.ax.pCx->isIndex = !u.ax.pCx->isTable;
break;
}
@@ -62736,6 +63884,7 @@ case OP_SeekGt: { /* jump, in3 */
assert( OP_SeekLe == OP_SeekLt+1 );
assert( OP_SeekGe == OP_SeekLt+2 );
assert( OP_SeekGt == OP_SeekLt+3 );
+ assert( u.az.pC->isOrdered );
if( u.az.pC->pCursor!=0 ){
u.az.oc = pOp->opcode;
u.az.pC->nullRow = 0;
@@ -62818,6 +63967,9 @@ case OP_SeekGt: { /* jump, in3 */
assert( u.az.oc!=OP_SeekLt || u.az.r.flags==0 );
u.az.r.aMem = &aMem[pOp->p3];
+#ifdef SQLITE_DEBUG
+ { int i; for(i=0; i<u.az.r.nField; i++) assert( memIsValid(&u.az.r.aMem[i]) ); }
+#endif
ExpandBlob(u.az.r.aMem);
rc = sqlite3BtreeMovetoUnpacked(u.az.pC->pCursor, &u.az.r, 0, 0, &u.az.res);
if( rc!=SQLITE_OK ){
@@ -62946,11 +64098,14 @@ case OP_Found: { /* jump, in3 */
u.bb.r.pKeyInfo = u.bb.pC->pKeyInfo;
u.bb.r.nField = (u16)pOp->p4.i;
u.bb.r.aMem = pIn3;
+#ifdef SQLITE_DEBUG
+ { int i; for(i=0; i<u.bb.r.nField; i++) assert( memIsValid(&u.bb.r.aMem[i]) ); }
+#endif
u.bb.r.flags = UNPACKED_PREFIX_MATCH;
u.bb.pIdxKey = &u.bb.r;
}else{
assert( pIn3->flags & MEM_Blob );
- ExpandBlob(pIn3);
+ assert( (pIn3->flags & MEM_Zero)==0 ); /* zeroblobs already expanded */
u.bb.pIdxKey = sqlite3VdbeRecordUnpack(u.bb.pC->pKeyInfo, pIn3->n, pIn3->z,
u.bb.aTempRec, sizeof(u.bb.aTempRec));
if( u.bb.pIdxKey==0 ){
@@ -63045,6 +64200,9 @@ case OP_IsUnique: { /* jump, in3 */
u.bc.r.nField = u.bc.nField + 1;
u.bc.r.flags = UNPACKED_PREFIX_SEARCH;
u.bc.r.aMem = u.bc.aMx;
+#ifdef SQLITE_DEBUG
+ { int i; for(i=0; i<u.bc.r.nField; i++) assert( memIsValid(&u.bc.r.aMem[i]) ); }
+#endif
/* Extract the value of u.bc.R from register P3. */
sqlite3VdbeMemIntegerify(pIn3);
@@ -63067,7 +64225,7 @@ case OP_IsUnique: { /* jump, in3 */
**
** Use the content of register P3 as a integer key. If a record
** with that key does not exist in table of P1, then jump to P2.
-** If the record does exist, then fall thru. The cursor is left
+** If the record does exist, then fall through. The cursor is left
** pointing to the record if it exists.
**
** The difference between this operation and NotFound is that this
@@ -63225,7 +64383,9 @@ case OP_NewRowid: { /* out2-prerelease */
/* Assert that P3 is a valid memory cell. */
assert( pOp->p3<=p->nMem );
u.be.pMem = &aMem[pOp->p3];
+ memAboutToChange(p, u.be.pMem);
}
+ assert( memIsValid(u.be.pMem) );
REGISTER_TRACE(pOp->p3, u.be.pMem);
sqlite3VdbeMemIntegerify(u.be.pMem);
@@ -63244,29 +64404,36 @@ case OP_NewRowid: { /* out2-prerelease */
sqlite3BtreeSetCachedRowid(u.be.pC->pCursor, u.be.v<MAX_ROWID ? u.be.v+1 : 0);
}
if( u.be.pC->useRandomRowid ){
- /* IMPLEMENTATION-OF: R-48598-02938 If the largest ROWID is equal to the
+ /* IMPLEMENTATION-OF: R-07677-41881 If the largest ROWID is equal to the
** largest possible integer (9223372036854775807) then the database
- ** engine starts picking candidate ROWIDs at random until it finds one
- ** that is not previously used.
- */
+ ** engine starts picking positive candidate ROWIDs at random until
+ ** it finds one that is not previously used. */
assert( pOp->p3==0 ); /* We cannot be in random rowid mode if this is
** an AUTOINCREMENT table. */
+ /* on the first attempt, simply do one more than previous */
u.be.v = db->lastRowid;
+ u.be.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */
+ u.be.v++; /* ensure non-zero */
u.be.cnt = 0;
- do{
- if( u.be.cnt==0 && (u.be.v&0xffffff)==u.be.v ){
- u.be.v++;
+ while( ((rc = sqlite3BtreeMovetoUnpacked(u.be.pC->pCursor, 0, (u64)u.be.v,
+ 0, &u.be.res))==SQLITE_OK)
+ && (u.be.res==0)
+ && (++u.be.cnt<100)){
+ /* collision - try another random rowid */
+ sqlite3_randomness(sizeof(u.be.v), &u.be.v);
+ if( u.be.cnt<5 ){
+ /* try "small" random rowids for the initial attempts */
+ u.be.v &= 0xffffff;
}else{
- sqlite3_randomness(sizeof(u.be.v), &u.be.v);
- if( u.be.cnt<5 ) u.be.v &= 0xffffff;
+ u.be.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */
}
- rc = sqlite3BtreeMovetoUnpacked(u.be.pC->pCursor, 0, (u64)u.be.v, 0, &u.be.res);
- u.be.cnt++;
- }while( u.be.cnt<100 && rc==SQLITE_OK && u.be.res==0 );
+ u.be.v++; /* ensure non-zero */
+ }
if( rc==SQLITE_OK && u.be.res==0 ){
rc = SQLITE_FULL; /* IMP: R-38219-53002 */
goto abort_due_to_error;
}
+ assert( u.be.v>0 ); /* EV: R-40812-03570 */
}
u.be.pC->rowidIsValid = 0;
u.be.pC->deferredMoveto = 0;
@@ -63336,6 +64503,7 @@ case OP_InsertInt: {
u.bf.pData = &aMem[pOp->p2];
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ assert( memIsValid(u.bf.pData) );
u.bf.pC = p->apCsr[pOp->p1];
assert( u.bf.pC!=0 );
assert( u.bf.pC->pCursor!=0 );
@@ -63346,6 +64514,7 @@ case OP_InsertInt: {
if( pOp->opcode==OP_Insert ){
u.bf.pKey = &aMem[pOp->p3];
assert( u.bf.pKey->flags & MEM_Int );
+ assert( memIsValid(u.bf.pKey) );
REGISTER_TRACE(pOp->p3, u.bf.pKey);
u.bf.iKey = u.bf.pKey->u.i;
}else{
@@ -63497,6 +64666,7 @@ case OP_RowData: {
#endif /* local variables moved into u.bh */
pOut = &aMem[pOp->p2];
+ memAboutToChange(p, pOut);
/* Note that RowKey and RowData are really exactly the same instruction */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
@@ -63839,6 +65009,9 @@ case OP_IdxDelete: {
u.bo.r.nField = (u16)pOp->p3;
u.bo.r.flags = 0;
u.bo.r.aMem = &aMem[pOp->p2];
+#ifdef SQLITE_DEBUG
+ { int i; for(i=0; i<u.bo.r.nField; i++) assert( memIsValid(&u.bo.r.aMem[i]) ); }
+#endif
rc = sqlite3BtreeMovetoUnpacked(u.bo.pCrsr, &u.bo.r, 0, 0, &u.bo.res);
if( rc==SQLITE_OK && u.bo.res==0 ){
rc = sqlite3BtreeDelete(u.bo.pCrsr);
@@ -63923,6 +65096,7 @@ case OP_IdxGE: { /* jump */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
u.bq.pC = p->apCsr[pOp->p1];
assert( u.bq.pC!=0 );
+ assert( u.bq.pC->isOrdered );
if( ALWAYS(u.bq.pC->pCursor!=0) ){
assert( u.bq.pC->deferredMoveto==0 );
assert( pOp->p5==0 || pOp->p5==1 );
@@ -63935,6 +65109,9 @@ case OP_IdxGE: { /* jump */
u.bq.r.flags = UNPACKED_IGNORE_ROWID;
}
u.bq.r.aMem = &aMem[pOp->p3];
+#ifdef SQLITE_DEBUG
+ { int i; for(i=0; i<u.bq.r.nField; i++) assert( memIsValid(&u.bq.r.aMem[i]) ); }
+#endif
rc = sqlite3VdbeIdxKeyCompare(u.bq.pC, &u.bq.r, &u.bq.res);
if( pOp->opcode==OP_IdxLT ){
u.bq.res = -u.bq.res;
@@ -64038,6 +65215,8 @@ case OP_Clear: {
if( pOp->p3 ){
p->nChange += u.bs.nChange;
if( pOp->p3>0 ){
+ assert( memIsValid(&aMem[pOp->p3]) );
+ memAboutToChange(p, &aMem[pOp->p3]);
aMem[pOp->p3].u.i += u.bs.nChange;
}
}
@@ -64081,9 +65260,9 @@ case OP_CreateTable: { /* out2-prerelease */
assert( u.bt.pDb->pBt!=0 );
if( pOp->opcode==OP_CreateTable ){
/* u.bt.flags = BTREE_INTKEY; */
- u.bt.flags = BTREE_LEAFDATA|BTREE_INTKEY;
+ u.bt.flags = BTREE_INTKEY;
}else{
- u.bt.flags = BTREE_ZERODATA;
+ u.bt.flags = BTREE_BLOBKEY;
}
rc = sqlite3BtreeCreateTable(u.bt.pDb->pBt, &u.bt.pgno, u.bt.flags);
pOut->u.i = u.bt.pgno;
@@ -64412,6 +65591,7 @@ case OP_Program: { /* jump */
u.by.pProgram = pOp->p4.pProgram;
u.by.pRt = &aMem[pOp->p3];
+ assert( memIsValid(u.by.pRt) );
assert( u.by.pProgram->nOp>0 );
/* If the p5 flag is clear, then recursive invocation of triggers is
@@ -64585,6 +65765,7 @@ case OP_MemMax: { /* in2 */
}else{
u.ca.pIn1 = &aMem[pOp->p1];
}
+ assert( memIsValid(u.ca.pIn1) );
sqlite3VdbeMemIntegerify(u.ca.pIn1);
pIn2 = &aMem[pOp->p2];
sqlite3VdbeMemIntegerify(pIn2);
@@ -64671,7 +65852,9 @@ case OP_AggStep: {
u.cb.apVal = p->apArg;
assert( u.cb.apVal || u.cb.n==0 );
for(u.cb.i=0; u.cb.i<u.cb.n; u.cb.i++, u.cb.pRec++){
+ assert( memIsValid(u.cb.pRec) );
u.cb.apVal[u.cb.i] = u.cb.pRec;
+ memAboutToChange(p, u.cb.pRec);
sqlite3VdbeMemStoreType(u.cb.pRec);
}
u.cb.ctx.pFunc = pOp->p4.pFunc;
@@ -64691,7 +65874,7 @@ case OP_AggStep: {
assert( pOp[-1].opcode==OP_CollSeq );
u.cb.ctx.pColl = pOp[-1].p4.pColl;
}
- (u.cb.ctx.pFunc->xStep)(&u.cb.ctx, u.cb.n, u.cb.apVal);
+ (u.cb.ctx.pFunc->xStep)(&u.cb.ctx, u.cb.n, u.cb.apVal); /* IMP: R-24505-23230 */
if( u.cb.ctx.isError ){
sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.cb.ctx.s));
rc = u.cb.ctx.isError;
@@ -65078,6 +66261,7 @@ case OP_VFilter: { /* jump */
u.ch.pQuery = &aMem[pOp->p3];
u.ch.pArgc = &u.ch.pQuery[1];
u.ch.pCur = p->apCsr[pOp->p1];
+ assert( memIsValid(u.ch.pQuery) );
REGISTER_TRACE(pOp->p3, u.ch.pQuery);
assert( u.ch.pCur->pVtabCursor );
u.ch.pVtabCursor = u.ch.pCur->pVtabCursor;
@@ -65135,6 +66319,7 @@ case OP_VColumn: {
assert( pCur->pVtabCursor );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
u.ci.pDest = &aMem[pOp->p3];
+ memAboutToChange(p, u.ci.pDest);
if( pCur->nullRow ){
sqlite3VdbeMemSetNull(u.ci.pDest);
break;
@@ -65237,10 +66422,12 @@ case OP_VRename: {
u.ck.pVtab = pOp->p4.pVtab->pVtab;
u.ck.pName = &aMem[pOp->p1];
assert( u.ck.pVtab->pModule->xRename );
+ assert( memIsValid(u.ck.pName) );
REGISTER_TRACE(pOp->p1, u.ck.pName);
assert( u.ck.pName->flags & MEM_Str );
rc = u.ck.pVtab->pModule->xRename(u.ck.pVtab, u.ck.pName->z);
importVtabErrMsg(p, u.ck.pVtab);
+ p->expired = 0;
break;
}
@@ -65289,6 +66476,8 @@ case OP_VUpdate: {
u.cl.apArg = p->apArg;
u.cl.pX = &aMem[pOp->p3];
for(u.cl.i=0; u.cl.i<u.cl.nArg; u.cl.i++){
+ assert( memIsValid(u.cl.pX) );
+ memAboutToChange(p, u.cl.pX);
sqlite3VdbeMemStoreType(u.cl.pX);
u.cl.apArg[u.cl.i] = u.cl.pX;
u.cl.pX++;
@@ -65316,6 +66505,32 @@ case OP_Pagecount: { /* out2-prerelease */
}
#endif
+
+#ifndef SQLITE_OMIT_PAGER_PRAGMAS
+/* Opcode: MaxPgcnt P1 P2 P3 * *
+**
+** Try to set the maximum page count for database P1 to the value in P3.
+** Do not let the maximum page count fall below the current page count and
+** do not change the maximum page count value if P3==0.
+**
+** Store the maximum page count after the change in register P2.
+*/
+case OP_MaxPgcnt: { /* out2-prerelease */
+ unsigned int newMax;
+ Btree *pBt;
+
+ pBt = db->aDb[pOp->p1].pBt;
+ newMax = 0;
+ if( pOp->p3 ){
+ newMax = sqlite3BtreeLastPage(pBt);
+ if( newMax < (unsigned)pOp->p3 ) newMax = (unsigned)pOp->p3;
+ }
+ pOut->u.i = sqlite3BtreeMaxPageCount(pBt, newMax);
+ break;
+}
+#endif
+
+
#ifndef SQLITE_OMIT_TRACE
/* Opcode: Trace * * * P4 *
**
@@ -65490,11 +66705,82 @@ struct Incrblob {
int flags; /* Copy of "flags" passed to sqlite3_blob_open() */
int nByte; /* Size of open blob, in bytes */
int iOffset; /* Byte offset of blob in cursor data */
+ int iCol; /* Table column this handle is open on */
BtCursor *pCsr; /* Cursor pointing at blob row */
sqlite3_stmt *pStmt; /* Statement holding cursor open */
sqlite3 *db; /* The associated database */
};
+
+/*
+** This function is used by both blob_open() and blob_reopen(). It seeks
+** the b-tree cursor associated with blob handle p to point to row iRow.
+** If successful, SQLITE_OK is returned and subsequent calls to
+** sqlite3_blob_read() or sqlite3_blob_write() access the specified row.
+**
+** If an error occurs, or if the specified row does not exist or does not
+** contain a value of type TEXT or BLOB in the column nominated when the
+** blob handle was opened, then an error code is returned and *pzErr may
+** be set to point to a buffer containing an error message. It is the
+** responsibility of the caller to free the error message buffer using
+** sqlite3DbFree().
+**
+** If an error does occur, then the b-tree cursor is closed. All subsequent
+** calls to sqlite3_blob_read(), blob_write() or blob_reopen() will
+** immediately return SQLITE_ABORT.
+*/
+static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
+ int rc; /* Error code */
+ char *zErr = 0; /* Error message */
+ Vdbe *v = (Vdbe *)p->pStmt;
+
+ /* Set the value of the SQL statements only variable to integer iRow.
+ ** This is done directly instead of using sqlite3_bind_int64() to avoid
+ ** triggering asserts related to mutexes.
+ */
+ assert( v->aVar[0].flags&MEM_Int );
+ v->aVar[0].u.i = iRow;
+
+ rc = sqlite3_step(p->pStmt);
+ if( rc==SQLITE_ROW ){
+ u32 type = v->apCsr[0]->aType[p->iCol];
+ if( type<12 ){
+ zErr = sqlite3MPrintf(p->db, "cannot open value of type %s",
+ type==0?"null": type==7?"real": "integer"
+ );
+ rc = SQLITE_ERROR;
+ sqlite3_finalize(p->pStmt);
+ p->pStmt = 0;
+ }else{
+ p->iOffset = v->apCsr[0]->aOffset[p->iCol];
+ p->nByte = sqlite3VdbeSerialTypeLen(type);
+ p->pCsr = v->apCsr[0]->pCursor;
+ sqlite3BtreeEnterCursor(p->pCsr);
+ sqlite3BtreeCacheOverflow(p->pCsr);
+ sqlite3BtreeLeaveCursor(p->pCsr);
+ }
+ }
+
+ if( rc==SQLITE_ROW ){
+ rc = SQLITE_OK;
+ }else if( p->pStmt ){
+ rc = sqlite3_finalize(p->pStmt);
+ p->pStmt = 0;
+ if( rc==SQLITE_OK ){
+ zErr = sqlite3MPrintf(p->db, "no such rowid: %lld", iRow);
+ rc = SQLITE_ERROR;
+ }else{
+ zErr = sqlite3MPrintf(p->db, "%s", sqlite3_errmsg(p->db));
+ }
+ }
+
+ assert( rc!=SQLITE_OK || zErr==0 );
+ assert( rc!=SQLITE_ROW && rc!=SQLITE_DONE );
+
+ *pzErr = zErr;
+ return rc;
+}
+
/*
** Open a blob handle.
*/
@@ -65535,29 +66821,35 @@ SQLITE_API int sqlite3_blob_open(
{OP_OpenWrite, 0, 0, 0}, /* 4: Open cursor 0 for read/write */
{OP_Variable, 1, 1, 1}, /* 5: Push the rowid to the stack */
- {OP_NotExists, 0, 9, 1}, /* 6: Seek the cursor */
+ {OP_NotExists, 0, 10, 1}, /* 6: Seek the cursor */
{OP_Column, 0, 0, 1}, /* 7 */
{OP_ResultRow, 1, 0, 0}, /* 8 */
- {OP_Close, 0, 0, 0}, /* 9 */
- {OP_Halt, 0, 0, 0}, /* 10 */
+ {OP_Goto, 0, 5, 0}, /* 9 */
+ {OP_Close, 0, 0, 0}, /* 10 */
+ {OP_Halt, 0, 0, 0}, /* 11 */
};
- Vdbe *v = 0;
int rc = SQLITE_OK;
char *zErr = 0;
Table *pTab;
- Parse *pParse;
+ Parse *pParse = 0;
+ Incrblob *pBlob = 0;
+ flags = !!flags; /* flags = (flags ? 1 : 0); */
*ppBlob = 0;
+
sqlite3_mutex_enter(db->mutex);
+
+ pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
+ if( !pBlob ) goto blob_open_out;
pParse = sqlite3StackAllocRaw(db, sizeof(*pParse));
- if( pParse==0 ){
- rc = SQLITE_NOMEM;
- goto blob_open_out;
- }
+ if( !pParse ) goto blob_open_out;
+
do {
memset(pParse, 0, sizeof(Parse));
pParse->db = db;
+ sqlite3DbFree(db, zErr);
+ zErr = 0;
sqlite3BtreeEnterAll(db);
pTab = sqlite3LocateTable(pParse, 0, zTable, zDb);
@@ -65583,7 +66875,7 @@ SQLITE_API int sqlite3_blob_open(
}
/* Now search pTab for the exact column. */
- for(iCol=0; iCol < pTab->nCol; iCol++) {
+ for(iCol=0; iCol<pTab->nCol; iCol++) {
if( sqlite3StrICmp(pTab->aCol[iCol].zName, zColumn)==0 ){
break;
}
@@ -65637,11 +66929,14 @@ SQLITE_API int sqlite3_blob_open(
}
}
- v = sqlite3VdbeCreate(db);
- if( v ){
+ pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(db);
+ assert( pBlob->pStmt || db->mallocFailed );
+ if( pBlob->pStmt ){
+ Vdbe *v = (Vdbe *)pBlob->pStmt;
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+
sqlite3VdbeAddOpList(v, sizeof(openBlob)/sizeof(VdbeOpList), openBlob);
- flags = !!flags; /* flags = (flags ? 1 : 0); */
+
/* Configure the OP_Transaction */
sqlite3VdbeChangeP1(v, 0, iDb);
@@ -65684,65 +66979,25 @@ SQLITE_API int sqlite3_blob_open(
}
}
+ pBlob->flags = flags;
+ pBlob->iCol = iCol;
+ pBlob->db = db;
sqlite3BtreeLeaveAll(db);
if( db->mallocFailed ){
goto blob_open_out;
}
-
- sqlite3_bind_int64((sqlite3_stmt *)v, 1, iRow);
- rc = sqlite3_step((sqlite3_stmt *)v);
- if( rc!=SQLITE_ROW ){
- nAttempt++;
- rc = sqlite3_finalize((sqlite3_stmt *)v);
- sqlite3DbFree(db, zErr);
- zErr = sqlite3MPrintf(db, sqlite3_errmsg(db));
- v = 0;
- }
- } while( nAttempt<5 && rc==SQLITE_SCHEMA );
-
- if( rc==SQLITE_ROW ){
- /* The row-record has been opened successfully. Check that the
- ** column in question contains text or a blob. If it contains
- ** text, it is up to the caller to get the encoding right.
- */
- Incrblob *pBlob;
- u32 type = v->apCsr[0]->aType[iCol];
-
- if( type<12 ){
- sqlite3DbFree(db, zErr);
- zErr = sqlite3MPrintf(db, "cannot open value of type %s",
- type==0?"null": type==7?"real": "integer"
- );
- rc = SQLITE_ERROR;
- goto blob_open_out;
- }
- pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
- if( db->mallocFailed ){
- sqlite3DbFree(db, pBlob);
- goto blob_open_out;
- }
- pBlob->flags = flags;
- pBlob->pCsr = v->apCsr[0]->pCursor;
- sqlite3BtreeEnterCursor(pBlob->pCsr);
- sqlite3BtreeCacheOverflow(pBlob->pCsr);
- sqlite3BtreeLeaveCursor(pBlob->pCsr);
- pBlob->pStmt = (sqlite3_stmt *)v;
- pBlob->iOffset = v->apCsr[0]->aOffset[iCol];
- pBlob->nByte = sqlite3VdbeSerialTypeLen(type);
- pBlob->db = db;
- *ppBlob = (sqlite3_blob *)pBlob;
- rc = SQLITE_OK;
- }else if( rc==SQLITE_OK ){
- sqlite3DbFree(db, zErr);
- zErr = sqlite3MPrintf(db, "no such rowid: %lld", iRow);
- rc = SQLITE_ERROR;
- }
+ sqlite3_bind_int64(pBlob->pStmt, 1, iRow);
+ rc = blobSeekToRow(pBlob, iRow, &zErr);
+ } while( (++nAttempt)<5 && rc==SQLITE_SCHEMA );
blob_open_out:
- if( v && (rc!=SQLITE_OK || db->mallocFailed) ){
- sqlite3VdbeFinalize(v);
+ if( rc==SQLITE_OK && db->mallocFailed==0 ){
+ *ppBlob = (sqlite3_blob *)pBlob;
+ }else{
+ if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt);
+ sqlite3DbFree(db, pBlob);
}
- sqlite3Error(db, rc, zErr);
+ sqlite3Error(db, rc, (zErr ? "%s" : 0), zErr);
sqlite3DbFree(db, zErr);
sqlite3StackFree(db, pParse);
rc = sqlite3ApiExit(db, rc);
@@ -65795,7 +67050,7 @@ static int blobReadWrite(
/* Request is out of range. Return a transient error. */
rc = SQLITE_ERROR;
sqlite3Error(db, SQLITE_ERROR, 0);
- } else if( v==0 ){
+ }else if( v==0 ){
/* If there is no statement handle, then the blob-handle has
** already been invalidated. Return SQLITE_ABORT in this case.
*/
@@ -65843,7 +67098,47 @@ SQLITE_API int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int
*/
SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *pBlob){
Incrblob *p = (Incrblob *)pBlob;
- return p ? p->nByte : 0;
+ return (p && p->pStmt) ? p->nByte : 0;
+}
+
+/*
+** Move an existing blob handle to point to a different row of the same
+** database table.
+**
+** If an error occurs, or if the specified row does not exist or does not
+** contain a blob or text value, then an error code is returned and the
+** database handle error code and message set. If this happens, then all
+** subsequent calls to sqlite3_blob_xxx() functions (except blob_close())
+** immediately return SQLITE_ABORT.
+*/
+SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
+ int rc;
+ Incrblob *p = (Incrblob *)pBlob;
+ sqlite3 *db;
+
+ if( p==0 ) return SQLITE_MISUSE_BKPT;
+ db = p->db;
+ sqlite3_mutex_enter(db->mutex);
+
+ if( p->pStmt==0 ){
+ /* If there is no statement handle, then the blob-handle has
+ ** already been invalidated. Return SQLITE_ABORT in this case.
+ */
+ rc = SQLITE_ABORT;
+ }else{
+ char *zErr;
+ rc = blobSeekToRow(p, iRow, &zErr);
+ if( rc!=SQLITE_OK ){
+ sqlite3Error(db, rc, (zErr ? "%s" : 0), zErr);
+ sqlite3DbFree(db, zErr);
+ }
+ assert( rc!=SQLITE_SCHEMA );
+ }
+
+ rc = sqlite3ApiExit(db, rc);
+ assert( rc==SQLITE_OK || p->pStmt==0 );
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
}
#endif /* #ifndef SQLITE_OMIT_INCRBLOB */
@@ -66343,8 +67638,7 @@ SQLITE_PRIVATE int sqlite3IsMemJournal(sqlite3_file *pJfd){
}
/*
-** Return the number of bytes required to store a MemJournal that uses vfs
-** pVfs to create the underlying on-disk files.
+** Return the number of bytes required to store a MemJournal file descriptor.
*/
SQLITE_PRIVATE int sqlite3MemJournalSize(void){
return sizeof(MemJournal);
@@ -68177,6 +69471,9 @@ SQLITE_PRIVATE Expr *sqlite3PExpr(
){
Expr *p = sqlite3ExprAlloc(pParse->db, op, pToken, 1);
sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight);
+ if( p ) {
+ sqlite3ExprCheckHeight(pParse, p->nHeight);
+ }
return p;
}
@@ -68248,7 +69545,7 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
/* Wildcard of the form "?nnn". Convert "nnn" to an integer and
** use it as the variable number */
i64 i;
- int bOk = sqlite3Atoi64(&z[1], &i);
+ int bOk = 0==sqlite3Atoi64(&z[1], &i, sqlite3Strlen30(&z[1]), SQLITE_UTF8);
pExpr->iColumn = (ynVar)i;
testcase( i==0 );
testcase( i==1 );
@@ -69228,8 +70525,8 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
#endif
/*
-** Generate code for scalar subqueries used as an expression
-** and IN operators. Examples:
+** Generate code for scalar subqueries used as a subquery expression, EXISTS,
+** or IN operators. Examples:
**
** (SELECT a FROM b) -- subquery
** EXISTS (SELECT a FROM b) -- EXISTS subquery
@@ -69290,12 +70587,22 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
assert( testAddr>0 || pParse->db->mallocFailed );
}
+#ifndef SQLITE_OMIT_EXPLAIN
+ if( pParse->explain==2 ){
+ char *zMsg = sqlite3MPrintf(
+ pParse->db, "EXECUTE %s%s SUBQUERY %d", testAddr?"":"CORRELATED ",
+ pExpr->op==TK_IN?"LIST":"SCALAR", pParse->iNextSelectId
+ );
+ sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC);
+ }
+#endif
+
switch( pExpr->op ){
case TK_IN: {
- char affinity;
- KeyInfo keyInfo;
- int addr; /* Address of OP_OpenEphemeral instruction */
- Expr *pLeft = pExpr->pLeft;
+ char affinity; /* Affinity of the LHS of the IN */
+ KeyInfo keyInfo; /* Keyinfo for the generated table */
+ int addr; /* Address of OP_OpenEphemeral instruction */
+ Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */
if( rMayHaveNull ){
sqlite3VdbeAddOp2(v, OP_Null, 0, rMayHaveNull);
@@ -69318,6 +70625,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
*/
pExpr->iTable = pParse->nTab++;
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, !isRowid);
+ if( rMayHaveNull==0 ) sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
memset(&keyInfo, 0, sizeof(keyInfo));
keyInfo.nField = 1;
@@ -69334,6 +70642,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
dest.affinity = (u8)affinity;
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
+ pExpr->x.pSelect->iLimit = 0;
if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){
return 0;
}
@@ -69434,6 +70743,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
sqlite3ExprDelete(pParse->db, pSel->pLimit);
pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0,
&sqlite3IntTokens[1]);
+ pSel->iLimit = 0;
if( sqlite3Select(pParse, pSel, &dest) ){
return 0;
}
@@ -69610,7 +70920,7 @@ static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){
if( ALWAYS(z!=0) ){
double value;
char *zV;
- sqlite3AtoF(z, &value);
+ sqlite3AtoF(z, &value, sqlite3Strlen30(z), SQLITE_UTF8);
assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */
if( negateFlag ) value = -value;
zV = dup8bytes(v, (char*)&value);
@@ -69624,9 +70934,7 @@ static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){
** Generate an instruction that will put the integer describe by
** text z[0..n-1] into register iMem.
**
-** The z[] string will probably not be zero-terminated. But the
-** z[n] character is guaranteed to be something that does not look
-** like the continuation of the number.
+** Expr.u.zToken is always UTF8 and zero-terminated.
*/
static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
Vdbe *v = pParse->pVdbe;
@@ -69635,13 +70943,14 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
if( negFlag ) i = -i;
sqlite3VdbeAddOp2(v, OP_Integer, i, iMem);
}else{
+ int c;
+ i64 value;
const char *z = pExpr->u.zToken;
assert( z!=0 );
- if( sqlite3FitsIn64Bits(z, negFlag) ){
- i64 value;
+ c = sqlite3Atoi64(z, &value, sqlite3Strlen30(z), SQLITE_UTF8);
+ if( c==0 || (c==2 && negFlag) ){
char *zV;
- sqlite3Atoi64(z, &value);
- if( negFlag ) value = -value;
+ if( negFlag ){ value = -value; }
zV = dup8bytes(v, (char*)&value);
sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64);
}else{
@@ -69927,73 +71236,6 @@ static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){
#endif /* SQLITE_DEBUG || SQLITE_COVERAGE_TEST */
/*
-** If the last instruction coded is an ephemeral copy of any of
-** the registers in the nReg registers beginning with iReg, then
-** convert the last instruction from OP_SCopy to OP_Copy.
-*/
-SQLITE_PRIVATE void sqlite3ExprHardCopy(Parse *pParse, int iReg, int nReg){
- VdbeOp *pOp;
- Vdbe *v;
-
- assert( pParse->db->mallocFailed==0 );
- v = pParse->pVdbe;
- assert( v!=0 );
- pOp = sqlite3VdbeGetOp(v, -1);
- assert( pOp!=0 );
- if( pOp->opcode==OP_SCopy && pOp->p1>=iReg && pOp->p1<iReg+nReg ){
- pOp->opcode = OP_Copy;
- }
-}
-
-/*
-** Generate code to store the value of the iAlias-th alias in register
-** target. The first time this is called, pExpr is evaluated to compute
-** the value of the alias. The value is stored in an auxiliary register
-** and the number of that register is returned. On subsequent calls,
-** the register number is returned without generating any code.
-**
-** Note that in order for this to work, code must be generated in the
-** same order that it is executed.
-**
-** Aliases are numbered starting with 1. So iAlias is in the range
-** of 1 to pParse->nAlias inclusive.
-**
-** pParse->aAlias[iAlias-1] records the register number where the value
-** of the iAlias-th alias is stored. If zero, that means that the
-** alias has not yet been computed.
-*/
-static int codeAlias(Parse *pParse, int iAlias, Expr *pExpr, int target){
-#if 0
- sqlite3 *db = pParse->db;
- int iReg;
- if( pParse->nAliasAlloc<pParse->nAlias ){
- pParse->aAlias = sqlite3DbReallocOrFree(db, pParse->aAlias,
- sizeof(pParse->aAlias[0])*pParse->nAlias );
- testcase( db->mallocFailed && pParse->nAliasAlloc>0 );
- if( db->mallocFailed ) return 0;
- memset(&pParse->aAlias[pParse->nAliasAlloc], 0,
- (pParse->nAlias-pParse->nAliasAlloc)*sizeof(pParse->aAlias[0]));
- pParse->nAliasAlloc = pParse->nAlias;
- }
- assert( iAlias>0 && iAlias<=pParse->nAlias );
- iReg = pParse->aAlias[iAlias-1];
- if( iReg==0 ){
- if( pParse->iCacheLevel>0 ){
- iReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
- }else{
- iReg = ++pParse->nMem;
- sqlite3ExprCode(pParse, pExpr, iReg);
- pParse->aAlias[iAlias-1] = iReg;
- }
- }
- return iReg;
-#else
- UNUSED_PARAMETER(iAlias);
- return sqlite3ExprCodeTarget(pParse, pExpr, target);
-#endif
-}
-
-/*
** Generate code into the current Vdbe to evaluate the given
** expression. Attempt to store the results in register "target".
** Return the register where results are stored.
@@ -70101,7 +71343,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
break;
}
case TK_AS: {
- inReg = codeAlias(pParse, pExpr->iTable, pExpr->pLeft, target);
+ inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
break;
}
#ifndef SQLITE_OMIT_CAST
@@ -70533,6 +71775,11 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
opCompare.op = TK_EQ;
opCompare.pLeft = &cacheX;
pTest = &opCompare;
+ /* Ticket b351d95f9cd5ef17e9d9dbae18f5ca8611190001:
+ ** The value in regFree1 might get SCopy-ed into the file result.
+ ** So make sure that the regFree1 register is not reused for other
+ ** purposes and possibly overwritten. */
+ regFree1 = 0;
}
for(i=0; i<nExpr; i=i+2){
sqlite3ExprCachePush(pParse);
@@ -70626,10 +71873,14 @@ SQLITE_PRIVATE int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
int inReg;
assert( target>0 && target<=pParse->nMem );
- inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
- assert( pParse->pVdbe || pParse->db->mallocFailed );
- if( inReg!=target && pParse->pVdbe ){
- sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
+ if( pExpr && pExpr->op==TK_REGISTER ){
+ sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, pExpr->iTable, target);
+ }else{
+ inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
+ assert( pParse->pVdbe || pParse->db->mallocFailed );
+ if( inReg!=target && pParse->pVdbe ){
+ sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
+ }
}
return target;
}
@@ -70776,9 +72027,22 @@ static int evalConstExpr(Walker *pWalker, Expr *pExpr){
** Preevaluate constant subexpressions within pExpr and store the
** results in registers. Modify pExpr so that the constant subexpresions
** are TK_REGISTER opcodes that refer to the precomputed values.
+**
+** This routine is a no-op if the jump to the cookie-check code has
+** already occur. Since the cookie-check jump is generated prior to
+** any other serious processing, this check ensures that there is no
+** way to accidently bypass the constant initializations.
+**
+** This routine is also a no-op if the SQLITE_FactorOutConst optimization
+** is disabled via the sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS)
+** interface. This allows test logic to verify that the same answer is
+** obtained for queries regardless of whether or not constants are
+** precomputed into registers or if they are inserted in-line.
*/
SQLITE_PRIVATE void sqlite3ExprCodeConstants(Parse *pParse, Expr *pExpr){
Walker w;
+ if( pParse->cookieGoto ) return;
+ if( (pParse->db->flags & SQLITE_FactorOutConst)!=0 ) return;
w.xExprCallback = evalConstExpr;
w.xSelectCallback = 0;
w.pParse = pParse;
@@ -70802,19 +72066,14 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
int i, n;
assert( pList!=0 );
assert( target>0 );
+ assert( pParse->pVdbe!=0 ); /* Never gets this far otherwise */
n = pList->nExpr;
for(pItem=pList->a, i=0; i<n; i++, pItem++){
- if( pItem->iAlias ){
- int iReg = codeAlias(pParse, pItem->iAlias, pItem->pExpr, target+i);
- Vdbe *v = sqlite3GetVdbe(pParse);
- if( iReg!=target+i ){
- sqlite3VdbeAddOp2(v, OP_SCopy, iReg, target+i);
- }
- }else{
- sqlite3ExprCode(pParse, pItem->pExpr, target+i);
- }
- if( doHardCopy && !pParse->db->mallocFailed ){
- sqlite3ExprHardCopy(pParse, target, n);
+ Expr *pExpr = pItem->pExpr;
+ int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
+ if( inReg!=target+i ){
+ sqlite3VdbeAddOp2(pParse->pVdbe, doHardCopy ? OP_Copy : OP_SCopy,
+ inReg, target+i);
}
}
return n;
@@ -71796,6 +73055,11 @@ static char *whereTempTriggers(Parse *pParse, Table *pTab){
}
}
}
+ if( zWhere ){
+ char *zNew = sqlite3MPrintf(pParse->db, "type='trigger' AND (%s)", zWhere);
+ sqlite3DbFree(pParse->db, zWhere);
+ zWhere = zNew;
+ }
return zWhere;
}
@@ -72403,7 +73667,8 @@ static void analyzeOneTable(
int i; /* Loop counter */
int topOfLoop; /* The top of the loop */
int endOfLoop; /* The end of the loop */
- int addr; /* The address of an instruction */
+ int addr = 0; /* The address of an instruction */
+ int jZeroRows = 0; /* Jump from here if number of rows is zero */
int iDb; /* Index of database containing pTab */
int regTabname = iMem++; /* Register containing table name */
int regIdxname = iMem++; /* Register containing index name */
@@ -72422,8 +73687,15 @@ static void analyzeOneTable(
#endif
v = sqlite3GetVdbe(pParse);
- if( v==0 || NEVER(pTab==0) || pTab->pIndex==0 ){
- /* Do no analysis for tables that have no indices */
+ if( v==0 || NEVER(pTab==0) ){
+ return;
+ }
+ if( pTab->tnum==0 ){
+ /* Do not gather statistics on views or virtual tables */
+ return;
+ }
+ if( memcmp(pTab->zName, "sqlite_", 7)==0 ){
+ /* Do not gather statistics on system tables */
return;
}
assert( sqlite3BtreeHoldsAllMutexes(db) );
@@ -72440,6 +73712,7 @@ static void analyzeOneTable(
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
iIdxCur = pParse->nTab++;
+ sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int nCol = pIdx->nColumn;
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
@@ -72454,10 +73727,7 @@ static void analyzeOneTable(
(char *)pKey, P4_KEYINFO_HANDOFF);
VdbeComment((v, "%s", pIdx->zName));
- /* Populate the registers containing the table and index names. */
- if( pTab->pIndex==pIdx ){
- sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0);
- }
+ /* Populate the register containing the index name. */
sqlite3VdbeAddOp4(v, OP_String8, 0, regIdxname, 0, pIdx->zName, 0);
#ifdef SQLITE_ENABLE_STAT2
@@ -72517,9 +73787,10 @@ static void analyzeOneTable(
sqlite3VdbeAddOp2(v, OP_AddImm, iMem, 1);
for(i=0; i<nCol; i++){
+ CollSeq *pColl;
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regCol);
-#ifdef SQLITE_ENABLE_STAT2
if( i==0 ){
+#ifdef SQLITE_ENABLE_STAT2
/* Check if the record that cursor iIdxCur points to contains a
** value that should be stored in the sqlite_stat2 table. If so,
** store it. */
@@ -72548,12 +73819,17 @@ static void analyzeOneTable(
sqlite3VdbeJumpHere(v, ne);
sqlite3VdbeAddOp2(v, OP_AddImm, regRecno, 1);
- }
#endif
- sqlite3VdbeAddOp3(v, OP_Ne, regCol, 0, iMem+nCol+i+1);
- /**** TODO: add collating sequence *****/
- sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
+ /* Always record the very first row */
+ sqlite3VdbeAddOp1(v, OP_IfNot, iMem+1);
+ }
+ assert( pIdx->azColl!=0 );
+ assert( pIdx->azColl[i]!=0 );
+ pColl = sqlite3LocateCollSeq(pParse, pIdx->azColl[i]);
+ sqlite3VdbeAddOp4(v, OP_Ne, regCol, 0, iMem+nCol+i+1,
+ (char*)pColl, P4_COLLSEQ);
+ sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
}
if( db->mallocFailed ){
/* If a malloc failure has occurred, then the result of the expression
@@ -72564,7 +73840,11 @@ static void analyzeOneTable(
}
sqlite3VdbeAddOp2(v, OP_Goto, 0, endOfLoop);
for(i=0; i<nCol; i++){
- sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-(nCol*2));
+ int addr2 = sqlite3VdbeCurrentAddr(v) - (nCol*2);
+ if( i==0 ){
+ sqlite3VdbeJumpHere(v, addr2-1); /* Set jump dest for the OP_IfNot */
+ }
+ sqlite3VdbeJumpHere(v, addr2); /* Set jump dest for the OP_Ne */
sqlite3VdbeAddOp2(v, OP_AddImm, iMem+i+1, 1);
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, iMem+nCol+i+1);
}
@@ -72592,8 +73872,10 @@ static void analyzeOneTable(
** If K>0 then it is always the case the D>0 so division by zero
** is never possible.
*/
- addr = sqlite3VdbeAddOp1(v, OP_IfNot, iMem);
sqlite3VdbeAddOp2(v, OP_SCopy, iMem, regSampleno);
+ if( jZeroRows==0 ){
+ jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, iMem);
+ }
for(i=0; i<nCol; i++){
sqlite3VdbeAddOp4(v, OP_String8, 0, regTemp, 0, " ", 0);
sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regSampleno, regSampleno);
@@ -72607,13 +73889,35 @@ static void analyzeOneTable(
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid);
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid);
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
+ }
+
+ /* If the table has no indices, create a single sqlite_stat1 entry
+ ** containing NULL as the index name and the row count as the content.
+ */
+ if( pTab->pIndex==0 ){
+ sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pTab->tnum, iDb);
+ VdbeComment((v, "%s", pTab->zName));
+ sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regSampleno);
+ sqlite3VdbeAddOp1(v, OP_Close, iIdxCur);
+ }else{
+ assert( jZeroRows>0 );
+ addr = sqlite3VdbeAddOp0(v, OP_Goto);
+ sqlite3VdbeJumpHere(v, jZeroRows);
+ }
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname);
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0);
+ sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid);
+ sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid);
+ sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
+ if( pParse->nMem<regRec ) pParse->nMem = regRec;
+ if( jZeroRows ){
sqlite3VdbeJumpHere(v, addr);
}
}
/*
** Generate code that will cause the most recent index analysis to
-** be laoded into internal hash tables where is can be used.
+** be loaded into internal hash tables where is can be used.
*/
static void loadAnalysis(Parse *pParse, int iDb){
Vdbe *v = sqlite3GetVdbe(pParse);
@@ -72743,33 +74047,46 @@ struct analysisInfo {
** This callback is invoked once for each index when reading the
** sqlite_stat1 table.
**
-** argv[0] = name of the index
-** argv[1] = results of analysis - on integer for each column
+** argv[0] = name of the table
+** argv[1] = name of the index (might be NULL)
+** argv[2] = results of analysis - on integer for each column
+**
+** Entries for which argv[1]==NULL simply record the number of rows in
+** the table.
*/
static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
analysisInfo *pInfo = (analysisInfo*)pData;
Index *pIndex;
- int i, c;
+ Table *pTable;
+ int i, c, n;
unsigned int v;
const char *z;
- assert( argc==2 );
+ assert( argc==3 );
UNUSED_PARAMETER2(NotUsed, argc);
- if( argv==0 || argv[0]==0 || argv[1]==0 ){
+ if( argv==0 || argv[0]==0 || argv[2]==0 ){
return 0;
}
- pIndex = sqlite3FindIndex(pInfo->db, argv[0], pInfo->zDatabase);
- if( pIndex==0 ){
+ pTable = sqlite3FindTable(pInfo->db, argv[0], pInfo->zDatabase);
+ if( pTable==0 ){
return 0;
}
- z = argv[1];
- for(i=0; *z && i<=pIndex->nColumn; i++){
+ if( argv[1] ){
+ pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase);
+ }else{
+ pIndex = 0;
+ }
+ n = pIndex ? pIndex->nColumn : 0;
+ z = argv[2];
+ for(i=0; *z && i<=n; i++){
v = 0;
while( (c=z[0])>='0' && c<='9' ){
v = v*10 + c - '0';
z++;
}
+ if( i==0 ) pTable->nRowEst = v;
+ if( pIndex==0 ) break;
pIndex->aiRowEst[i] = v;
if( *z==' ' ) z++;
}
@@ -72845,7 +74162,7 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
/* Load new statistics out of the sqlite_stat1 table */
zSql = sqlite3MPrintf(db,
- "SELECT idx, stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
+ "SELECT tbl, idx, stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
if( zSql==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -72873,8 +74190,11 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
if( rc==SQLITE_OK ){
while( sqlite3_step(pStmt)==SQLITE_ROW ){
- char *zIndex = (char *)sqlite3_column_text(pStmt, 0);
- Index *pIdx = sqlite3FindIndex(db, zIndex, sInfo.zDatabase);
+ char *zIndex; /* Index name */
+ Index *pIdx; /* Pointer to the index object */
+
+ zIndex = (char *)sqlite3_column_text(pStmt, 0);
+ pIdx = zIndex ? sqlite3FindIndex(db, zIndex, sInfo.zDatabase) : 0;
if( pIdx ){
int iSample = sqlite3_column_int(pStmt, 1);
if( iSample<SQLITE_INDEX_SAMPLES && iSample>=0 ){
@@ -73062,9 +74382,8 @@ static void attachFunc(
** it to obtain the database schema. At this point the schema may
** or may not be initialised.
*/
- rc = sqlite3BtreeFactory(db, zFile, 0, SQLITE_DEFAULT_CACHE_SIZE,
- db->openFlags | SQLITE_OPEN_MAIN_DB,
- &aNew->pBt);
+ rc = sqlite3BtreeOpen(zFile, db, &aNew->pBt, 0,
+ db->openFlags | SQLITE_OPEN_MAIN_DB);
db->nDb++;
if( rc==SQLITE_CONSTRAINT ){
rc = SQLITE_ERROR;
@@ -73305,7 +74624,8 @@ SQLITE_PRIVATE void sqlite3Detach(Parse *pParse, Expr *pDbname){
0, /* xStep */
0, /* xFinalize */
"sqlite_detach", /* zName */
- 0 /* pHash */
+ 0, /* pHash */
+ 0 /* pDestructor */
};
codeAttach(pParse, SQLITE_DETACH, &detach_func, pDbname, 0, 0, pDbname);
}
@@ -73326,7 +74646,8 @@ SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *p
0, /* xStep */
0, /* xFinalize */
"sqlite_attach", /* zName */
- 0 /* pHash */
+ 0, /* pHash */
+ 0 /* pDestructor */
};
codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey);
}
@@ -74455,8 +75776,9 @@ SQLITE_PRIVATE void sqlite3StartTable(
*/
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
if( iDb<0 ) return;
- if( !OMIT_TEMPDB && isTemp && iDb>1 ){
- /* If creating a temp table, the name may not be qualified */
+ if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){
+ /* If creating a temp table, the name may not be qualified. Unless
+ ** the database name is "temp" anyway. */
sqlite3ErrorMsg(pParse, "temporary table name must be unqualified");
return;
}
@@ -74504,17 +75826,18 @@ SQLITE_PRIVATE void sqlite3StartTable(
** collisions.
*/
if( !IN_DECLARE_VTAB ){
+ char *zDb = db->aDb[iDb].zName;
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
goto begin_table_error;
}
- pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName);
+ pTable = sqlite3FindTable(db, zName, zDb);
if( pTable ){
if( !noErr ){
sqlite3ErrorMsg(pParse, "table %T already exists", pName);
}
goto begin_table_error;
}
- if( sqlite3FindIndex(db, zName, 0)!=0 && (iDb==0 || !db->init.busy) ){
+ if( sqlite3FindIndex(db, zName, zDb)!=0 ){
sqlite3ErrorMsg(pParse, "there is already an index named %s", zName);
goto begin_table_error;
}
@@ -74531,6 +75854,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
pTable->iPKey = -1;
pTable->pSchema = db->aDb[iDb].pSchema;
pTable->nRef = 1;
+ pTable->nRowEst = 1000000;
assert( pParse->pNewTable==0 );
pParse->pNewTable = pTable;
@@ -75377,12 +76701,10 @@ SQLITE_PRIVATE void sqlite3CreateView(
}
sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr);
p = pParse->pNewTable;
- if( p==0 ){
+ if( p==0 || pParse->nErr ){
sqlite3SelectDelete(db, pSelect);
return;
}
- assert( pParse->nErr==0 ); /* If sqlite3StartTable return non-NULL then
- ** there could not have been an error */
sqlite3TwoPartName(pParse, pName1, pName2, &pName);
iDb = sqlite3SchemaToIndex(db, p->pSchema);
if( sqlite3FixInit(&sFix, pParse, iDb, "view", pName)
@@ -76500,7 +77822,8 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
sqlite3RefillIndex(pParse, pIndex, iMem);
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0,
- sqlite3MPrintf(db, "name='%q'", pIndex->zName), P4_DYNAMIC);
+ sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName),
+ P4_DYNAMIC);
sqlite3VdbeAddOp1(v, OP_Expire, 0);
}
}
@@ -76561,14 +77884,14 @@ exit_create_index:
SQLITE_PRIVATE void sqlite3DefaultRowEst(Index *pIdx){
unsigned *a = pIdx->aiRowEst;
int i;
+ unsigned n;
assert( a!=0 );
- a[0] = 1000000;
- for(i=pIdx->nColumn; i>=5; i--){
- a[i] = 5;
- }
- while( i>=1 ){
- a[i] = 11 - i;
- i--;
+ a[0] = pIdx->pTable->nRowEst;
+ if( a[0]<10 ) a[0] = 10;
+ n = 10;
+ for(i=1; i<=pIdx->nColumn; i++){
+ a[i] = n;
+ if( n>5 ) n--;
}
if( pIdx->onError!=OE_None ){
a[pIdx->nColumn] = 1;
@@ -76628,7 +77951,7 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists
if( v ){
sqlite3BeginWriteOperation(pParse, 1, iDb);
sqlite3NestedParse(pParse,
- "DELETE FROM %Q.%s WHERE name=%Q",
+ "DELETE FROM %Q.%s WHERE name=%Q AND type='index'",
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
pIndex->zName
);
@@ -77120,7 +78443,7 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){
SQLITE_OPEN_DELETEONCLOSE |
SQLITE_OPEN_TEMP_DB;
- rc = sqlite3BtreeFactory(db, 0, 0, SQLITE_DEFAULT_CACHE_SIZE, flags, &pBt);
+ rc = sqlite3BtreeOpen(0, db, &pBt, 0, flags);
if( rc!=SQLITE_OK ){
sqlite3ErrorMsg(pParse, "unable to open a temporary database "
"file for storing temporary tables");
@@ -77777,7 +79100,7 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
** priority to built-in functions.
**
** Except, if createFlag is true, that means that we are trying to
- ** install a new function. Whatever FuncDef structure is returned will
+ ** install a new function. Whatever FuncDef structure is returned it will
** have fields overwritten with new information appropriate for the
** new function. But the FuncDefs for built-in functions are read-only.
** So we must not search for built-ins when creating a new function.
@@ -78793,7 +80116,7 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
sqlite3_result_error_nomem(context);
return;
}
- sqlite3AtoF(zBuf, &r);
+ sqlite3AtoF(zBuf, &r, sqlite3Strlen30(zBuf), SQLITE_UTF8);
sqlite3_free(zBuf);
}
sqlite3_result_double(context, r);
@@ -79958,10 +81281,10 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive)
}else{
pInfo = (struct compareInfo*)&likeInfoNorm;
}
- sqlite3CreateFunc(db, "like", 2, SQLITE_ANY, pInfo, likeFunc, 0, 0);
- sqlite3CreateFunc(db, "like", 3, SQLITE_ANY, pInfo, likeFunc, 0, 0);
- sqlite3CreateFunc(db, "glob", 2, SQLITE_ANY,
- (struct compareInfo*)&globInfo, likeFunc, 0,0);
+ sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0);
+ sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0);
+ sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8,
+ (struct compareInfo*)&globInfo, likeFunc, 0, 0, 0);
setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE);
setLikeOptFlag(db, "like",
caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : SQLITE_FUNC_LIKE);
@@ -80045,10 +81368,10 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
FUNCTION(coalesce, 1, 0, 0, 0 ),
FUNCTION(coalesce, 0, 0, 0, 0 ),
/* FUNCTION(coalesce, -1, 0, 0, ifnullFunc ), */
- {-1,SQLITE_UTF8,SQLITE_FUNC_COALESCE,0,0,ifnullFunc,0,0,"coalesce",0},
+ {-1,SQLITE_UTF8,SQLITE_FUNC_COALESCE,0,0,ifnullFunc,0,0,"coalesce",0,0},
FUNCTION(hex, 1, 0, 0, hexFunc ),
/* FUNCTION(ifnull, 2, 0, 0, ifnullFunc ), */
- {2,SQLITE_UTF8,SQLITE_FUNC_COALESCE,0,0,ifnullFunc,0,0,"ifnull",0},
+ {2,SQLITE_UTF8,SQLITE_FUNC_COALESCE,0,0,ifnullFunc,0,0,"ifnull",0,0},
FUNCTION(random, 0, 0, 0, randomFunc ),
FUNCTION(randomblob, 1, 0, 0, randomBlob ),
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
@@ -80075,7 +81398,7 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),
AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ),
/* AGGREGATE(count, 0, 0, 0, countStep, countFinalize ), */
- {0,SQLITE_UTF8,SQLITE_FUNC_COUNT,0,0,0,countStep,countFinalize,"count",0},
+ {0,SQLITE_UTF8,SQLITE_FUNC_COUNT,0,0,0,countStep,countFinalize,"count",0,0},
AGGREGATE(count, 1, 0, 0, countStep, countFinalize ),
AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize),
AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize),
@@ -80486,7 +81809,7 @@ static void fkLookupParent(
sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb);
sqlite3VdbeChangeP4(v, -1, (char*)pKey, P4_KEYINFO_HANDOFF);
for(i=0; i<nCol; i++){
- sqlite3VdbeAddOp2(v, OP_SCopy, aiCol[i]+1+regData, regTemp+i);
+ sqlite3VdbeAddOp2(v, OP_Copy, aiCol[i]+1+regData, regTemp+i);
}
/* If the parent table is the same as the child table, and we are about
@@ -83488,6 +84811,27 @@ struct sqlite3_api_routines {
sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
const char *(*sql)(sqlite3_stmt*);
int (*status)(int,int*,int*,int);
+ int (*backup_finish)(sqlite3_backup*);
+ sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
+ int (*backup_pagecount)(sqlite3_backup*);
+ int (*backup_remaining)(sqlite3_backup*);
+ int (*backup_step)(sqlite3_backup*,int);
+ const char *(*compileoption_get)(int);
+ int (*compileoption_used)(const char*);
+ int (*create_function_v2)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*),void(*xDestroy)(void*));
+ int (*db_config)(sqlite3*,int,...);
+ sqlite3_mutex *(*db_mutex)(sqlite3*);
+ int (*db_status)(sqlite3*,int,int*,int*,int);
+ int (*extended_errcode)(sqlite3*);
+ void (*log)(int,const char*,...);
+ sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
+ const char *(*sourceid)(void);
+ int (*stmt_status)(sqlite3_stmt*,int,int);
+ int (*strnicmp)(const char*,const char*,int);
+ int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
+ int (*wal_autocheckpoint)(sqlite3*,int);
+ int (*wal_checkpoint)(sqlite3*,const char*);
+ void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
};
/*
@@ -83667,6 +85011,27 @@ struct sqlite3_api_routines {
#define sqlite3_next_stmt sqlite3_api->next_stmt
#define sqlite3_sql sqlite3_api->sql
#define sqlite3_status sqlite3_api->status
+#define sqlite3_backup_finish sqlite3_api->backup_finish
+#define sqlite3_backup_init sqlite3_api->backup_init
+#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount
+#define sqlite3_backup_remaining sqlite3_api->backup_remaining
+#define sqlite3_backup_step sqlite3_api->backup_step
+#define sqlite3_compileoption_get sqlite3_api->compileoption_get
+#define sqlite3_compileoption_used sqlite3_api->compileoption_used
+#define sqlite3_create_function_v2 sqlite3_api->create_function_v2
+#define sqlite3_db_config sqlite3_api->db_config
+#define sqlite3_db_mutex sqlite3_api->db_mutex
+#define sqlite3_db_status sqlite3_api->db_status
+#define sqlite3_extended_errcode sqlite3_api->extended_errcode
+#define sqlite3_log sqlite3_api->log
+#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64
+#define sqlite3_sourceid sqlite3_api->sourceid
+#define sqlite3_stmt_status sqlite3_api->stmt_status
+#define sqlite3_strnicmp sqlite3_api->strnicmp
+#define sqlite3_unlock_notify sqlite3_api->unlock_notify
+#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
+#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
+#define sqlite3_wal_hook sqlite3_api->wal_hook
#endif /* SQLITE_CORE */
#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0;
@@ -83984,6 +85349,46 @@ static const sqlite3_api_routines sqlite3Apis = {
sqlite3_next_stmt,
sqlite3_sql,
sqlite3_status,
+
+ /*
+ ** Added for 3.7.4
+ */
+ sqlite3_backup_finish,
+ sqlite3_backup_init,
+ sqlite3_backup_pagecount,
+ sqlite3_backup_remaining,
+ sqlite3_backup_step,
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+ sqlite3_compileoption_get,
+ sqlite3_compileoption_used,
+#else
+ 0,
+ 0,
+#endif
+ sqlite3_create_function_v2,
+ sqlite3_db_config,
+ sqlite3_db_mutex,
+ sqlite3_db_status,
+ sqlite3_extended_errcode,
+ sqlite3_log,
+ sqlite3_soft_heap_limit64,
+ sqlite3_sourceid,
+ sqlite3_stmt_status,
+ sqlite3_strnicmp,
+#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
+ sqlite3_unlock_notify,
+#else
+ 0,
+#endif
+#ifndef SQLITE_OMIT_WAL
+ sqlite3_wal_autocheckpoint,
+ sqlite3_wal_checkpoint,
+ sqlite3_wal_hook,
+#else
+ 0,
+ 0,
+ 0,
+#endif
};
/*
@@ -84299,7 +85704,7 @@ static u8 getSafetyLevel(const char *z){
static const u8 iValue[] = {1, 0, 0, 0, 1, 1, 2};
int i, n;
if( sqlite3Isdigit(*z) ){
- return (u8)atoi(z);
+ return (u8)sqlite3Atoi(z);
}
n = sqlite3Strlen30(z);
for(i=0; i<ArraySize(iLength); i++){
@@ -84340,7 +85745,7 @@ static int getAutoVacuum(const char *z){
if( 0==sqlite3StrICmp(z, "none") ) return BTREE_AUTOVACUUM_NONE;
if( 0==sqlite3StrICmp(z, "full") ) return BTREE_AUTOVACUUM_FULL;
if( 0==sqlite3StrICmp(z, "incremental") ) return BTREE_AUTOVACUUM_INCR;
- i = atoi(z);
+ i = sqlite3Atoi(z);
return (u8)((i>=0&&i<=2)?i:0);
}
#endif /* ifndef SQLITE_OMIT_AUTOVACUUM */
@@ -84436,6 +85841,7 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
{ "empty_result_callbacks", SQLITE_NullCallback },
{ "legacy_file_format", SQLITE_LegacyFileFmt },
{ "fullfsync", SQLITE_FullFSync },
+ { "checkpoint_fullfsync", SQLITE_CkptFullFSync },
{ "reverse_unordered_selects", SQLITE_ReverseOrder },
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
{ "automatic_index", SQLITE_AutoIndex },
@@ -84647,7 +86053,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3VdbeChangeP1(v, addr+1, iDb);
sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE);
}else{
- int size = atoi(zRight);
+ int size = sqlite3Atoi(zRight);
if( size<0 ) size = -size;
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
@@ -84676,7 +86082,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
/* Malloc may fail when setting the page-size, as there is an internal
** buffer that the pager module resizes using sqlite3_realloc().
*/
- db->nextPagesize = atoi(zRight);
+ db->nextPagesize = sqlite3Atoi(zRight);
if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
db->mallocFailed = 1;
}
@@ -84684,28 +86090,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
}else
/*
- ** PRAGMA [database.]max_page_count
- ** PRAGMA [database.]max_page_count=N
- **
- ** The first form reports the current setting for the
- ** maximum number of pages in the database file. The
- ** second form attempts to change this setting. Both
- ** forms return the current setting.
- */
- if( sqlite3StrICmp(zLeft,"max_page_count")==0 ){
- Btree *pBt = pDb->pBt;
- int newMax = 0;
- assert( pBt!=0 );
- if( zRight ){
- newMax = atoi(zRight);
- }
- if( ALWAYS(pBt) ){
- newMax = sqlite3BtreeMaxPageCount(pBt, newMax);
- }
- returnSingleInt(pParse, "max_page_count", newMax);
- }else
-
- /*
** PRAGMA [database.]secure_delete
** PRAGMA [database.]secure_delete=ON/OFF
**
@@ -84731,19 +86115,33 @@ SQLITE_PRIVATE void sqlite3Pragma(
}else
/*
+ ** PRAGMA [database.]max_page_count
+ ** PRAGMA [database.]max_page_count=N
+ **
+ ** The first form reports the current setting for the
+ ** maximum number of pages in the database file. The
+ ** second form attempts to change this setting. Both
+ ** forms return the current setting.
+ **
** PRAGMA [database.]page_count
**
** Return the number of pages in the specified database.
*/
- if( sqlite3StrICmp(zLeft,"page_count")==0 ){
+ if( sqlite3StrICmp(zLeft,"page_count")==0
+ || sqlite3StrICmp(zLeft,"max_page_count")==0
+ ){
int iReg;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3CodeVerifySchema(pParse, iDb);
iReg = ++pParse->nMem;
- sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
+ if( zLeft[0]=='p' ){
+ sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
+ }else{
+ sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, sqlite3Atoi(zRight));
+ }
sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1);
sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "page_count", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
}else
/*
@@ -84851,7 +86249,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
Pager *pPager = sqlite3BtreePager(pDb->pBt);
i64 iLimit = -2;
if( zRight ){
- sqlite3Atoi64(zRight, &iLimit);
+ sqlite3Atoi64(zRight, &iLimit, 1000000, SQLITE_UTF8);
if( iLimit<-1 ) iLimit = -1;
}
iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
@@ -84965,7 +86363,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( !zRight ){
returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
}else{
- int size = atoi(zRight);
+ int size = sqlite3Atoi(zRight);
if( size<0 ) size = -size;
pDb->pSchema->cache_size = size;
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
@@ -85358,7 +86756,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
/* Set the maximum error count */
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
if( zRight ){
- mxErr = atoi(zRight);
+ sqlite3GetInt32(zRight, &mxErr);
if( mxErr<=0 ){
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
}
@@ -85615,7 +87013,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
};
int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie);
sqlite3VdbeChangeP1(v, addr, iDb);
- sqlite3VdbeChangeP1(v, addr+1, atoi(zRight));
+ sqlite3VdbeChangeP1(v, addr+1, sqlite3Atoi(zRight));
sqlite3VdbeChangeP1(v, addr+2, iDb);
sqlite3VdbeChangeP2(v, addr+2, iCookie);
}else{
@@ -85676,8 +87074,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
*/
if( sqlite3StrICmp(zLeft, "wal_autocheckpoint")==0 ){
if( zRight ){
- int nAuto = atoi(zRight);
- sqlite3_wal_autocheckpoint(db, nAuto);
+ sqlite3_wal_autocheckpoint(db, sqlite3Atoi(zRight));
}
returnSingleInt(pParse, "wal_autocheckpoint",
db->xWalCallback==sqlite3WalDefaultHook ?
@@ -85767,7 +87164,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
if( db->autoCommit ){
sqlite3BtreeSetSafetyLevel(pDb->pBt, pDb->safety_level,
- (db->flags&SQLITE_FullFSync)!=0);
+ (db->flags&SQLITE_FullFSync)!=0,
+ (db->flags&SQLITE_CkptFullFSync)!=0);
}
#endif
pragma_out:
@@ -85859,7 +87257,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
assert( db->init.busy );
db->init.iDb = iDb;
- db->init.newTnum = atoi(argv[1]);
+ db->init.newTnum = sqlite3Atoi(argv[1]);
db->init.orphanTrigger = 0;
TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
rc = db->errCode;
@@ -86408,13 +87806,13 @@ static int sqlite3Prepare(
if( rc==SQLITE_OK && pParse->pVdbe && pParse->explain ){
static const char * const azColName[] = {
"addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
- "order", "from", "detail"
+ "selectid", "order", "from", "detail"
};
int iFirst, mx;
if( pParse->explain==2 ){
- sqlite3VdbeSetNumCols(pParse->pVdbe, 3);
+ sqlite3VdbeSetNumCols(pParse->pVdbe, 4);
iFirst = 8;
- mx = 11;
+ mx = 12;
}else{
sqlite3VdbeSetNumCols(pParse->pVdbe, 8);
iFirst = 0;
@@ -86564,7 +87962,7 @@ SQLITE_API int sqlite3_prepare_v2(
*/
static int sqlite3Prepare16(
sqlite3 *db, /* Database handle. */
- const void *zSql, /* UTF-8 encoded SQL statement. */
+ const void *zSql, /* UTF-16 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
int saveSqlFlag, /* True to save SQL text into the sqlite3_stmt */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
@@ -86614,7 +88012,7 @@ static int sqlite3Prepare16(
*/
SQLITE_API int sqlite3_prepare16(
sqlite3 *db, /* Database handle. */
- const void *zSql, /* UTF-8 encoded SQL statement. */
+ const void *zSql, /* UTF-16 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const void **pzTail /* OUT: End of parsed string */
@@ -86626,7 +88024,7 @@ SQLITE_API int sqlite3_prepare16(
}
SQLITE_API int sqlite3_prepare16_v2(
sqlite3 *db, /* Database handle. */
- const void *zSql, /* UTF-8 encoded SQL statement. */
+ const void *zSql, /* UTF-16 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const void **pzTail /* OUT: End of parsed string */
@@ -87084,7 +88482,6 @@ static void pushOntoSorter(
sqlite3VdbeAddOp1(v, OP_Last, pOrderBy->iECursor);
sqlite3VdbeAddOp1(v, OP_Delete, pOrderBy->iECursor);
sqlite3VdbeJumpHere(v, addr2);
- pSelect->iLimit = 0;
}
}
@@ -87133,11 +88530,13 @@ static void codeDistinct(
sqlite3ReleaseTempReg(pParse, r1);
}
+#ifndef SQLITE_OMIT_SUBQUERY
/*
** Generate an error message when a SELECT is used within a subexpression
** (example: "a IN (SELECT * FROM table)") but it has more than 1 result
-** column. We do this in a subroutine because the error occurs in multiple
-** places.
+** column. We do this in a subroutine because the error used to occur
+** in multiple places. (The error only occurs in one place now, but we
+** retain the subroutine to minimize code disruption.)
*/
static int checkForMultiColumnSelectError(
Parse *pParse, /* Parse context. */
@@ -87153,6 +88552,7 @@ static int checkForMultiColumnSelectError(
return 0;
}
}
+#endif
/*
** This routine generates the code for the inside of the inner loop
@@ -87232,10 +88632,6 @@ static void selectInnerLoop(
}
}
- if( checkForMultiColumnSelectError(pParse, pDest, pEList->nExpr) ){
- return;
- }
-
switch( eDest ){
/* In this mode, write each query result to the key of the temporary
** table iParm.
@@ -87364,11 +88760,11 @@ static void selectInnerLoop(
#endif
}
- /* Jump to the end of the loop if the LIMIT is reached.
+ /* Jump to the end of the loop if the LIMIT is reached. Except, if
+ ** there is a sorter, in which case the sorter has already limited
+ ** the output for us.
*/
- if( p->iLimit ){
- assert( pOrderBy==0 ); /* If there is an ORDER BY, the call to
- ** pushOntoSorter() would have cleared p->iLimit */
+ if( pOrderBy==0 && p->iLimit ){
sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1);
}
}
@@ -87415,6 +88811,88 @@ static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList){
return pInfo;
}
+#ifndef SQLITE_OMIT_COMPOUND_SELECT
+/*
+** Name of the connection operator, used for error messages.
+*/
+static const char *selectOpName(int id){
+ char *z;
+ switch( id ){
+ case TK_ALL: z = "UNION ALL"; break;
+ case TK_INTERSECT: z = "INTERSECT"; break;
+ case TK_EXCEPT: z = "EXCEPT"; break;
+ default: z = "UNION"; break;
+ }
+ return z;
+}
+#endif /* SQLITE_OMIT_COMPOUND_SELECT */
+
+#ifndef SQLITE_OMIT_EXPLAIN
+/*
+** Unless an "EXPLAIN QUERY PLAN" command is being processed, this function
+** is a no-op. Otherwise, it adds a single row of output to the EQP result,
+** where the caption is of the form:
+**
+** "USE TEMP B-TREE FOR xxx"
+**
+** where xxx is one of "DISTINCT", "ORDER BY" or "GROUP BY". Exactly which
+** is determined by the zUsage argument.
+*/
+static void explainTempTable(Parse *pParse, const char *zUsage){
+ if( pParse->explain==2 ){
+ Vdbe *v = pParse->pVdbe;
+ char *zMsg = sqlite3MPrintf(pParse->db, "USE TEMP B-TREE FOR %s", zUsage);
+ sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC);
+ }
+}
+
+/*
+** Unless an "EXPLAIN QUERY PLAN" command is being processed, this function
+** is a no-op. Otherwise, it adds a single row of output to the EQP result,
+** where the caption is of one of the two forms:
+**
+** "COMPOSITE SUBQUERIES iSub1 and iSub2 (op)"
+** "COMPOSITE SUBQUERIES iSub1 and iSub2 USING TEMP B-TREE (op)"
+**
+** where iSub1 and iSub2 are the integers passed as the corresponding
+** function parameters, and op is the text representation of the parameter
+** of the same name. The parameter "op" must be one of TK_UNION, TK_EXCEPT,
+** TK_INTERSECT or TK_ALL. The first form is used if argument bUseTmp is
+** false, or the second form if it is true.
+*/
+static void explainComposite(
+ Parse *pParse, /* Parse context */
+ int op, /* One of TK_UNION, TK_EXCEPT etc. */
+ int iSub1, /* Subquery id 1 */
+ int iSub2, /* Subquery id 2 */
+ int bUseTmp /* True if a temp table was used */
+){
+ assert( op==TK_UNION || op==TK_EXCEPT || op==TK_INTERSECT || op==TK_ALL );
+ if( pParse->explain==2 ){
+ Vdbe *v = pParse->pVdbe;
+ char *zMsg = sqlite3MPrintf(
+ pParse->db, "COMPOUND SUBQUERIES %d AND %d %s(%s)", iSub1, iSub2,
+ bUseTmp?"USING TEMP B-TREE ":"", selectOpName(op)
+ );
+ sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC);
+ }
+}
+
+/*
+** Assign expression b to lvalue a. A second, no-op, version of this macro
+** is provided when SQLITE_OMIT_EXPLAIN is defined. This allows the code
+** in sqlite3Select() to assign values to structure member variables that
+** only exist if SQLITE_OMIT_EXPLAIN is not defined without polluting the
+** code with #ifndef directives.
+*/
+# define explainSetInteger(a, b) a = b
+
+#else
+/* No-op versions of the explainXXX() functions and macros. */
+# define explainTempTable(y,z)
+# define explainComposite(v,w,x,y,z)
+# define explainSetInteger(y,z)
+#endif
/*
** If the inner loop was generated using a non-null pOrderBy argument,
@@ -87503,10 +88981,6 @@ static void generateSortTail(
sqlite3ReleaseTempReg(pParse, regRow);
sqlite3ReleaseTempReg(pParse, regRowid);
- /* LIMIT has been implemented by the pushOntoSorter() routine.
- */
- assert( p->iLimit==0 );
-
/* The bottom of the loop
*/
sqlite3VdbeResolveLabel(v, addrContinue);
@@ -87766,22 +89240,6 @@ static void generateColumnNames(
generateColumnTypes(pParse, pTabList, pEList);
}
-#ifndef SQLITE_OMIT_COMPOUND_SELECT
-/*
-** Name of the connection operator, used for error messages.
-*/
-static const char *selectOpName(int id){
- char *z;
- switch( id ){
- case TK_ALL: z = "UNION ALL"; break;
- case TK_INTERSECT: z = "INTERSECT"; break;
- case TK_EXCEPT: z = "EXCEPT"; break;
- default: z = "UNION"; break;
- }
- return z;
-}
-#endif /* SQLITE_OMIT_COMPOUND_SELECT */
-
/*
** Given a an expression list (which is really the list of expressions
** that form the result set of a SELECT statement) compute appropriate
@@ -87944,6 +89402,7 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
assert( db->lookaside.bEnabled==0 );
pTab->nRef = 1;
pTab->zName = 0;
+ pTab->nRowEst = 1000000;
selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSelect);
pTab->iPKey = -1;
@@ -88014,6 +89473,8 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
VdbeComment((v, "LIMIT counter"));
if( n==0 ){
sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak);
+ }else{
+ if( p->nSelectRow > (double)n ) p->nSelectRow = (double)n;
}
}else{
sqlite3ExprCode(pParse, p->pLimit, iLimit);
@@ -88114,6 +89575,10 @@ static int multiSelect(
SelectDest dest; /* Alternative data destination */
Select *pDelete = 0; /* Chain of simple selects to delete */
sqlite3 *db; /* Database connection */
+#ifndef SQLITE_OMIT_EXPLAIN
+ int iSub1; /* EQP id of left-hand query */
+ int iSub2; /* EQP id of right-hand query */
+#endif
/* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only
** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT.
@@ -88145,6 +89610,7 @@ static int multiSelect(
if( dest.eDest==SRT_EphemTab ){
assert( p->pEList );
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iParm, p->pEList->nExpr);
+ sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
dest.eDest = SRT_Table;
}
@@ -88170,9 +89636,11 @@ static int multiSelect(
switch( p->op ){
case TK_ALL: {
int addr = 0;
+ int nLimit;
assert( !pPrior->pLimit );
pPrior->pLimit = p->pLimit;
pPrior->pOffset = p->pOffset;
+ explainSetInteger(iSub1, pParse->iNextSelectId);
rc = sqlite3Select(pParse, pPrior, &dest);
p->pLimit = 0;
p->pOffset = 0;
@@ -88186,10 +89654,18 @@ static int multiSelect(
addr = sqlite3VdbeAddOp1(v, OP_IfZero, p->iLimit);
VdbeComment((v, "Jump ahead if LIMIT reached"));
}
+ explainSetInteger(iSub2, pParse->iNextSelectId);
rc = sqlite3Select(pParse, p, &dest);
testcase( rc!=SQLITE_OK );
pDelete = p->pPrior;
p->pPrior = pPrior;
+ p->nSelectRow += pPrior->nSelectRow;
+ if( pPrior->pLimit
+ && sqlite3ExprIsInteger(pPrior->pLimit, &nLimit)
+ && p->nSelectRow > (double)nLimit
+ ){
+ p->nSelectRow = (double)nLimit;
+ }
if( addr ){
sqlite3VdbeJumpHere(v, addr);
}
@@ -88233,6 +89709,7 @@ static int multiSelect(
*/
assert( !pPrior->pOrderBy );
sqlite3SelectDestInit(&uniondest, priorOp, unionTab);
+ explainSetInteger(iSub1, pParse->iNextSelectId);
rc = sqlite3Select(pParse, pPrior, &uniondest);
if( rc ){
goto multi_select_end;
@@ -88252,6 +89729,7 @@ static int multiSelect(
pOffset = p->pOffset;
p->pOffset = 0;
uniondest.eDest = op;
+ explainSetInteger(iSub2, pParse->iNextSelectId);
rc = sqlite3Select(pParse, p, &uniondest);
testcase( rc!=SQLITE_OK );
/* Query flattening in sqlite3Select() might refill p->pOrderBy.
@@ -88260,6 +89738,7 @@ static int multiSelect(
pDelete = p->pPrior;
p->pPrior = pPrior;
p->pOrderBy = 0;
+ if( p->op==TK_UNION ) p->nSelectRow += pPrior->nSelectRow;
sqlite3ExprDelete(db, p->pLimit);
p->pLimit = pLimit;
p->pOffset = pOffset;
@@ -88317,6 +89796,7 @@ static int multiSelect(
/* Code the SELECTs to our left into temporary table "tab1".
*/
sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1);
+ explainSetInteger(iSub1, pParse->iNextSelectId);
rc = sqlite3Select(pParse, pPrior, &intersectdest);
if( rc ){
goto multi_select_end;
@@ -88333,10 +89813,12 @@ static int multiSelect(
pOffset = p->pOffset;
p->pOffset = 0;
intersectdest.iParm = tab2;
+ explainSetInteger(iSub2, pParse->iNextSelectId);
rc = sqlite3Select(pParse, p, &intersectdest);
testcase( rc!=SQLITE_OK );
pDelete = p->pPrior;
p->pPrior = pPrior;
+ if( p->nSelectRow>pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow;
sqlite3ExprDelete(db, p->pLimit);
p->pLimit = pLimit;
p->pOffset = pOffset;
@@ -88369,6 +89851,8 @@ static int multiSelect(
}
}
+ explainComposite(pParse, p->op, iSub1, iSub2, p->op!=TK_ALL);
+
/* Compute collating sequences used by
** temporary tables needed to implement the compound select.
** Attach the KeyInfo structure to all temporary tables.
@@ -88712,6 +90196,10 @@ static int multiSelectOrderBy(
ExprList *pOrderBy; /* The ORDER BY clause */
int nOrderBy; /* Number of terms in the ORDER BY clause */
int *aPermute; /* Mapping from ORDER BY terms to result set columns */
+#ifndef SQLITE_OMIT_EXPLAIN
+ int iSub1; /* EQP id of left-hand query */
+ int iSub2; /* EQP id of right-hand query */
+#endif
assert( p->pOrderBy!=0 );
assert( pKeyDup==0 ); /* "Managed" code needs this. Ticket #3382. */
@@ -88823,7 +90311,6 @@ static int multiSelectOrderBy(
/* Separate the left and the right query from one another
*/
p->pPrior = 0;
- pPrior->pRightmost = 0;
sqlite3ResolveOrderGroupBy(pParse, p, p->pOrderBy, "ORDER");
if( pPrior->pPrior==0 ){
sqlite3ResolveOrderGroupBy(pParse, pPrior, pPrior->pOrderBy, "ORDER");
@@ -88866,6 +90353,7 @@ static int multiSelectOrderBy(
*/
VdbeNoopComment((v, "Begin coroutine for left SELECT"));
pPrior->iLimit = regLimitA;
+ explainSetInteger(iSub1, pParse->iNextSelectId);
sqlite3Select(pParse, pPrior, &destA);
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofA);
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
@@ -88880,6 +90368,7 @@ static int multiSelectOrderBy(
savedOffset = p->iOffset;
p->iLimit = regLimitB;
p->iOffset = 0;
+ explainSetInteger(iSub2, pParse->iNextSelectId);
sqlite3Select(pParse, p, &destB);
p->iLimit = savedLimit;
p->iOffset = savedOffset;
@@ -88916,6 +90405,7 @@ static int multiSelectOrderBy(
sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofA);
+ p->nSelectRow += pPrior->nSelectRow;
}
/* Generate a subroutine to run when the results from select B
@@ -88923,6 +90413,7 @@ static int multiSelectOrderBy(
*/
if( op==TK_INTERSECT ){
addrEofB = addrEofA;
+ if( p->nSelectRow > pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow;
}else{
VdbeNoopComment((v, "eof-B subroutine"));
addrEofB = sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd);
@@ -89010,6 +90501,7 @@ static int multiSelectOrderBy(
/*** TBD: Insert subroutine calls to close cursors on incomplete
**** subqueries ****/
+ explainComposite(pParse, p->op, iSub1, iSub2, 0);
return SQLITE_OK;
}
#endif
@@ -89743,6 +91235,7 @@ static int selectExpander(Walker *pWalker, Select *p){
while( pSel->pPrior ){ pSel = pSel->pPrior; }
selectColumnsFromExprList(pParse, pSel->pEList, &pTab->nCol, &pTab->aCol);
pTab->iPKey = -1;
+ pTab->nRowEst = 1000000;
pTab->tabFlags |= TF_Ephemeral;
#endif
}else{
@@ -90107,7 +91600,7 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
if( pList ){
nArg = pList->nExpr;
regAgg = sqlite3GetTempRange(pParse, nArg);
- sqlite3ExprCodeExprList(pParse, pList, regAgg, 0);
+ sqlite3ExprCodeExprList(pParse, pList, regAgg, 1);
}else{
nArg = 0;
regAgg = 0;
@@ -90236,6 +91729,11 @@ SQLITE_PRIVATE int sqlite3Select(
int iEnd; /* Address of the end of the query */
sqlite3 *db; /* The database connection */
+#ifndef SQLITE_OMIT_EXPLAIN
+ int iRestoreSelectId = pParse->iSelectId;
+ pParse->iSelectId = pParse->iNextSelectId++;
+#endif
+
db = pParse->db;
if( p==0 || db->mallocFailed || pParse->nErr ){
return 1;
@@ -90267,6 +91765,15 @@ SQLITE_PRIVATE int sqlite3Select(
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto select_end;
+ /* If writing to memory or generating a set
+ ** only a single column may be output.
+ */
+#ifndef SQLITE_OMIT_SUBQUERY
+ if( checkForMultiColumnSelectError(pParse, pDest, pEList->nExpr) ){
+ goto select_end;
+ }
+#endif
+
/* Generate code for all sub-queries in the FROM clause
*/
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
@@ -90298,8 +91805,10 @@ SQLITE_PRIVATE int sqlite3Select(
}else{
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
assert( pItem->isPopulated==0 );
+ explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
sqlite3Select(pParse, pSub, &dest);
pItem->isPopulated = 1;
+ pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
}
if( /*pParse->nErr ||*/ db->mallocFailed ){
goto select_end;
@@ -90333,19 +91842,12 @@ SQLITE_PRIVATE int sqlite3Select(
mxSelect = db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT];
if( mxSelect && cnt>mxSelect ){
sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
- return 1;
+ goto select_end;
}
}
- return multiSelect(pParse, p, pDest);
- }
-#endif
-
- /* If writing to memory or generating a set
- ** only a single column may be output.
- */
-#ifndef SQLITE_OMIT_SUBQUERY
- if( checkForMultiColumnSelectError(pParse, pDest, pEList->nExpr) ){
- goto select_end;
+ rc = multiSelect(pParse, p, pDest);
+ explainSetInteger(pParse->iSelectId, iRestoreSelectId);
+ return rc;
}
#endif
@@ -90357,7 +91859,6 @@ SQLITE_PRIVATE int sqlite3Select(
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
pGroupBy = p->pGroupBy;
p->selFlags &= ~SF_Distinct;
- isDistinct = 0;
}
/* If there is both a GROUP BY and an ORDER BY clause and they are
@@ -90400,17 +91901,19 @@ SQLITE_PRIVATE int sqlite3Select(
/* Set the limiter.
*/
iEnd = sqlite3VdbeMakeLabel(v);
+ p->nSelectRow = (double)LARGEST_INT64;
computeLimitRegisters(pParse, p, iEnd);
/* Open a virtual index to use for the distinct set.
*/
- if( isDistinct ){
+ if( p->selFlags & SF_Distinct ){
KeyInfo *pKeyInfo;
assert( isAgg || pGroupBy );
distinct = pParse->nTab++;
pKeyInfo = keyInfoFromExprList(pParse, p->pEList);
sqlite3VdbeAddOp4(v, OP_OpenEphemeral, distinct, 0, 0,
(char*)pKeyInfo, P4_KEYINFO_HANDOFF);
+ sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
}else{
distinct = -1;
}
@@ -90422,6 +91925,7 @@ SQLITE_PRIVATE int sqlite3Select(
*/
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pOrderBy, 0);
if( pWInfo==0 ) goto select_end;
+ if( pWInfo->nRowOut < p->nSelectRow ) p->nSelectRow = pWInfo->nRowOut;
/* If sorting index that was created by a prior OP_OpenEphemeral
** instruction ended up not being needed, then change the OP_OpenEphemeral
@@ -90466,6 +91970,9 @@ SQLITE_PRIVATE int sqlite3Select(
for(k=pGroupBy->nExpr, pItem=pGroupBy->a; k>0; k--, pItem++){
pItem->iAlias = 0;
}
+ if( p->nSelectRow>(double)100 ) p->nSelectRow = (double)100;
+ }else{
+ p->nSelectRow = (double)1;
}
@@ -90562,6 +92069,9 @@ SQLITE_PRIVATE int sqlite3Select(
int nCol;
int nGroupBy;
+ explainTempTable(pParse,
+ isDistinct && !(p->selFlags&SF_Distinct)?"DISTINCT":"GROUP BY");
+
groupBySort = 1;
nGroupBy = pGroupBy->nExpr;
nCol = nGroupBy + 1;
@@ -90823,10 +92333,15 @@ SQLITE_PRIVATE int sqlite3Select(
} /* endif aggregate query */
+ if( distinct>=0 ){
+ explainTempTable(pParse, "DISTINCT");
+ }
+
/* If there is an ORDER BY clause, then we need to sort the results
** and send them to the callback one by one.
*/
if( pOrderBy ){
+ explainTempTable(pParse, "ORDER BY");
generateSortTail(pParse, p, v, pEList->nExpr, pDest);
}
@@ -90843,6 +92358,7 @@ SQLITE_PRIVATE int sqlite3Select(
** successful coding of the SELECT.
*/
select_end:
+ explainSetInteger(pParse->iSelectId, iRestoreSelectId);
/* Identify column names if results of the SELECT are to be output.
*/
@@ -92886,6 +94402,7 @@ static void updateVirtualTable(
assert( v );
ephemTab = pParse->nTab++;
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, pTab->nCol+1+(pRowid!=0));
+ sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
/* fill the ephemeral table
*/
@@ -93025,6 +94542,10 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
return SQLITE_ERROR;
}
+ if( db->activeVdbeCnt>1 ){
+ sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress");
+ return SQLITE_ERROR;
+ }
/* Save the current value of the database flags so that it can be
** restored before returning. Then set the writable-schema flag, and
@@ -93626,7 +95147,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
- zWhere = sqlite3MPrintf(db, "name='%q'", pTab->zName);
+ zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 1, 0, zWhere, P4_DYNAMIC);
sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0,
pTab->zName, sqlite3Strlen30(pTab->zName) + 1);
@@ -93927,7 +95448,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
}
db->pVTab = 0;
}else{
- sqlite3Error(db, SQLITE_ERROR, zErr);
+ sqlite3Error(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
sqlite3DbFree(db, zErr);
rc = SQLITE_ERROR;
}
@@ -94389,7 +95910,6 @@ struct WhereMaskSet {
struct WhereCost {
WherePlan plan; /* The lookup strategy */
double rCost; /* Overall cost of pursuing this search strategy */
- double nRow; /* Estimated number of output rows */
Bitmask used; /* Bitmask of cursors used by this plan */
};
@@ -94432,10 +95952,11 @@ struct WhereCost {
#define WHERE_COLUMN_IN 0x00040000 /* x IN (...) */
#define WHERE_COLUMN_NULL 0x00080000 /* x IS NULL */
#define WHERE_INDEXED 0x000f0000 /* Anything that uses an index */
-#define WHERE_NOT_FULLSCAN 0x000f3000 /* Does not do a full table scan */
+#define WHERE_NOT_FULLSCAN 0x100f3000 /* Does not do a full table scan */
#define WHERE_IN_ABLE 0x000f1000 /* Able to support an IN operator */
#define WHERE_TOP_LIMIT 0x00100000 /* x<EXPR or x<=EXPR constraint */
#define WHERE_BTM_LIMIT 0x00200000 /* x>EXPR or x>=EXPR constraint */
+#define WHERE_BOTH_LIMIT 0x00300000 /* Both x>EXPR and x<EXPR */
#define WHERE_IDX_ONLY 0x00800000 /* Use index only - omit table */
#define WHERE_ORDERBY 0x01000000 /* Output will appear in correct order */
#define WHERE_REVERSE 0x02000000 /* Scan in reverse order */
@@ -94866,11 +96387,12 @@ static int isLikeOrGlob(
}
if( op==TK_VARIABLE ){
Vdbe *pReprepare = pParse->pReprepare;
- pVal = sqlite3VdbeGetValue(pReprepare, pRight->iColumn, SQLITE_AFF_NONE);
+ int iCol = pRight->iColumn;
+ pVal = sqlite3VdbeGetValue(pReprepare, iCol, SQLITE_AFF_NONE);
if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){
z = (char *)sqlite3_value_text(pVal);
}
- sqlite3VdbeSetVarmask(pParse->pVdbe, pRight->iColumn);
+ sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); /* IMP: R-23257-02778 */
assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER );
}else if( op==TK_STRING ){
z = pRight->u.zToken;
@@ -94888,7 +96410,7 @@ static int isLikeOrGlob(
*ppPrefix = pPrefix;
if( op==TK_VARIABLE ){
Vdbe *v = pParse->pVdbe;
- sqlite3VdbeSetVarmask(v, pRight->iColumn);
+ sqlite3VdbeSetVarmask(v, pRight->iColumn); /* IMP: R-23257-02778 */
if( *pisComplete && pRight->u.zToken[1] ){
/* If the rhs of the LIKE expression is a variable, and the current
** value of the variable means there is no need to invoke the LIKE
@@ -95752,7 +97274,8 @@ static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){
** Required because bestIndex() is called by bestOrClauseIndex()
*/
static void bestIndex(
- Parse*, WhereClause*, struct SrcList_item*, Bitmask, ExprList*, WhereCost*);
+ Parse*, WhereClause*, struct SrcList_item*,
+ Bitmask, Bitmask, ExprList*, WhereCost*);
/*
** This routine attempts to find an scanning strategy that can be used
@@ -95765,7 +97288,8 @@ static void bestOrClauseIndex(
Parse *pParse, /* The parsing context */
WhereClause *pWC, /* The WHERE clause */
struct SrcList_item *pSrc, /* The FROM clause term to search */
- Bitmask notReady, /* Mask of cursors that are not available */
+ Bitmask notReady, /* Mask of cursors not available for indexing */
+ Bitmask notValid, /* Cursors not available for any purpose */
ExprList *pOrderBy, /* The ORDER BY clause */
WhereCost *pCost /* Lowest cost query plan */
){
@@ -95775,8 +97299,9 @@ static void bestOrClauseIndex(
WhereTerm * const pWCEnd = &pWC->a[pWC->nTerm]; /* End of pWC->a[] */
WhereTerm *pTerm; /* A single term of the WHERE clause */
- /* No OR-clause optimization allowed if the NOT INDEXED clause is used */
- if( pSrc->notIndexed ){
+ /* No OR-clause optimization allowed if the INDEXED BY or NOT INDEXED clauses
+ ** are used */
+ if( pSrc->notIndexed || pSrc->pIndex!=0 ){
return;
}
@@ -95801,7 +97326,7 @@ static void bestOrClauseIndex(
));
if( pOrTerm->eOperator==WO_AND ){
WhereClause *pAndWC = &pOrTerm->u.pAndInfo->wc;
- bestIndex(pParse, pAndWC, pSrc, notReady, 0, &sTermCost);
+ bestIndex(pParse, pAndWC, pSrc, notReady, notValid, 0, &sTermCost);
}else if( pOrTerm->leftCursor==iCur ){
WhereClause tempWC;
tempWC.pParse = pWC->pParse;
@@ -95809,12 +97334,12 @@ static void bestOrClauseIndex(
tempWC.op = TK_AND;
tempWC.a = pOrTerm;
tempWC.nTerm = 1;
- bestIndex(pParse, &tempWC, pSrc, notReady, 0, &sTermCost);
+ bestIndex(pParse, &tempWC, pSrc, notReady, notValid, 0, &sTermCost);
}else{
continue;
}
rTotal += sTermCost.rCost;
- nRow += sTermCost.nRow;
+ nRow += sTermCost.plan.nRow;
used |= sTermCost.used;
if( rTotal>=pCost->rCost ) break;
}
@@ -95833,8 +97358,8 @@ static void bestOrClauseIndex(
WHERETRACE(("... multi-index OR cost=%.9g nrow=%.9g\n", rTotal, nRow));
if( rTotal<pCost->rCost ){
pCost->rCost = rTotal;
- pCost->nRow = nRow;
pCost->used = used;
+ pCost->plan.nRow = nRow;
pCost->plan.wsFlags = flags;
pCost->plan.u.pTerm = pTerm;
}
@@ -95902,7 +97427,7 @@ static void bestAutomaticIndex(
assert( pParse->nQueryLoop >= (double)1 );
pTable = pSrc->pTab;
- nTableRow = pTable->pIndex ? pTable->pIndex->aiRowEst[0] : 1000000;
+ nTableRow = pTable->nRowEst;
logN = estLog(nTableRow);
costTempIdx = 2*logN*(nTableRow/pParse->nQueryLoop + 1);
if( costTempIdx>=pCost->rCost ){
@@ -95918,7 +97443,7 @@ static void bestAutomaticIndex(
WHERETRACE(("auto-index reduces cost from %.2f to %.2f\n",
pCost->rCost, costTempIdx));
pCost->rCost = costTempIdx;
- pCost->nRow = logN + 1;
+ pCost->plan.nRow = logN + 1;
pCost->plan.wsFlags = WHERE_TEMP_INDEX;
pCost->used = pTerm->prereqRight;
break;
@@ -96256,7 +97781,8 @@ static void bestVirtualIndex(
Parse *pParse, /* The parsing context */
WhereClause *pWC, /* The WHERE clause */
struct SrcList_item *pSrc, /* The FROM clause term to search */
- Bitmask notReady, /* Mask of cursors that are not available */
+ Bitmask notReady, /* Mask of cursors not available for index */
+ Bitmask notValid, /* Cursors not valid for any purpose */
ExprList *pOrderBy, /* The order by clause */
WhereCost *pCost, /* Lowest cost query plan */
sqlite3_index_info **ppIdxInfo /* Index information passed to xBestIndex */
@@ -96386,7 +97912,7 @@ static void bestVirtualIndex(
/* Try to find a more efficient access pattern by using multiple indexes
** to optimize an OR expression within the WHERE clause.
*/
- bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost);
+ bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost);
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -96507,12 +98033,11 @@ static int valueFromExpr(
u8 aff,
sqlite3_value **pp
){
- /* The evalConstExpr() function will have already converted any TK_VARIABLE
- ** expression involved in an comparison into a TK_REGISTER. */
- assert( pExpr->op!=TK_VARIABLE );
- if( pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE ){
+ if( pExpr->op==TK_VARIABLE
+ || (pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
+ ){
int iVar = pExpr->iColumn;
- sqlite3VdbeSetVarmask(pParse->pVdbe, iVar);
+ sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); /* IMP: R-23257-02778 */
*pp = sqlite3VdbeGetValue(pParse->pReprepare, iVar, aff);
return SQLITE_OK;
}
@@ -96667,7 +98192,8 @@ static void bestBtreeIndex(
Parse *pParse, /* The parsing context */
WhereClause *pWC, /* The WHERE clause */
struct SrcList_item *pSrc, /* The FROM clause term to search */
- Bitmask notReady, /* Mask of cursors that are not available */
+ Bitmask notReady, /* Mask of cursors not available for indexing */
+ Bitmask notValid, /* Cursors not available for any purpose */
ExprList *pOrderBy, /* The ORDER BY clause */
WhereCost *pCost /* Lowest cost query plan */
){
@@ -96709,23 +98235,14 @@ static void bestBtreeIndex(
sPk.nColumn = 1;
sPk.aiColumn = &aiColumnPk;
sPk.aiRowEst = aiRowEstPk;
- aiRowEstPk[1] = 1;
sPk.onError = OE_Replace;
sPk.pTable = pSrc->pTab;
+ aiRowEstPk[0] = pSrc->pTab->nRowEst;
+ aiRowEstPk[1] = 1;
pFirst = pSrc->pTab->pIndex;
if( pSrc->notIndexed==0 ){
sPk.pNext = pFirst;
}
- /* The aiRowEstPk[0] is an estimate of the total number of rows in the
- ** table. Get this information from the ANALYZE information if it is
- ** available. If not available, assume the table 1 million rows in size.
- */
- if( pFirst ){
- assert( pFirst->aiRowEst!=0 ); /* Allocated together with pFirst */
- aiRowEstPk[0] = pFirst->aiRowEst[0];
- }else{
- aiRowEstPk[0] = 1000000;
- }
pProbe = &sPk;
wsFlagMask = ~(
WHERE_COLUMN_IN|WHERE_COLUMN_EQ|WHERE_COLUMN_NULL|WHERE_COLUMN_RANGE
@@ -96938,16 +98455,16 @@ static void bestBtreeIndex(
** with this step if we already know this index will not be chosen.
** Also, never reduce the output row count below 2 using this step.
**
- ** Do not reduce the output row count if pSrc is the only table that
- ** is notReady; if notReady is a power of two. This will be the case
- ** when the main sqlite3WhereBegin() loop is scanning for a table with
- ** and "optimal" index, and on such a scan the output row count
- ** reduction is not valid because it does not update the "pCost->used"
- ** bitmap. The notReady bitmap will also be a power of two when we
- ** are scanning for the last table in a 64-way join. We are willing
- ** to bypass this optimization in that corner case.
+ ** It is critical that the notValid mask be used here instead of
+ ** the notReady mask. When computing an "optimal" index, the notReady
+ ** mask will only have one bit set - the bit for the current table.
+ ** The notValid mask, on the other hand, always has all bits set for
+ ** tables that are not in outer loops. If notReady is used here instead
+ ** of notValid, then a optimal index that depends on inner joins loops
+ ** might be selected even when there exists an optimal index that has
+ ** no such dependency.
*/
- if( nRow>2 && cost<=pCost->rCost && (notReady & (notReady-1))!=0 ){
+ if( nRow>2 && cost<=pCost->rCost ){
int k; /* Loop counter */
int nSkipEq = nEq; /* Number of == constraints to skip */
int nSkipRange = nBound; /* Number of < constraints to skip */
@@ -96956,7 +98473,7 @@ static void bestBtreeIndex(
thisTab = getMask(pWC->pMaskSet, iCur);
for(pTerm=pWC->a, k=pWC->nTerm; nRow>2 && k; k--, pTerm++){
if( pTerm->wtFlags & TERM_VIRTUAL ) continue;
- if( (pTerm->prereqAll & notReady)!=thisTab ) continue;
+ if( (pTerm->prereqAll & notValid)!=thisTab ) continue;
if( pTerm->eOperator & (WO_EQ|WO_IN|WO_ISNULL) ){
if( nSkipEq ){
/* Ignore the first nEq equality matches since the index
@@ -96998,11 +98515,11 @@ static void bestBtreeIndex(
** index and its cost in the pCost structure.
*/
if( (!pIdx || wsFlags)
- && (cost<pCost->rCost || (cost<=pCost->rCost && nRow<pCost->nRow))
+ && (cost<pCost->rCost || (cost<=pCost->rCost && nRow<pCost->plan.nRow))
){
pCost->rCost = cost;
- pCost->nRow = nRow;
pCost->used = used;
+ pCost->plan.nRow = nRow;
pCost->plan.wsFlags = (wsFlags&wsFlagMask);
pCost->plan.nEq = nEq;
pCost->plan.u.pIdx = pIdx;
@@ -97038,7 +98555,7 @@ static void bestBtreeIndex(
pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk")
));
- bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost);
+ bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost);
bestAutomaticIndex(pParse, pWC, pSrc, notReady, pCost);
pCost->plan.wsFlags |= eqTermMask;
}
@@ -97053,14 +98570,15 @@ static void bestIndex(
Parse *pParse, /* The parsing context */
WhereClause *pWC, /* The WHERE clause */
struct SrcList_item *pSrc, /* The FROM clause term to search */
- Bitmask notReady, /* Mask of cursors that are not available */
+ Bitmask notReady, /* Mask of cursors not available for indexing */
+ Bitmask notValid, /* Cursors not available for any purpose */
ExprList *pOrderBy, /* The ORDER BY clause */
WhereCost *pCost /* Lowest cost query plan */
){
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pSrc->pTab) ){
sqlite3_index_info *p = 0;
- bestVirtualIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost, &p);
+ bestVirtualIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost,&p);
if( p->needToFreeIdxStr ){
sqlite3_free(p->idxStr);
}
@@ -97068,7 +98586,7 @@ static void bestIndex(
}else
#endif
{
- bestBtreeIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost);
+ bestBtreeIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost);
}
}
@@ -97330,6 +98848,161 @@ static int codeAllEqualityTerms(
return regBase;
}
+#ifndef SQLITE_OMIT_EXPLAIN
+/*
+** This routine is a helper for explainIndexRange() below
+**
+** pStr holds the text of an expression that we are building up one term
+** at a time. This routine adds a new term to the end of the expression.
+** Terms are separated by AND so add the "AND" text for second and subsequent
+** terms only.
+*/
+static void explainAppendTerm(
+ StrAccum *pStr, /* The text expression being built */
+ int iTerm, /* Index of this term. First is zero */
+ const char *zColumn, /* Name of the column */
+ const char *zOp /* Name of the operator */
+){
+ if( iTerm ) sqlite3StrAccumAppend(pStr, " AND ", 5);
+ sqlite3StrAccumAppend(pStr, zColumn, -1);
+ sqlite3StrAccumAppend(pStr, zOp, 1);
+ sqlite3StrAccumAppend(pStr, "?", 1);
+}
+
+/*
+** Argument pLevel describes a strategy for scanning table pTab. This
+** function returns a pointer to a string buffer containing a description
+** of the subset of table rows scanned by the strategy in the form of an
+** SQL expression. Or, if all rows are scanned, NULL is returned.
+**
+** For example, if the query:
+**
+** SELECT * FROM t1 WHERE a=1 AND b>2;
+**
+** is run and there is an index on (a, b), then this function returns a
+** string similar to:
+**
+** "a=? AND b>?"
+**
+** The returned pointer points to memory obtained from sqlite3DbMalloc().
+** It is the responsibility of the caller to free the buffer when it is
+** no longer required.
+*/
+static char *explainIndexRange(sqlite3 *db, WhereLevel *pLevel, Table *pTab){
+ WherePlan *pPlan = &pLevel->plan;
+ Index *pIndex = pPlan->u.pIdx;
+ int nEq = pPlan->nEq;
+ int i, j;
+ Column *aCol = pTab->aCol;
+ int *aiColumn = pIndex->aiColumn;
+ StrAccum txt;
+
+ if( nEq==0 && (pPlan->wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ){
+ return 0;
+ }
+ sqlite3StrAccumInit(&txt, 0, 0, SQLITE_MAX_LENGTH);
+ txt.db = db;
+ sqlite3StrAccumAppend(&txt, " (", 2);
+ for(i=0; i<nEq; i++){
+ explainAppendTerm(&txt, i, aCol[aiColumn[i]].zName, "=");
+ }
+
+ j = i;
+ if( pPlan->wsFlags&WHERE_BTM_LIMIT ){
+ explainAppendTerm(&txt, i++, aCol[aiColumn[j]].zName, ">");
+ }
+ if( pPlan->wsFlags&WHERE_TOP_LIMIT ){
+ explainAppendTerm(&txt, i, aCol[aiColumn[j]].zName, "<");
+ }
+ sqlite3StrAccumAppend(&txt, ")", 1);
+ return sqlite3StrAccumFinish(&txt);
+}
+
+/*
+** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
+** command. If the query being compiled is an EXPLAIN QUERY PLAN, a single
+** record is added to the output to describe the table scan strategy in
+** pLevel.
+*/
+static void explainOneScan(
+ Parse *pParse, /* Parse context */
+ SrcList *pTabList, /* Table list this loop refers to */
+ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
+ int iLevel, /* Value for "level" column of output */
+ int iFrom, /* Value for "from" column of output */
+ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
+){
+ if( pParse->explain==2 ){
+ u32 flags = pLevel->plan.wsFlags;
+ struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
+ Vdbe *v = pParse->pVdbe; /* VM being constructed */
+ sqlite3 *db = pParse->db; /* Database handle */
+ char *zMsg; /* Text to add to EQP output */
+ sqlite3_int64 nRow; /* Expected number of rows visited by scan */
+ int iId = pParse->iSelectId; /* Select id (left-most output column) */
+ int isSearch; /* True for a SEARCH. False for SCAN. */
+
+ if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return;
+
+ isSearch = (pLevel->plan.nEq>0)
+ || (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0
+ || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX));
+
+ zMsg = sqlite3MPrintf(db, "%s", isSearch?"SEARCH":"SCAN");
+ if( pItem->pSelect ){
+ zMsg = sqlite3MAppendf(db, zMsg, "%s SUBQUERY %d", zMsg,pItem->iSelectId);
+ }else{
+ zMsg = sqlite3MAppendf(db, zMsg, "%s TABLE %s", zMsg, pItem->zName);
+ }
+
+ if( pItem->zAlias ){
+ zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias);
+ }
+ if( (flags & WHERE_INDEXED)!=0 ){
+ char *zWhere = explainIndexRange(db, pLevel, pItem->pTab);
+ zMsg = sqlite3MAppendf(db, zMsg, "%s USING %s%sINDEX%s%s%s", zMsg,
+ ((flags & WHERE_TEMP_INDEX)?"AUTOMATIC ":""),
+ ((flags & WHERE_IDX_ONLY)?"COVERING ":""),
+ ((flags & WHERE_TEMP_INDEX)?"":" "),
+ ((flags & WHERE_TEMP_INDEX)?"": pLevel->plan.u.pIdx->zName),
+ zWhere
+ );
+ sqlite3DbFree(db, zWhere);
+ }else if( flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
+ zMsg = sqlite3MAppendf(db, zMsg, "%s USING INTEGER PRIMARY KEY", zMsg);
+
+ if( flags&WHERE_ROWID_EQ ){
+ zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid=?)", zMsg);
+ }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){
+ zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>? AND rowid<?)", zMsg);
+ }else if( flags&WHERE_BTM_LIMIT ){
+ zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>?)", zMsg);
+ }else if( flags&WHERE_TOP_LIMIT ){
+ zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid<?)", zMsg);
+ }
+ }
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
+ sqlite3_index_info *pVtabIdx = pLevel->plan.u.pVtabIdx;
+ zMsg = sqlite3MAppendf(db, zMsg, "%s VIRTUAL TABLE INDEX %d:%s", zMsg,
+ pVtabIdx->idxNum, pVtabIdx->idxStr);
+ }
+#endif
+ if( wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX) ){
+ testcase( wctrlFlags & WHERE_ORDERBY_MIN );
+ nRow = 1;
+ }else{
+ nRow = (sqlite3_int64)pLevel->plan.nRow;
+ }
+ zMsg = sqlite3MAppendf(db, zMsg, "%s (~%lld rows)", zMsg, nRow);
+ sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC);
+ }
+}
+#else
+# define explainOneScan(u,v,w,x,y,z)
+#endif /* SQLITE_OMIT_EXPLAIN */
+
+
/*
** Generate code for the start of the iLevel-th loop in the WHERE clause
** implementation described by pWInfo.
@@ -97737,7 +99410,7 @@ static Bitmask codeOneLoopStart(
r1 = sqlite3GetTempReg(pParse);
testcase( pLevel->plan.wsFlags & WHERE_BTM_LIMIT );
testcase( pLevel->plan.wsFlags & WHERE_TOP_LIMIT );
- if( pLevel->plan.wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT) ){
+ if( (pLevel->plan.wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 ){
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, nEq, r1);
sqlite3VdbeAddOp2(v, OP_IsNull, r1, addrCont);
}
@@ -97871,6 +99544,9 @@ static Bitmask codeOneLoopStart(
WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE |
WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY);
if( pSubWInfo ){
+ explainOneScan(
+ pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
+ );
if( (wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
int r;
@@ -98266,6 +99942,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
memset(&bestPlan, 0, sizeof(bestPlan));
bestPlan.rCost = SQLITE_BIG_DBL;
+ WHERETRACE(("*** Begin search for loop %d ***\n", i));
/* Loop through the remaining entries in the FROM clause to find the
** next nested loop. The loop tests all FROM clause entries
@@ -98284,9 +99961,15 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
** other FROM clause terms that are notReady. If no notReady terms are
** used then the "optimal" query plan works.
**
+ ** Note that the WhereCost.nRow parameter for an optimal scan might
+ ** not be as small as it would be if the table really were the innermost
+ ** join. The nRow value can be reduced by WHERE clause constraints
+ ** that do not use indices. But this nRow reduction only happens if the
+ ** table really is the innermost join.
+ **
** The second loop iteration is only performed if no optimal scan
- ** strategies were found by the first loop. This 2nd iteration is used to
- ** search for the lowest cost scan overall.
+ ** strategies were found by the first iteration. This second iteration
+ ** is used to search for the lowest cost scan overall.
**
** Previous versions of SQLite performed only the second iteration -
** the next outermost loop was always that with the lowest overall
@@ -98299,14 +99982,14 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
**
** The best strategy is to iterate through table t1 first. However it
** is not possible to determine this with a simple greedy algorithm.
- ** However, since the cost of a linear scan through table t2 is the same
+ ** Since the cost of a linear scan through table t2 is the same
** as the cost of a linear scan through table t1, a simple greedy
** algorithm may choose to use t2 for the outer loop, which is a much
** costlier approach.
*/
nUnconstrained = 0;
notIndexed = 0;
- for(isOptimal=(iFrom<nTabList-1); isOptimal>=0; isOptimal--){
+ for(isOptimal=(iFrom<nTabList-1); isOptimal>=0 && bestJ<0; isOptimal--){
Bitmask mask; /* Mask of tables not yet ready */
for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){
int doNotReorder; /* True if this table should not be reordered */
@@ -98324,15 +100007,19 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0);
if( pTabItem->pIndex==0 ) nUnconstrained++;
+ WHERETRACE(("=== trying table %d with isOptimal=%d ===\n",
+ j, isOptimal));
assert( pTabItem->pTab );
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTabItem->pTab) ){
sqlite3_index_info **pp = &pWInfo->a[j].pIdxInfo;
- bestVirtualIndex(pParse, pWC, pTabItem, mask, pOrderBy, &sCost, pp);
+ bestVirtualIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy,
+ &sCost, pp);
}else
#endif
{
- bestBtreeIndex(pParse, pWC, pTabItem, mask, pOrderBy, &sCost);
+ bestBtreeIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy,
+ &sCost);
}
assert( isOptimal || (sCost.used&notReady)==0 );
@@ -98372,10 +100059,12 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
&& (nUnconstrained==0 || pTabItem->pIndex==0 /* (3) */
|| NEVER((sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
&& (bestJ<0 || sCost.rCost<bestPlan.rCost /* (4) */
- || (sCost.rCost<=bestPlan.rCost && sCost.nRow<bestPlan.nRow))
+ || (sCost.rCost<=bestPlan.rCost
+ && sCost.plan.nRow<bestPlan.plan.nRow))
){
- WHERETRACE(("... best so far with cost=%g and nRow=%g\n",
- sCost.rCost, sCost.nRow));
+ WHERETRACE(("=== table %d is best so far"
+ " with cost=%g and nRow=%g\n",
+ j, sCost.rCost, sCost.plan.nRow));
bestPlan = sCost;
bestJ = j;
}
@@ -98384,8 +100073,9 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
}
assert( bestJ>=0 );
assert( notReady & getMask(pMaskSet, pTabList->a[bestJ].iCursor) );
- WHERETRACE(("*** Optimizer selects table %d for loop %d\n", bestJ,
- pLevel-pWInfo->a));
+ WHERETRACE(("*** Optimizer selects table %d for loop %d"
+ " with cost=%g and nRow=%g\n",
+ bestJ, pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow));
if( (bestPlan.plan.wsFlags & WHERE_ORDERBY)!=0 ){
*ppOrderBy = 0;
}
@@ -98400,7 +100090,9 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
}
notReady &= ~getMask(pMaskSet, pTabList->a[bestJ].iCursor);
pLevel->iFrom = (u8)bestJ;
- if( bestPlan.nRow>=(double)1 ) pParse->nQueryLoop *= bestPlan.nRow;
+ if( bestPlan.plan.nRow>=(double)1 ){
+ pParse->nQueryLoop *= bestPlan.plan.nRow;
+ }
/* Check that if the table scanned by this loop iteration had an
** INDEXED BY clause attached to it, that the named index is being
@@ -98448,44 +100140,15 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
*/
sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
notReady = ~(Bitmask)0;
+ pWInfo->nRowOut = (double)1;
for(i=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
Table *pTab; /* Table to open */
int iDb; /* Index of database containing table/index */
-#ifndef SQLITE_OMIT_EXPLAIN
- if( pParse->explain==2 ){
- char *zMsg;
- struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
- zMsg = sqlite3MPrintf(db, "TABLE %s", pItem->zName);
- if( pItem->zAlias ){
- zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias);
- }
- if( (pLevel->plan.wsFlags & WHERE_TEMP_INDEX)!=0 ){
- zMsg = sqlite3MAppendf(db, zMsg, "%s WITH AUTOMATIC INDEX", zMsg);
- }else if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
- zMsg = sqlite3MAppendf(db, zMsg, "%s WITH INDEX %s",
- zMsg, pLevel->plan.u.pIdx->zName);
- }else if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){
- zMsg = sqlite3MAppendf(db, zMsg, "%s VIA MULTI-INDEX UNION", zMsg);
- }else if( pLevel->plan.wsFlags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
- zMsg = sqlite3MAppendf(db, zMsg, "%s USING PRIMARY KEY", zMsg);
- }
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- else if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){
- sqlite3_index_info *pVtabIdx = pLevel->plan.u.pVtabIdx;
- zMsg = sqlite3MAppendf(db, zMsg, "%s VIRTUAL TABLE INDEX %d:%s", zMsg,
- pVtabIdx->idxNum, pVtabIdx->idxStr);
- }
-#endif
- if( pLevel->plan.wsFlags & WHERE_ORDERBY ){
- zMsg = sqlite3MAppendf(db, zMsg, "%s ORDER BY", zMsg);
- }
- sqlite3VdbeAddOp4(v, OP_Explain, i, pLevel->iFrom, 0, zMsg, P4_DYNAMIC);
- }
-#endif /* SQLITE_OMIT_EXPLAIN */
pTabItem = &pTabList->a[pLevel->iFrom];
pTab = pTabItem->pTab;
pLevel->iTabCur = pTabItem->iCursor;
+ pWInfo->nRowOut *= pLevel->plan.nRow;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ){
/* Do nothing */
@@ -98541,8 +100204,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
*/
notReady = ~(Bitmask)0;
for(i=0; i<nTabList; i++){
+ pLevel = &pWInfo->a[i];
+ explainOneScan(pParse, pTabList, pLevel, i, pLevel->iFrom, wctrlFlags);
notReady = codeOneLoopStart(pWInfo, i, wctrlFlags, notReady);
- pWInfo->iContinue = pWInfo->a[i].addrCont;
+ pWInfo->iContinue = pLevel->addrCont;
}
#ifdef SQLITE_TEST /* For testing and debugging use only */
@@ -103368,15 +105033,33 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db);
/************** Continuing where we left off in main.c ***********************/
#endif
-/*
-** The version of the library
-*/
#ifndef SQLITE_AMALGAMATION
+/* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant
+** contains the text of SQLITE_VERSION macro.
+*/
SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;
#endif
+
+/* IMPLEMENTATION-OF: R-53536-42575 The sqlite3_libversion() function returns
+** a pointer to the to the sqlite3_version[] string constant.
+*/
SQLITE_API const char *sqlite3_libversion(void){ return sqlite3_version; }
+
+/* IMPLEMENTATION-OF: R-63124-39300 The sqlite3_sourceid() function returns a
+** pointer to a string constant whose value is the same as the
+** SQLITE_SOURCE_ID C preprocessor macro.
+*/
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
+
+/* IMPLEMENTATION-OF: R-35210-63508 The sqlite3_libversion_number() function
+** returns an integer equal to SQLITE_VERSION_NUMBER.
+*/
SQLITE_API int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
+
+/* IMPLEMENTATION-OF: R-54823-41343 The sqlite3_threadsafe() function returns
+** zero if and only if SQLite was compiled mutexing code omitted due to
+** the SQLITE_THREADSAFE compile-time option being set to 0.
+*/
SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }
#if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE)
@@ -103497,6 +105180,13 @@ SQLITE_API int sqlite3_initialize(void){
** sqlite3_initialize(). The recursive calls normally come through
** sqlite3_os_init() when it invokes sqlite3_vfs_register(), but other
** recursive calls might also be possible.
+ **
+ ** IMPLEMENTATION-OF: R-00140-37445 SQLite automatically serializes calls
+ ** to the xInit method, so the xInit method need not be threadsafe.
+ **
+ ** The following mutex is what serializes access to the appdef pcache xInit
+ ** methods. The sqlite3_pcache_methods.xInit() all is embedded in the
+ ** call to sqlite3PcacheInitialize().
*/
sqlite3_mutex_enter(sqlite3GlobalConfig.pInitMutex);
if( sqlite3GlobalConfig.isInit==0 && sqlite3GlobalConfig.inProgress==0 ){
@@ -103777,12 +105467,12 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
sz = 0;
pStart = 0;
}else if( pBuf==0 ){
- sz = ROUND8(sz);
+ sz = ROUNDDOWN8(sz); /* IMP: R-33038-09382 */
sqlite3BeginBenignMalloc();
- pStart = sqlite3Malloc( sz*cnt );
+ pStart = sqlite3Malloc( sz*cnt ); /* IMP: R-61949-35727 */
sqlite3EndBenignMalloc();
}else{
- sz = ROUNDDOWN8(sz);
+ sz = ROUNDDOWN8(sz); /* IMP: R-33038-09382 */
pStart = pBuf;
}
db->lookaside.pStart = pStart;
@@ -103825,14 +105515,14 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
va_start(ap, op);
switch( op ){
case SQLITE_DBCONFIG_LOOKASIDE: {
- void *pBuf = va_arg(ap, void*);
- int sz = va_arg(ap, int);
- int cnt = va_arg(ap, int);
+ void *pBuf = va_arg(ap, void*); /* IMP: R-21112-12275 */
+ int sz = va_arg(ap, int); /* IMP: R-47871-25994 */
+ int cnt = va_arg(ap, int); /* IMP: R-04460-53386 */
rc = setupLookaside(db, pBuf, sz, cnt);
break;
}
default: {
- rc = SQLITE_ERROR;
+ rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
break;
}
}
@@ -103938,10 +105628,27 @@ SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *db){
}
/*
+** Invoke the destructor function associated with FuncDef p, if any. Except,
+** if this is not the last copy of the function, do not invoke it. Multiple
+** copies of a single function are created when create_function() is called
+** with SQLITE_ANY as the encoding.
+*/
+static void functionDestroy(sqlite3 *db, FuncDef *p){
+ FuncDestructor *pDestructor = p->pDestructor;
+ if( pDestructor ){
+ pDestructor->nRef--;
+ if( pDestructor->nRef==0 ){
+ pDestructor->xDestroy(pDestructor->pUserData);
+ sqlite3DbFree(db, pDestructor);
+ }
+ }
+}
+
+/*
** Close an existing SQLite database
*/
SQLITE_API int sqlite3_close(sqlite3 *db){
- HashElem *i;
+ HashElem *i; /* Hash table iterator */
int j;
if( !db ){
@@ -104009,6 +105716,7 @@ SQLITE_API int sqlite3_close(sqlite3 *db){
for(p=db->aFunc.a[j]; p; p=pHash){
pHash = p->pHash;
while( p ){
+ functionDestroy(db, p);
pNext = p->pNext;
sqlite3DbFree(db, p);
p = pNext;
@@ -104115,7 +105823,7 @@ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){
/* SQLITE_INTERRUPT */ "interrupted",
/* SQLITE_IOERR */ "disk I/O error",
/* SQLITE_CORRUPT */ "database disk image is malformed",
- /* SQLITE_NOTFOUND */ 0,
+ /* SQLITE_NOTFOUND */ "unknown operation",
/* SQLITE_FULL */ "database or disk is full",
/* SQLITE_CANTOPEN */ "unable to open database file",
/* SQLITE_PROTOCOL */ "locking protocol",
@@ -104283,7 +105991,8 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
void *pUserData,
void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
- void (*xFinal)(sqlite3_context*)
+ void (*xFinal)(sqlite3_context*),
+ FuncDestructor *pDestructor
){
FuncDef *p;
int nName;
@@ -104311,10 +106020,10 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
}else if( enc==SQLITE_ANY ){
int rc;
rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8,
- pUserData, xFunc, xStep, xFinal);
+ pUserData, xFunc, xStep, xFinal, pDestructor);
if( rc==SQLITE_OK ){
rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE,
- pUserData, xFunc, xStep, xFinal);
+ pUserData, xFunc, xStep, xFinal, pDestructor);
}
if( rc!=SQLITE_OK ){
return rc;
@@ -104347,6 +106056,15 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
if( !p ){
return SQLITE_NOMEM;
}
+
+ /* If an older version of the function with a configured destructor is
+ ** being replaced invoke the destructor function here. */
+ functionDestroy(db, p);
+
+ if( pDestructor ){
+ pDestructor->nRef++;
+ }
+ p->pDestructor = pDestructor;
p->flags = 0;
p->xFunc = xFunc;
p->xStep = xStep;
@@ -104361,7 +106079,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
*/
SQLITE_API int sqlite3_create_function(
sqlite3 *db,
- const char *zFunctionName,
+ const char *zFunc,
int nArg,
int enc,
void *p,
@@ -104369,9 +106087,41 @@ SQLITE_API int sqlite3_create_function(
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
void (*xFinal)(sqlite3_context*)
){
- int rc;
+ return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xFunc, xStep,
+ xFinal, 0);
+}
+
+SQLITE_API int sqlite3_create_function_v2(
+ sqlite3 *db,
+ const char *zFunc,
+ int nArg,
+ int enc,
+ void *p,
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
+ void (*xStep)(sqlite3_context*,int,sqlite3_value **),
+ void (*xFinal)(sqlite3_context*),
+ void (*xDestroy)(void *)
+){
+ int rc = SQLITE_ERROR;
+ FuncDestructor *pArg = 0;
sqlite3_mutex_enter(db->mutex);
- rc = sqlite3CreateFunc(db, zFunctionName, nArg, enc, p, xFunc, xStep, xFinal);
+ if( xDestroy ){
+ pArg = (FuncDestructor *)sqlite3DbMallocZero(db, sizeof(FuncDestructor));
+ if( !pArg ){
+ xDestroy(p);
+ goto out;
+ }
+ pArg->xDestroy = xDestroy;
+ pArg->pUserData = p;
+ }
+ rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xFunc, xStep, xFinal, pArg);
+ if( pArg && pArg->nRef==0 ){
+ assert( rc!=SQLITE_OK );
+ xDestroy(p);
+ sqlite3DbFree(db, pArg);
+ }
+
+ out:
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
@@ -104393,7 +106143,7 @@ SQLITE_API int sqlite3_create_function16(
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE);
- rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal);
+ rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal,0);
sqlite3DbFree(db, zFunc8);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
@@ -104424,7 +106174,7 @@ SQLITE_API int sqlite3_overload_function(
sqlite3_mutex_enter(db->mutex);
if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){
sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
- 0, sqlite3InvalidFunction, 0, 0);
+ 0, sqlite3InvalidFunction, 0, 0, 0);
}
rc = sqlite3ApiExit(db, SQLITE_OK);
sqlite3_mutex_leave(db->mutex);
@@ -104562,7 +106312,10 @@ SQLITE_PRIVATE int sqlite3WalDefaultHook(
** configured by this function.
*/
SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
-#ifndef SQLITE_OMIT_WAL
+#ifdef SQLITE_OMIT_WAL
+ UNUSED_PARAMETER(db);
+ UNUSED_PARAMETER(nFrame);
+#else
if( nFrame>0 ){
sqlite3_wal_hook(db, sqlite3WalDefaultHook, SQLITE_INT_TO_PTR(nFrame));
}else{
@@ -104693,60 +106446,6 @@ SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3 *db){
}
/*
-** This routine is called to create a connection to a database BTree
-** driver. If zFilename is the name of a file, then that file is
-** opened and used. If zFilename is the magic name ":memory:" then
-** the database is stored in memory (and is thus forgotten as soon as
-** the connection is closed.) If zFilename is NULL then the database
-** is a "virtual" database for transient use only and is deleted as
-** soon as the connection is closed.
-**
-** A virtual database can be either a disk file (that is automatically
-** deleted when the file is closed) or it an be held entirely in memory.
-** The sqlite3TempInMemory() function is used to determine which.
-*/
-SQLITE_PRIVATE int sqlite3BtreeFactory(
- sqlite3 *db, /* Main database when opening aux otherwise 0 */
- const char *zFilename, /* Name of the file containing the BTree database */
- int omitJournal, /* if TRUE then do not journal this file */
- int nCache, /* How many pages in the page cache */
- int vfsFlags, /* Flags passed through to vfsOpen */
- Btree **ppBtree /* Pointer to new Btree object written here */
-){
- int btFlags = 0;
- int rc;
-
- assert( sqlite3_mutex_held(db->mutex) );
- assert( ppBtree != 0);
- if( omitJournal ){
- btFlags |= BTREE_OMIT_JOURNAL;
- }
- if( db->flags & SQLITE_NoReadlock ){
- btFlags |= BTREE_NO_READLOCK;
- }
-#ifndef SQLITE_OMIT_MEMORYDB
- if( zFilename==0 && sqlite3TempInMemory(db) ){
- zFilename = ":memory:";
- }
-#endif
-
- if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (zFilename==0 || *zFilename==0) ){
- vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB;
- }
- rc = sqlite3BtreeOpen(zFilename, (sqlite3 *)db, ppBtree, btFlags, vfsFlags);
-
- /* If the B-Tree was successfully opened, set the pager-cache size to the
- ** default value. Except, if the call to BtreeOpen() returned a handle
- ** open on an existing shared pager-cache, do not change the pager-cache
- ** size.
- */
- if( rc==SQLITE_OK && 0==sqlite3BtreeSchema(*ppBtree, 0, 0) ){
- sqlite3BtreeSetCacheSize(*ppBtree, nCache);
- }
- return rc;
-}
-
-/*
** Return UTF-8 encoded English language explanation of the most recent
** error.
*/
@@ -104910,13 +106609,12 @@ static int createCollation(
}
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 1);
- if( pColl ){
- pColl->xCmp = xCompare;
- pColl->pUser = pCtx;
- pColl->xDel = xDel;
- pColl->enc = (u8)(enc2 | (enc & SQLITE_UTF16_ALIGNED));
- pColl->type = collType;
- }
+ if( pColl==0 ) return SQLITE_NOMEM;
+ pColl->xCmp = xCompare;
+ pColl->pUser = pCtx;
+ pColl->xDel = xDel;
+ pColl->enc = (u8)(enc2 | (enc & SQLITE_UTF16_ALIGNED));
+ pColl->type = collType;
sqlite3Error(db, SQLITE_OK, 0);
return SQLITE_OK;
}
@@ -104988,17 +106686,39 @@ static const int aHardLimit[] = {
*/
SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
int oldLimit;
+
+
+ /* EVIDENCE-OF: R-30189-54097 For each limit category SQLITE_LIMIT_NAME
+ ** there is a hard upper bound set at compile-time by a C preprocessor
+ ** macro called SQLITE_MAX_NAME. (The "_LIMIT_" in the name is changed to
+ ** "_MAX_".)
+ */
+ assert( aHardLimit[SQLITE_LIMIT_LENGTH]==SQLITE_MAX_LENGTH );
+ assert( aHardLimit[SQLITE_LIMIT_SQL_LENGTH]==SQLITE_MAX_SQL_LENGTH );
+ assert( aHardLimit[SQLITE_LIMIT_COLUMN]==SQLITE_MAX_COLUMN );
+ assert( aHardLimit[SQLITE_LIMIT_EXPR_DEPTH]==SQLITE_MAX_EXPR_DEPTH );
+ assert( aHardLimit[SQLITE_LIMIT_COMPOUND_SELECT]==SQLITE_MAX_COMPOUND_SELECT);
+ assert( aHardLimit[SQLITE_LIMIT_VDBE_OP]==SQLITE_MAX_VDBE_OP );
+ assert( aHardLimit[SQLITE_LIMIT_FUNCTION_ARG]==SQLITE_MAX_FUNCTION_ARG );
+ assert( aHardLimit[SQLITE_LIMIT_ATTACHED]==SQLITE_MAX_ATTACHED );
+ assert( aHardLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]==
+ SQLITE_MAX_LIKE_PATTERN_LENGTH );
+ assert( aHardLimit[SQLITE_LIMIT_VARIABLE_NUMBER]==SQLITE_MAX_VARIABLE_NUMBER);
+ assert( aHardLimit[SQLITE_LIMIT_TRIGGER_DEPTH]==SQLITE_MAX_TRIGGER_DEPTH );
+ assert( SQLITE_LIMIT_TRIGGER_DEPTH==(SQLITE_N_LIMIT-1) );
+
+
if( limitId<0 || limitId>=SQLITE_N_LIMIT ){
return -1;
}
oldLimit = db->aLimit[limitId];
- if( newLimit>=0 ){
+ if( newLimit>=0 ){ /* IMP: R-52476-28732 */
if( newLimit>aHardLimit[limitId] ){
- newLimit = aHardLimit[limitId];
+ newLimit = aHardLimit[limitId]; /* IMP: R-51463-25634 */
}
db->aLimit[limitId] = newLimit;
}
- return oldLimit;
+ return oldLimit; /* IMP: R-53341-35419 */
}
/*
@@ -105022,6 +106742,24 @@ static int openDatabase(
if( rc ) return rc;
#endif
+ /* Only allow sensible combinations of bits in the flags argument.
+ ** Throw an error if any non-sense combination is used. If we
+ ** do not block illegal combinations here, it could trigger
+ ** assert() statements in deeper layers. Sensible combinations
+ ** are:
+ **
+ ** 1: SQLITE_OPEN_READONLY
+ ** 2: SQLITE_OPEN_READWRITE
+ ** 6: SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
+ */
+ assert( SQLITE_OPEN_READONLY == 0x01 );
+ assert( SQLITE_OPEN_READWRITE == 0x02 );
+ assert( SQLITE_OPEN_CREATE == 0x04 );
+ testcase( (1<<(flags&7))==0x02 ); /* READONLY */
+ testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
+ testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
+ if( ((1<<(flags&7)) & 0x46)==0 ) return SQLITE_MISUSE;
+
if( sqlite3GlobalConfig.bCoreMutex==0 ){
isThreadsafe = 0;
}else if( flags & SQLITE_OPEN_NOMUTEX ){
@@ -105055,7 +106793,8 @@ static int openDatabase(
SQLITE_OPEN_SUBJOURNAL |
SQLITE_OPEN_MASTER_JOURNAL |
SQLITE_OPEN_NOMUTEX |
- SQLITE_OPEN_FULLMUTEX
+ SQLITE_OPEN_FULLMUTEX |
+ SQLITE_OPEN_WAL
);
/* Allocate the sqlite data structure */
@@ -105090,6 +106829,9 @@ static int openDatabase(
#if SQLITE_DEFAULT_RECURSIVE_TRIGGERS
| SQLITE_RecTriggers
#endif
+#if defined(SQLITE_DEFAULT_FOREIGN_KEYS) && SQLITE_DEFAULT_FOREIGN_KEYS
+ | SQLITE_ForeignKeys
+#endif
;
sqlite3HashInit(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -105127,9 +106869,8 @@ static int openDatabase(
/* Open the backend database driver */
db->openFlags = flags;
- rc = sqlite3BtreeFactory(db, zFilename, 0, SQLITE_DEFAULT_CACHE_SIZE,
- flags | SQLITE_OPEN_MAIN_DB,
- &db->aDb[0].pBt);
+ rc = sqlite3BtreeOpen(zFilename, db, &db->aDb[0].pBt, 0,
+ flags | SQLITE_OPEN_MAIN_DB);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_IOERR_NOMEM ){
rc = SQLITE_NOMEM;
@@ -105625,8 +107366,13 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo
assert( pPager!=0 );
fd = sqlite3PagerFile(pPager);
assert( fd!=0 );
- if( fd->pMethods ){
+ if( op==SQLITE_FCNTL_FILE_POINTER ){
+ *(sqlite3_file**)pArg = fd;
+ rc = SQLITE_OK;
+ }else if( fd->pMethods ){
rc = sqlite3OsFileControl(fd, op, pArg);
+ }else{
+ rc = SQLITE_NOTFOUND;
}
sqlite3BtreeLeave(pBtree);
}
@@ -105836,6 +107582,22 @@ SQLITE_API int sqlite3_test_control(int op, ...){
break;
}
+ /* sqlite3_test_control(SQLITE_TESTCTRL_SCRATCHMALLOC, sz, &pNew, pFree);
+ **
+ ** Pass pFree into sqlite3ScratchFree().
+ ** If sz>0 then allocate a scratch buffer into pNew.
+ */
+ case SQLITE_TESTCTRL_SCRATCHMALLOC: {
+ void *pFree, **ppNew;
+ int sz;
+ sz = va_arg(ap, int);
+ ppNew = va_arg(ap, void**);
+ pFree = va_arg(ap, void*);
+ if( sz ) *ppNew = sqlite3ScratchMalloc(sz);
+ sqlite3ScratchFree(pFree);
+ break;
+ }
+
}
va_end(ap);
#endif /* SQLITE_OMIT_BUILTIN_TEST */
@@ -106828,8 +108590,14 @@ SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const voi
** Macros indicating that conditional expressions are always true or
** false.
*/
+#ifdef SQLITE_COVERAGE_TEST
+# define ALWAYS(x) (1)
+# define NEVER(X) (0)
+#else
# define ALWAYS(x) (x)
# define NEVER(X) (x)
+#endif
+
/*
** Internal types used by SQLite.
*/
@@ -106847,8 +108615,12 @@ typedef struct Fts3Table Fts3Table;
typedef struct Fts3Cursor Fts3Cursor;
typedef struct Fts3Expr Fts3Expr;
typedef struct Fts3Phrase Fts3Phrase;
-typedef struct Fts3SegReader Fts3SegReader;
+typedef struct Fts3PhraseToken Fts3PhraseToken;
+
typedef struct Fts3SegFilter Fts3SegFilter;
+typedef struct Fts3DeferredToken Fts3DeferredToken;
+typedef struct Fts3SegReader Fts3SegReader;
+typedef struct Fts3SegReaderArray Fts3SegReaderArray;
/*
** A connection to a fulltext index is an instance of the following
@@ -106869,22 +108641,14 @@ struct Fts3Table {
/* Precompiled statements used by the implementation. Each of these
** statements is run and reset within a single virtual table API call.
*/
- sqlite3_stmt *aStmt[25];
-
- /* Pointer to string containing the SQL:
- **
- ** "SELECT block FROM %_segments WHERE blockid BETWEEN ? AND ?
- ** ORDER BY blockid"
- */
- char *zSelectLeaves;
- int nLeavesStmt; /* Valid statements in aLeavesStmt */
- int nLeavesTotal; /* Total number of prepared leaves stmts */
- int nLeavesAlloc; /* Allocated size of aLeavesStmt */
- sqlite3_stmt **aLeavesStmt; /* Array of prepared zSelectLeaves stmts */
+ sqlite3_stmt *aStmt[24];
int nNodeSize; /* Soft limit for node size */
- u8 bHasContent; /* True if %_content table exists */
+ u8 bHasStat; /* True if %_stat table exists */
u8 bHasDocsize; /* True if %_docsize table exists */
+ int nPgsz; /* Page size for host database */
+ char *zSegmentsTbl; /* Name of %_segments table */
+ sqlite3_blob *pSegments; /* Blob handle open on %_segments table */
/* The following hash table is used to buffer pending index updates during
** transactions. Variable nPendingData estimates the memory size of the
@@ -106911,14 +108675,25 @@ struct Fts3Cursor {
u8 isRequireSeek; /* True if must seek pStmt to %_content row */
sqlite3_stmt *pStmt; /* Prepared statement in use by the cursor */
Fts3Expr *pExpr; /* Parsed MATCH query string */
+ int nPhrase; /* Number of matchable phrases in query */
+ Fts3DeferredToken *pDeferred; /* Deferred search tokens, if any */
sqlite3_int64 iPrevId; /* Previous id read from aDoclist */
char *pNextId; /* Pointer into the body of aDoclist */
char *aDoclist; /* List of docids for full-text queries */
int nDoclist; /* Size of buffer at aDoclist */
+ int eEvalmode; /* An FTS3_EVAL_XX constant */
+ int nRowAvg; /* Average size of database rows, in pages */
+
int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */
u32 *aMatchinfo; /* Information about most recent match */
+ int nMatchinfo; /* Number of elements in aMatchinfo[] */
+ char *zMatchinfo; /* Matchinfo specification */
};
+#define FTS3_EVAL_FILTER 0
+#define FTS3_EVAL_NEXT 1
+#define FTS3_EVAL_MATCHINFO 2
+
/*
** The Fts3Cursor.eSearch member is always set to one of the following.
** Actualy, Fts3Cursor.eSearch can be greater than or equal to
@@ -106941,18 +108716,30 @@ struct Fts3Cursor {
/*
** A "phrase" is a sequence of one or more tokens that must match in
** sequence. A single token is the base case and the most common case.
-** For a sequence of tokens contained in "...", nToken will be the number
-** of tokens in the string.
-*/
+** For a sequence of tokens contained in double-quotes (i.e. "one two three")
+** nToken will be the number of tokens in the string.
+**
+** The nDocMatch and nMatch variables contain data that may be used by the
+** matchinfo() function. They are populated when the full-text index is
+** queried for hits on the phrase. If one or more tokens in the phrase
+** are deferred, the nDocMatch and nMatch variables are populated based
+** on the assumption that the
+*/
+struct Fts3PhraseToken {
+ char *z; /* Text of the token */
+ int n; /* Number of bytes in buffer z */
+ int isPrefix; /* True if token ends with a "*" character */
+ int bFulltext; /* True if full-text index was used */
+ Fts3SegReaderArray *pArray; /* Segment-reader for this token */
+ Fts3DeferredToken *pDeferred; /* Deferred token object for this token */
+};
+
struct Fts3Phrase {
+ /* Variables populated by fts3_expr.c when parsing a MATCH expression */
int nToken; /* Number of tokens in the phrase */
int iColumn; /* Index of column this phrase must match */
int isNot; /* Phrase prefixed by unary not (-) operator */
- struct PhraseToken {
- char *z; /* Text of the token */
- int n; /* Number of bytes in buffer pointed to by z */
- int isPrefix; /* True if token ends in with a "*" character */
- } aToken[1]; /* One entry for each token in the phrase */
+ Fts3PhraseToken aToken[1]; /* One entry for each token in the phrase */
};
/*
@@ -107002,28 +108789,34 @@ struct Fts3Expr {
#define FTSQUERY_PHRASE 5
-/* fts3_init.c */
-SQLITE_PRIVATE int sqlite3Fts3DeleteVtab(int, sqlite3_vtab *);
-SQLITE_PRIVATE int sqlite3Fts3InitVtab(int, sqlite3*, void*, int, const char*const*,
- sqlite3_vtab **, char **);
-
/* fts3_write.c */
SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*);
SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *);
SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *);
SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *);
-SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(Fts3Table *,int, sqlite3_int64,
+SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(int, sqlite3_int64,
sqlite3_int64, sqlite3_int64, const char *, int, Fts3SegReader**);
SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(Fts3Table*,const char*,int,int,Fts3SegReader**);
-SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3Table *, Fts3SegReader *);
+SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *);
SQLITE_PRIVATE int sqlite3Fts3SegReaderIterate(
Fts3Table *, Fts3SegReader **, int, Fts3SegFilter *,
int (*)(Fts3Table *, void *, char *, int, char *, int), void *
);
-SQLITE_PRIVATE int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char const**, int*);
+SQLITE_PRIVATE int sqlite3Fts3SegReaderCost(Fts3Cursor *, Fts3SegReader *, int *);
SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(Fts3Table*, sqlite3_stmt **);
-SQLITE_PRIVATE int sqlite3Fts3MatchinfoDocsizeLocal(Fts3Cursor*, u32*);
-SQLITE_PRIVATE int sqlite3Fts3MatchinfoDocsizeGlobal(Fts3Cursor*, u32*);
+SQLITE_PRIVATE int sqlite3Fts3ReadLock(Fts3Table *);
+SQLITE_PRIVATE int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char **, int*);
+
+SQLITE_PRIVATE int sqlite3Fts3SelectDoctotal(Fts3Table *, sqlite3_stmt **);
+SQLITE_PRIVATE int sqlite3Fts3SelectDocsize(Fts3Table *, sqlite3_int64, sqlite3_stmt **);
+
+SQLITE_PRIVATE void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *);
+SQLITE_PRIVATE int sqlite3Fts3DeferToken(Fts3Cursor *, Fts3PhraseToken *, int);
+SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *);
+SQLITE_PRIVATE void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *);
+SQLITE_PRIVATE char *sqlite3Fts3DeferredDoclist(Fts3DeferredToken *, int *);
+
+SQLITE_PRIVATE void sqlite3Fts3SegmentsClose(Fts3Table *);
/* Flags allowed as part of the 4th argument to SegmentReaderIterate() */
#define FTS3_SEGMENT_REQUIRE_POS 0x00000001
@@ -107047,22 +108840,24 @@ SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64);
SQLITE_PRIVATE void sqlite3Fts3Dequote(char *);
SQLITE_PRIVATE char *sqlite3Fts3FindPositions(Fts3Expr *, sqlite3_int64, int);
-SQLITE_PRIVATE int sqlite3Fts3ExprLoadDoclist(Fts3Table *, Fts3Expr *);
+SQLITE_PRIVATE int sqlite3Fts3ExprLoadDoclist(Fts3Cursor *, Fts3Expr *);
+SQLITE_PRIVATE int sqlite3Fts3ExprLoadFtDoclist(Fts3Cursor *, Fts3Expr *, char **, int *);
SQLITE_PRIVATE int sqlite3Fts3ExprNearTrim(Fts3Expr *, Fts3Expr *, int);
/* fts3_tokenizer.c */
SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *);
SQLITE_PRIVATE int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *);
-SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash,
- const char *, sqlite3_tokenizer **, const char **, char **
+SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *,
+ sqlite3_tokenizer **, char **
);
+SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char);
/* fts3_snippet.c */
SQLITE_PRIVATE void sqlite3Fts3Offsets(sqlite3_context*, Fts3Cursor*);
SQLITE_PRIVATE void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const char *,
const char *, const char *, int, int
);
-SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *);
+SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *);
/* fts3_expr.c */
SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *,
@@ -107211,16 +109006,13 @@ static int fts3DisconnectMethod(sqlite3_vtab *pVtab){
int i;
assert( p->nPendingData==0 );
+ assert( p->pSegments==0 );
/* Free any prepared statements held */
for(i=0; i<SizeofArray(p->aStmt); i++){
sqlite3_finalize(p->aStmt[i]);
}
- for(i=0; i<p->nLeavesStmt; i++){
- sqlite3_finalize(p->aLeavesStmt[i]);
- }
- sqlite3_free(p->zSelectLeaves);
- sqlite3_free(p->aLeavesStmt);
+ sqlite3_free(p->zSegmentsTbl);
/* Invoke the tokenizer destructor to free the tokenizer. */
p->pTokenizer->pModule->xDestroy(p->pTokenizer);
@@ -107231,7 +109023,7 @@ static int fts3DisconnectMethod(sqlite3_vtab *pVtab){
/*
** Construct one or more SQL statements from the format string given
-** and then evaluate those statements. The success code is writting
+** and then evaluate those statements. The success code is written
** into *pRc.
**
** If *pRc is initially non-zero then this routine is a no-op.
@@ -107283,33 +109075,38 @@ static int fts3DestroyMethod(sqlite3_vtab *pVtab){
** Invoke sqlite3_declare_vtab() to declare the schema for the FTS3 table
** passed as the first argument. This is done as part of the xConnect()
** and xCreate() methods.
+**
+** If *pRc is non-zero when this function is called, it is a no-op.
+** Otherwise, if an error occurs, an SQLite error code is stored in *pRc
+** before returning.
*/
-static int fts3DeclareVtab(Fts3Table *p){
- int i; /* Iterator variable */
- int rc; /* Return code */
- char *zSql; /* SQL statement passed to declare_vtab() */
- char *zCols; /* List of user defined columns */
+static void fts3DeclareVtab(int *pRc, Fts3Table *p){
+ if( *pRc==SQLITE_OK ){
+ int i; /* Iterator variable */
+ int rc; /* Return code */
+ char *zSql; /* SQL statement passed to declare_vtab() */
+ char *zCols; /* List of user defined columns */
- /* Create a list of user columns for the virtual table */
- zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]);
- for(i=1; zCols && i<p->nColumn; i++){
- zCols = sqlite3_mprintf("%z%Q, ", zCols, p->azColumn[i]);
- }
+ /* Create a list of user columns for the virtual table */
+ zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]);
+ for(i=1; zCols && i<p->nColumn; i++){
+ zCols = sqlite3_mprintf("%z%Q, ", zCols, p->azColumn[i]);
+ }
- /* Create the whole "CREATE TABLE" statement to pass to SQLite */
- zSql = sqlite3_mprintf(
- "CREATE TABLE x(%s %Q HIDDEN, docid HIDDEN)", zCols, p->zName
- );
+ /* Create the whole "CREATE TABLE" statement to pass to SQLite */
+ zSql = sqlite3_mprintf(
+ "CREATE TABLE x(%s %Q HIDDEN, docid HIDDEN)", zCols, p->zName
+ );
+ if( !zCols || !zSql ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_declare_vtab(p->db, zSql);
+ }
- if( !zCols || !zSql ){
- rc = SQLITE_NOMEM;
- }else{
- rc = sqlite3_declare_vtab(p->db, zSql);
+ sqlite3_free(zSql);
+ sqlite3_free(zCols);
+ *pRc = rc;
}
-
- sqlite3_free(zSql);
- sqlite3_free(zCols);
- return rc;
}
/*
@@ -107328,21 +109125,19 @@ static int fts3CreateTables(Fts3Table *p){
sqlite3 *db = p->db; /* The database connection */
/* Create a list of user columns for the content table */
- if( p->bHasContent ){
- zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY");
- for(i=0; zContentCols && i<p->nColumn; i++){
- char *z = p->azColumn[i];
- zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z);
- }
- if( zContentCols==0 ) rc = SQLITE_NOMEM;
-
- /* Create the content table */
- fts3DbExec(&rc, db,
- "CREATE TABLE %Q.'%q_content'(%s)",
- p->zDb, p->zName, zContentCols
- );
- sqlite3_free(zContentCols);
+ zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY");
+ for(i=0; zContentCols && i<p->nColumn; i++){
+ char *z = p->azColumn[i];
+ zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z);
}
+ if( zContentCols==0 ) rc = SQLITE_NOMEM;
+
+ /* Create the content table */
+ fts3DbExec(&rc, db,
+ "CREATE TABLE %Q.'%q_content'(%s)",
+ p->zDb, p->zName, zContentCols
+ );
+ sqlite3_free(zContentCols);
/* Create other tables */
fts3DbExec(&rc, db,
"CREATE TABLE %Q.'%q_segments'(blockid INTEGER PRIMARY KEY, block BLOB);",
@@ -107365,6 +109160,8 @@ static int fts3CreateTables(Fts3Table *p){
"CREATE TABLE %Q.'%q_docsize'(docid INTEGER PRIMARY KEY, size BLOB);",
p->zDb, p->zName
);
+ }
+ if( p->bHasStat ){
fts3DbExec(&rc, db,
"CREATE TABLE %Q.'%q_stat'(id INTEGER PRIMARY KEY, value BLOB);",
p->zDb, p->zName
@@ -107374,39 +109171,63 @@ static int fts3CreateTables(Fts3Table *p){
}
/*
-** An sqlite3_exec() callback for fts3TableExists.
+** Store the current database page-size in bytes in p->nPgsz.
+**
+** If *pRc is non-zero when this function is called, it is a no-op.
+** Otherwise, if an error occurs, an SQLite error code is stored in *pRc
+** before returning.
*/
-static int fts3TableExistsCallback(void *pArg, int n, char **pp1, char **pp2){
- UNUSED_PARAMETER(n);
- UNUSED_PARAMETER(pp1);
- UNUSED_PARAMETER(pp2);
- *(int*)pArg = 1;
- return 1;
+static void fts3DatabasePageSize(int *pRc, Fts3Table *p){
+ if( *pRc==SQLITE_OK ){
+ int rc; /* Return code */
+ char *zSql; /* SQL text "PRAGMA %Q.page_size" */
+ sqlite3_stmt *pStmt; /* Compiled "PRAGMA %Q.page_size" statement */
+
+ zSql = sqlite3_mprintf("PRAGMA %Q.page_size", p->zDb);
+ if( !zSql ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_step(pStmt);
+ p->nPgsz = sqlite3_column_int(pStmt, 0);
+ rc = sqlite3_finalize(pStmt);
+ }
+ }
+ assert( p->nPgsz>0 || rc!=SQLITE_OK );
+ sqlite3_free(zSql);
+ *pRc = rc;
+ }
}
/*
-** Determine if a table currently exists in the database.
+** "Special" FTS4 arguments are column specifications of the following form:
+**
+** <key> = <value>
+**
+** There may not be whitespace surrounding the "=" character. The <value>
+** term may be quoted, but the <key> may not.
*/
-static void fts3TableExists(
- int *pRc, /* Success code */
- sqlite3 *db, /* The database connection to test */
- const char *zDb, /* ATTACHed database within the connection */
- const char *zName, /* Name of the FTS3 table */
- const char *zSuffix, /* Shadow table extension */
- u8 *pResult /* Write results here */
+static int fts3IsSpecialColumn(
+ const char *z,
+ int *pnKey,
+ char **pzValue
){
- int rc = SQLITE_OK;
- int res = 0;
- char *zSql;
- if( *pRc ) return;
- zSql = sqlite3_mprintf(
- "SELECT 1 FROM %Q.sqlite_master WHERE name='%q%s'",
- zDb, zName, zSuffix
- );
- rc = sqlite3_exec(db, zSql, fts3TableExistsCallback, &res, 0);
- sqlite3_free(zSql);
- *pResult = (u8)(res & 0xff);
- if( rc!=SQLITE_ABORT ) *pRc = rc;
+ char *zValue;
+ const char *zCsr = z;
+
+ while( *zCsr!='=' ){
+ if( *zCsr=='\0' ) return 0;
+ zCsr++;
+ }
+
+ *pnKey = (int)(zCsr-z);
+ zValue = sqlite3_mprintf("%s", &zCsr[1]);
+ if( zValue ){
+ sqlite3Fts3Dequote(zValue);
+ }
+ *pzValue = zValue;
+ return 1;
}
/*
@@ -107430,8 +109251,8 @@ static int fts3InitVtab(
char **pzErr /* Write any error message here */
){
Fts3Hash *pHash = (Fts3Hash *)pAux;
- Fts3Table *p; /* Pointer to allocated vtab */
- int rc; /* Return code */
+ Fts3Table *p = 0; /* Pointer to allocated vtab */
+ int rc = SQLITE_OK; /* Return code */
int i; /* Iterator variable */
int nByte; /* Size of allocation used for *p */
int iCol; /* Column index */
@@ -107440,35 +109261,90 @@ static int fts3InitVtab(
char *zCsr; /* Space for holding column names */
int nDb; /* Bytes required to hold database name */
int nName; /* Bytes required to hold table name */
-
- const char *zTokenizer = 0; /* Name of tokenizer to use */
+ int isFts4 = (argv[0][3]=='4'); /* True for FTS4, false for FTS3 */
+ int bNoDocsize = 0; /* True to omit %_docsize table */
+ const char **aCol; /* Array of column names */
sqlite3_tokenizer *pTokenizer = 0; /* Tokenizer for this table */
+ assert( strlen(argv[0])==4 );
+ assert( (sqlite3_strnicmp(argv[0], "fts4", 4)==0 && isFts4)
+ || (sqlite3_strnicmp(argv[0], "fts3", 4)==0 && !isFts4)
+ );
+
nDb = (int)strlen(argv[1]) + 1;
nName = (int)strlen(argv[2]) + 1;
- for(i=3; i<argc; i++){
+
+ aCol = (const char **)sqlite3_malloc(sizeof(const char *) * (argc-2) );
+ if( !aCol ) return SQLITE_NOMEM;
+ memset((void *)aCol, 0, sizeof(const char *) * (argc-2));
+
+ /* Loop through all of the arguments passed by the user to the FTS3/4
+ ** module (i.e. all the column names and special arguments). This loop
+ ** does the following:
+ **
+ ** + Figures out the number of columns the FTSX table will have, and
+ ** the number of bytes of space that must be allocated to store copies
+ ** of the column names.
+ **
+ ** + If there is a tokenizer specification included in the arguments,
+ ** initializes the tokenizer pTokenizer.
+ */
+ for(i=3; rc==SQLITE_OK && i<argc; i++){
char const *z = argv[i];
- rc = sqlite3Fts3InitTokenizer(pHash, z, &pTokenizer, &zTokenizer, pzErr);
- if( rc!=SQLITE_OK ){
- return rc;
+ int nKey;
+ char *zVal;
+
+ /* Check if this is a tokenizer specification */
+ if( !pTokenizer
+ && strlen(z)>8
+ && 0==sqlite3_strnicmp(z, "tokenize", 8)
+ && 0==sqlite3Fts3IsIdChar(z[8])
+ ){
+ rc = sqlite3Fts3InitTokenizer(pHash, &z[9], &pTokenizer, pzErr);
}
- if( z!=zTokenizer ){
- nString += (int)(strlen(z) + 1);
+
+ /* Check if it is an FTS4 special argument. */
+ else if( isFts4 && fts3IsSpecialColumn(z, &nKey, &zVal) ){
+ if( !zVal ){
+ rc = SQLITE_NOMEM;
+ goto fts3_init_out;
+ }
+ if( nKey==9 && 0==sqlite3_strnicmp(z, "matchinfo", 9) ){
+ if( strlen(zVal)==4 && 0==sqlite3_strnicmp(zVal, "fts3", 4) ){
+ bNoDocsize = 1;
+ }else{
+ *pzErr = sqlite3_mprintf("unrecognized matchinfo: %s", zVal);
+ rc = SQLITE_ERROR;
+ }
+ }else{
+ *pzErr = sqlite3_mprintf("unrecognized parameter: %s", z);
+ rc = SQLITE_ERROR;
+ }
+ sqlite3_free(zVal);
}
- }
- nCol = argc - 3 - (zTokenizer!=0);
- if( zTokenizer==0 ){
- rc = sqlite3Fts3InitTokenizer(pHash, 0, &pTokenizer, 0, pzErr);
- if( rc!=SQLITE_OK ){
- return rc;
+
+ /* Otherwise, the argument is a column name. */
+ else {
+ nString += (int)(strlen(z) + 1);
+ aCol[nCol++] = z;
}
- assert( pTokenizer );
}
+ if( rc!=SQLITE_OK ) goto fts3_init_out;
if( nCol==0 ){
+ assert( nString==0 );
+ aCol[0] = "content";
+ nString = 8;
nCol = 1;
}
+ if( pTokenizer==0 ){
+ rc = sqlite3Fts3InitTokenizer(pHash, "simple", &pTokenizer, pzErr);
+ if( rc!=SQLITE_OK ) goto fts3_init_out;
+ }
+ assert( pTokenizer );
+
+
/* Allocate and populate the Fts3Table structure. */
nByte = sizeof(Fts3Table) + /* Fts3Table */
nCol * sizeof(char *) + /* azColumn */
@@ -107481,7 +109357,6 @@ static int fts3InitVtab(
goto fts3_init_out;
}
memset(p, 0, nByte);
-
p->db = db;
p->nColumn = nCol;
p->nPendingData = 0;
@@ -107489,11 +109364,12 @@ static int fts3InitVtab(
p->pTokenizer = pTokenizer;
p->nNodeSize = 1000;
p->nMaxPendingData = FTS3_MAX_PENDING_DATA;
- zCsr = (char *)&p->azColumn[nCol];
-
+ p->bHasDocsize = (isFts4 && bNoDocsize==0);
+ p->bHasStat = isFts4;
fts3HashInit(&p->pendingTerms, FTS3_HASH_STRING, 1);
/* Fill in the zName and zDb fields of the vtab structure. */
+ zCsr = (char *)&p->azColumn[nCol];
p->zName = zCsr;
memcpy(zCsr, argv[2], nName);
zCsr += nName;
@@ -107502,52 +109378,45 @@ static int fts3InitVtab(
zCsr += nDb;
/* Fill in the azColumn array */
- iCol = 0;
- for(i=3; i<argc; i++){
- if( argv[i]!=zTokenizer ){
- char *z;
- int n;
- z = (char *)sqlite3Fts3NextToken(argv[i], &n);
- memcpy(zCsr, z, n);
- zCsr[n] = '\0';
- sqlite3Fts3Dequote(zCsr);
- p->azColumn[iCol++] = zCsr;
- zCsr += n+1;
- assert( zCsr <= &((char *)p)[nByte] );
- }
- }
- if( iCol==0 ){
- assert( nCol==1 );
- p->azColumn[0] = "content";
+ for(iCol=0; iCol<nCol; iCol++){
+ char *z;
+ int n;
+ z = (char *)sqlite3Fts3NextToken(aCol[iCol], &n);
+ memcpy(zCsr, z, n);
+ zCsr[n] = '\0';
+ sqlite3Fts3Dequote(zCsr);
+ p->azColumn[iCol] = zCsr;
+ zCsr += n+1;
+ assert( zCsr <= &((char *)p)[nByte] );
}
/* If this is an xCreate call, create the underlying tables in the
** database. TODO: For xConnect(), it could verify that said tables exist.
*/
if( isCreate ){
- p->bHasContent = 1;
- p->bHasDocsize = argv[0][3]=='4';
rc = fts3CreateTables(p);
- }else{
- rc = SQLITE_OK;
- fts3TableExists(&rc, db, argv[1], argv[2], "_content", &p->bHasContent);
- fts3TableExists(&rc, db, argv[1], argv[2], "_docsize", &p->bHasDocsize);
}
- if( rc!=SQLITE_OK ) goto fts3_init_out;
- rc = fts3DeclareVtab(p);
- if( rc!=SQLITE_OK ) goto fts3_init_out;
+ /* Figure out the page-size for the database. This is required in order to
+ ** estimate the cost of loading large doclists from the database (see
+ ** function sqlite3Fts3SegReaderCost() for details).
+ */
+ fts3DatabasePageSize(&rc, p);
- *ppVTab = &p->base;
+ /* Declare the table schema to SQLite. */
+ fts3DeclareVtab(&rc, p);
fts3_init_out:
- assert( p || (pTokenizer && rc!=SQLITE_OK) );
+
+ sqlite3_free((void *)aCol);
if( rc!=SQLITE_OK ){
if( p ){
fts3DisconnectMethod((sqlite3_vtab *)p);
- }else{
+ }else if( pTokenizer ){
pTokenizer->pModule->xDestroy(pTokenizer);
}
+ }else{
+ *ppVTab = &p->base;
}
return rc;
}
@@ -107659,10 +109528,12 @@ static int fts3OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
** Close the cursor. For additional information see the documentation
** on the xClose method of the virtual table interface.
*/
-static int fulltextClose(sqlite3_vtab_cursor *pCursor){
+static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){
Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
+ assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
sqlite3_finalize(pCsr->pStmt);
sqlite3Fts3ExprFree(pCsr->pExpr);
+ sqlite3Fts3FreeDeferredTokens(pCsr);
sqlite3_free(pCsr->aDoclist);
sqlite3_free(pCsr->aMatchinfo);
sqlite3_free(pCsr);
@@ -107701,50 +109572,137 @@ static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
}
/*
-** Advance the cursor to the next row in the %_content table that
-** matches the search criteria. For a MATCH search, this will be
-** the next row that matches. For a full-table scan, this will be
-** simply the next row in the %_content table. For a docid lookup,
-** this routine simply sets the EOF flag.
+** This function is used to process a single interior node when searching
+** a b-tree for a term or term prefix. The node data is passed to this
+** function via the zNode/nNode parameters. The term to search for is
+** passed in zTerm/nTerm.
**
-** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned
-** even if we reach end-of-file. The fts3EofMethod() will be called
-** subsequently to determine whether or not an EOF was hit.
+** If piFirst is not NULL, then this function sets *piFirst to the blockid
+** of the child node that heads the sub-tree that may contain the term.
+**
+** If piLast is not NULL, then *piLast is set to the right-most child node
+** that heads a sub-tree that may contain a term for which zTerm/nTerm is
+** a prefix.
+**
+** If an OOM error occurs, SQLITE_NOMEM is returned. Otherwise, SQLITE_OK.
*/
-static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
+static int fts3ScanInteriorNode(
+ const char *zTerm, /* Term to select leaves for */
+ int nTerm, /* Size of term zTerm in bytes */
+ const char *zNode, /* Buffer containing segment interior node */
+ int nNode, /* Size of buffer at zNode */
+ sqlite3_int64 *piFirst, /* OUT: Selected child node */
+ sqlite3_int64 *piLast /* OUT: Selected child node */
+){
int rc = SQLITE_OK; /* Return code */
- Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
+ const char *zCsr = zNode; /* Cursor to iterate through node */
+ const char *zEnd = &zCsr[nNode];/* End of interior node buffer */
+ char *zBuffer = 0; /* Buffer to load terms into */
+ int nAlloc = 0; /* Size of allocated buffer */
+ int isFirstTerm = 1; /* True when processing first term on page */
+ sqlite3_int64 iChild; /* Block id of child node to descend to */
- if( pCsr->aDoclist==0 ){
- if( SQLITE_ROW!=sqlite3_step(pCsr->pStmt) ){
- pCsr->isEof = 1;
- rc = sqlite3_reset(pCsr->pStmt);
- }
- }else if( pCsr->pNextId>=&pCsr->aDoclist[pCsr->nDoclist] ){
- pCsr->isEof = 1;
- }else{
- sqlite3_reset(pCsr->pStmt);
- fts3GetDeltaVarint(&pCsr->pNextId, &pCsr->iPrevId);
- pCsr->isRequireSeek = 1;
- pCsr->isMatchinfoNeeded = 1;
+ /* Skip over the 'height' varint that occurs at the start of every
+ ** interior node. Then load the blockid of the left-child of the b-tree
+ ** node into variable iChild.
+ **
+ ** Even if the data structure on disk is corrupted, this (reading two
+ ** varints from the buffer) does not risk an overread. If zNode is a
+ ** root node, then the buffer comes from a SELECT statement. SQLite does
+ ** not make this guarantee explicitly, but in practice there are always
+ ** either more than 20 bytes of allocated space following the nNode bytes of
+ ** contents, or two zero bytes. Or, if the node is read from the %_segments
+ ** table, then there are always 20 bytes of zeroed padding following the
+ ** nNode bytes of content (see sqlite3Fts3ReadBlock() for details).
+ */
+ zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
+ zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
+ if( zCsr>zEnd ){
+ return SQLITE_CORRUPT;
}
+
+ while( zCsr<zEnd && (piFirst || piLast) ){
+ int cmp; /* memcmp() result */
+ int nSuffix; /* Size of term suffix */
+ int nPrefix = 0; /* Size of term prefix */
+ int nBuffer; /* Total term size */
+
+ /* Load the next term on the node into zBuffer. Use realloc() to expand
+ ** the size of zBuffer if required. */
+ if( !isFirstTerm ){
+ zCsr += sqlite3Fts3GetVarint32(zCsr, &nPrefix);
+ }
+ isFirstTerm = 0;
+ zCsr += sqlite3Fts3GetVarint32(zCsr, &nSuffix);
+
+ if( nPrefix<0 || nSuffix<0 || &zCsr[nSuffix]>zEnd ){
+ rc = SQLITE_CORRUPT;
+ goto finish_scan;
+ }
+ if( nPrefix+nSuffix>nAlloc ){
+ char *zNew;
+ nAlloc = (nPrefix+nSuffix) * 2;
+ zNew = (char *)sqlite3_realloc(zBuffer, nAlloc);
+ if( !zNew ){
+ rc = SQLITE_NOMEM;
+ goto finish_scan;
+ }
+ zBuffer = zNew;
+ }
+ memcpy(&zBuffer[nPrefix], zCsr, nSuffix);
+ nBuffer = nPrefix + nSuffix;
+ zCsr += nSuffix;
+
+ /* Compare the term we are searching for with the term just loaded from
+ ** the interior node. If the specified term is greater than or equal
+ ** to the term from the interior node, then all terms on the sub-tree
+ ** headed by node iChild are smaller than zTerm. No need to search
+ ** iChild.
+ **
+ ** If the interior node term is larger than the specified term, then
+ ** the tree headed by iChild may contain the specified term.
+ */
+ cmp = memcmp(zTerm, zBuffer, (nBuffer>nTerm ? nTerm : nBuffer));
+ if( piFirst && (cmp<0 || (cmp==0 && nBuffer>nTerm)) ){
+ *piFirst = iChild;
+ piFirst = 0;
+ }
+
+ if( piLast && cmp<0 ){
+ *piLast = iChild;
+ piLast = 0;
+ }
+
+ iChild++;
+ };
+
+ if( piFirst ) *piFirst = iChild;
+ if( piLast ) *piLast = iChild;
+
+ finish_scan:
+ sqlite3_free(zBuffer);
return rc;
}
/*
-** The buffer pointed to by argument zNode (size nNode bytes) contains the
-** root node of a b-tree segment. The segment is guaranteed to be at least
-** one level high (i.e. the root node is not also a leaf). If successful,
-** this function locates the leaf node of the segment that may contain the
-** term specified by arguments zTerm and nTerm and writes its block number
-** to *piLeaf.
+** The buffer pointed to by argument zNode (size nNode bytes) contains an
+** interior node of a b-tree segment. The zTerm buffer (size nTerm bytes)
+** contains a term. This function searches the sub-tree headed by the zNode
+** node for the range of leaf nodes that may contain the specified term
+** or terms for which the specified term is a prefix.
+**
+** If piLeaf is not NULL, then *piLeaf is set to the blockid of the
+** left-most leaf node in the tree that may contain the specified term.
+** If piLeaf2 is not NULL, then *piLeaf2 is set to the blockid of the
+** right-most leaf node that may contain a term for which the specified
+** term is a prefix.
**
-** It is possible that the returned leaf node does not contain the specified
-** term. However, if the segment does contain said term, it is stored on
-** the identified leaf node. Because this function only inspects interior
-** segment nodes (and never loads leaf nodes into memory), it is not possible
-** to be sure.
+** It is possible that the range of returned leaf nodes does not contain
+** the specified term or any terms for which it is a prefix. However, if the
+** segment does contain any such terms, they are stored within the identified
+** range. Because this function only inspects interior segment nodes (and
+** never loads leaf nodes into memory), it is not possible to be sure.
**
** If an error occurs, an error code other than SQLITE_OK is returned.
*/
@@ -107754,77 +109712,41 @@ static int fts3SelectLeaf(
int nTerm, /* Size of term zTerm in bytes */
const char *zNode, /* Buffer containing segment interior node */
int nNode, /* Size of buffer at zNode */
- sqlite3_int64 *piLeaf /* Selected leaf node */
+ sqlite3_int64 *piLeaf, /* Selected leaf node */
+ sqlite3_int64 *piLeaf2 /* Selected leaf node */
){
- int rc = SQLITE_OK; /* Return code */
- const char *zCsr = zNode; /* Cursor to iterate through node */
- const char *zEnd = &zCsr[nNode];/* End of interior node buffer */
- char *zBuffer = 0; /* Buffer to load terms into */
- int nAlloc = 0; /* Size of allocated buffer */
+ int rc; /* Return code */
+ int iHeight; /* Height of this node in tree */
- while( 1 ){
- int isFirstTerm = 1; /* True when processing first term on page */
- int iHeight; /* Height of this node in tree */
- sqlite3_int64 iChild; /* Block id of child node to descend to */
- int nBlock; /* Size of child node in bytes */
+ assert( piLeaf || piLeaf2 );
- zCsr += sqlite3Fts3GetVarint32(zCsr, &iHeight);
- zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
-
- while( zCsr<zEnd ){
- int cmp; /* memcmp() result */
- int nSuffix; /* Size of term suffix */
- int nPrefix = 0; /* Size of term prefix */
- int nBuffer; /* Total term size */
-
- /* Load the next term on the node into zBuffer */
- if( !isFirstTerm ){
- zCsr += sqlite3Fts3GetVarint32(zCsr, &nPrefix);
- }
- isFirstTerm = 0;
- zCsr += sqlite3Fts3GetVarint32(zCsr, &nSuffix);
- if( nPrefix+nSuffix>nAlloc ){
- char *zNew;
- nAlloc = (nPrefix+nSuffix) * 2;
- zNew = (char *)sqlite3_realloc(zBuffer, nAlloc);
- if( !zNew ){
- sqlite3_free(zBuffer);
- return SQLITE_NOMEM;
- }
- zBuffer = zNew;
- }
- memcpy(&zBuffer[nPrefix], zCsr, nSuffix);
- nBuffer = nPrefix + nSuffix;
- zCsr += nSuffix;
-
- /* Compare the term we are searching for with the term just loaded from
- ** the interior node. If the specified term is greater than or equal
- ** to the term from the interior node, then all terms on the sub-tree
- ** headed by node iChild are smaller than zTerm. No need to search
- ** iChild.
- **
- ** If the interior node term is larger than the specified term, then
- ** the tree headed by iChild may contain the specified term.
- */
- cmp = memcmp(zTerm, zBuffer, (nBuffer>nTerm ? nTerm : nBuffer));
- if( cmp<0 || (cmp==0 && nBuffer>nTerm) ) break;
- iChild++;
- };
+ sqlite3Fts3GetVarint32(zNode, &iHeight);
+ rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2);
+ assert( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );
- /* If (iHeight==1), the children of this interior node are leaves. The
- ** specified term may be present on leaf node iChild.
- */
- if( iHeight==1 ){
- *piLeaf = iChild;
- break;
+ if( rc==SQLITE_OK && iHeight>1 ){
+ char *zBlob = 0; /* Blob read from %_segments table */
+ int nBlob; /* Size of zBlob in bytes */
+
+ if( piLeaf && piLeaf2 && (*piLeaf!=*piLeaf2) ){
+ rc = sqlite3Fts3ReadBlock(p, *piLeaf, &zBlob, &nBlob);
+ if( rc==SQLITE_OK ){
+ rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, 0);
+ }
+ sqlite3_free(zBlob);
+ piLeaf = 0;
+ zBlob = 0;
}
- /* Descend to interior node iChild. */
- rc = sqlite3Fts3ReadBlock(p, iChild, &zCsr, &nBlock);
- if( rc!=SQLITE_OK ) break;
- zEnd = &zCsr[nBlock];
+ if( rc==SQLITE_OK ){
+ rc = sqlite3Fts3ReadBlock(p, piLeaf ? *piLeaf : *piLeaf2, &zBlob, &nBlob);
+ }
+ if( rc==SQLITE_OK ){
+ rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, piLeaf2);
+ }
+ sqlite3_free(zBlob);
}
- sqlite3_free(zBuffer);
+
return rc;
}
@@ -108056,20 +109978,44 @@ static void fts3PoslistMerge(
/*
** nToken==1 searches for adjacent positions.
+**
+** This function is used to merge two position lists into one. When it is
+** called, *pp1 and *pp2 must both point to position lists. A position-list is
+** the part of a doclist that follows each document id. For example, if a row
+** contains:
+**
+** 'a b c'|'x y z'|'a b b a'
+**
+** Then the position list for this row for token 'b' would consist of:
+**
+** 0x02 0x01 0x02 0x03 0x03 0x00
+**
+** When this function returns, both *pp1 and *pp2 are left pointing to the
+** byte following the 0x00 terminator of their respective position lists.
+**
+** If isSaveLeft is 0, an entry is added to the output position list for
+** each position in *pp2 for which there exists one or more positions in
+** *pp1 so that (pos(*pp2)>pos(*pp1) && pos(*pp2)-pos(*pp1)<=nToken). i.e.
+** when the *pp1 token appears before the *pp2 token, but not more than nToken
+** slots before it.
*/
static int fts3PoslistPhraseMerge(
- char **pp, /* Output buffer */
+ char **pp, /* IN/OUT: Preallocated output buffer */
int nToken, /* Maximum difference in token positions */
int isSaveLeft, /* Save the left position */
- char **pp1, /* Left input list */
- char **pp2 /* Right input list */
+ int isExact, /* If *pp1 is exactly nTokens before *pp2 */
+ char **pp1, /* IN/OUT: Left input list */
+ char **pp2 /* IN/OUT: Right input list */
){
char *p = (pp ? *pp : 0);
char *p1 = *pp1;
char *p2 = *pp2;
-
int iCol1 = 0;
int iCol2 = 0;
+
+ /* Never set both isSaveLeft and isExact for the same invocation. */
+ assert( isSaveLeft==0 || isExact==0 );
+
assert( *p1!=0 && *p2!=0 );
if( *p1==POS_COLUMN ){
p1++;
@@ -108098,7 +110044,9 @@ static int fts3PoslistPhraseMerge(
fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2;
while( 1 ){
- if( iPos2>iPos1 && iPos2<=iPos1+nToken ){
+ if( iPos2==iPos1+nToken
+ || (isExact==0 && iPos2>iPos1 && iPos2<=iPos1+nToken)
+ ){
sqlite3_int64 iSave;
if( !pp ){
fts3PoslistCopy(0, &p2);
@@ -108181,21 +110129,21 @@ static int fts3PoslistNearMerge(
char *p2 = *pp2;
if( !pp ){
- if( fts3PoslistPhraseMerge(0, nRight, 0, pp1, pp2) ) return 1;
+ if( fts3PoslistPhraseMerge(0, nRight, 0, 0, pp1, pp2) ) return 1;
*pp1 = p1;
*pp2 = p2;
- return fts3PoslistPhraseMerge(0, nLeft, 0, pp2, pp1);
+ return fts3PoslistPhraseMerge(0, nLeft, 0, 0, pp2, pp1);
}else{
char *pTmp1 = aTmp;
char *pTmp2;
char *aTmp2;
int res = 1;
- fts3PoslistPhraseMerge(&pTmp1, nRight, 0, pp1, pp2);
+ fts3PoslistPhraseMerge(&pTmp1, nRight, 0, 0, pp1, pp2);
aTmp2 = pTmp2 = pTmp1;
*pp1 = p1;
*pp2 = p2;
- fts3PoslistPhraseMerge(&pTmp2, nLeft, 1, pp2, pp1);
+ fts3PoslistPhraseMerge(&pTmp2, nLeft, 1, 0, pp2, pp1);
if( pTmp1!=aTmp && pTmp2!=aTmp2 ){
fts3PoslistMerge(pp, &aTmp, &aTmp2);
}else if( pTmp1!=aTmp ){
@@ -108241,7 +110189,8 @@ static int fts3DoclistMerge(
char *a1, /* Buffer containing first doclist */
int n1, /* Size of buffer a1 */
char *a2, /* Buffer containing second doclist */
- int n2 /* Size of buffer a2 */
+ int n2, /* Size of buffer a2 */
+ int *pnDoc /* OUT: Number of docids in output */
){
sqlite3_int64 i1 = 0;
sqlite3_int64 i2 = 0;
@@ -108252,6 +110201,7 @@ static int fts3DoclistMerge(
char *p2 = a2;
char *pEnd1 = &a1[n1];
char *pEnd2 = &a2[n2];
+ int nDoc = 0;
assert( mergetype==MERGE_OR || mergetype==MERGE_POS_OR
|| mergetype==MERGE_AND || mergetype==MERGE_NOT
@@ -108295,6 +110245,7 @@ static int fts3DoclistMerge(
fts3PutDeltaVarint(&p, &iPrev, i1);
fts3GetDeltaVarint2(&p1, pEnd1, &i1);
fts3GetDeltaVarint2(&p2, pEnd2, &i2);
+ nDoc++;
}else if( i1<i2 ){
fts3GetDeltaVarint2(&p1, pEnd1, &i1);
}else{
@@ -108325,9 +110276,11 @@ static int fts3DoclistMerge(
char *pSave = p;
sqlite3_int64 iPrevSave = iPrev;
fts3PutDeltaVarint(&p, &iPrev, i1);
- if( 0==fts3PoslistPhraseMerge(ppPos, 1, 0, &p1, &p2) ){
+ if( 0==fts3PoslistPhraseMerge(ppPos, nParam1, 0, 1, &p1, &p2) ){
p = pSave;
iPrev = iPrevSave;
+ }else{
+ nDoc++;
}
fts3GetDeltaVarint2(&p1, pEnd1, &i1);
fts3GetDeltaVarint2(&p2, pEnd2, &i2);
@@ -108380,6 +110333,7 @@ static int fts3DoclistMerge(
}
}
+ if( pnDoc ) *pnDoc = nDoc;
*pnBuffer = (int)(p-aBuffer);
return SQLITE_OK;
}
@@ -108418,7 +110372,7 @@ static int fts3TermSelectMerge(TermSelect *pTS){
if( !aOut ){
aOut = pTS->aaOutput[i];
nOut = pTS->anOutput[i];
- pTS->aaOutput[0] = 0;
+ pTS->aaOutput[i] = 0;
}else{
int nNew = nOut + pTS->anOutput[i];
char *aNew = sqlite3_malloc(nNew);
@@ -108427,7 +110381,7 @@ static int fts3TermSelectMerge(TermSelect *pTS){
return SQLITE_NOMEM;
}
fts3DoclistMerge(mergetype, 0, 0,
- aNew, &nNew, pTS->aaOutput[i], pTS->anOutput[i], aOut, nOut
+ aNew, &nNew, pTS->aaOutput[i], pTS->anOutput[i], aOut, nOut, 0
);
sqlite3_free(pTS->aaOutput[i]);
sqlite3_free(aOut);
@@ -108498,8 +110452,8 @@ static int fts3TermSelectCb(
}
return SQLITE_NOMEM;
}
- fts3DoclistMerge(mergetype, 0, 0,
- aNew, &nNew, pTS->aaOutput[iOut], pTS->anOutput[iOut], aMerge, nMerge
+ fts3DoclistMerge(mergetype, 0, 0, aNew, &nNew,
+ pTS->aaOutput[iOut], pTS->anOutput[iOut], aMerge, nMerge, 0
);
if( iOut>0 ) sqlite3_free(aMerge);
@@ -108517,43 +110471,106 @@ static int fts3TermSelectCb(
return SQLITE_OK;
}
+static int fts3DeferredTermSelect(
+ Fts3DeferredToken *pToken, /* Phrase token */
+ int isTermPos, /* True to include positions */
+ int *pnOut, /* OUT: Size of list */
+ char **ppOut /* OUT: Body of list */
+){
+ char *aSource;
+ int nSource;
+
+ aSource = sqlite3Fts3DeferredDoclist(pToken, &nSource);
+ if( !aSource ){
+ *pnOut = 0;
+ *ppOut = 0;
+ }else if( isTermPos ){
+ *ppOut = sqlite3_malloc(nSource);
+ if( !*ppOut ) return SQLITE_NOMEM;
+ memcpy(*ppOut, aSource, nSource);
+ *pnOut = nSource;
+ }else{
+ sqlite3_int64 docid;
+ *pnOut = sqlite3Fts3GetVarint(aSource, &docid);
+ *ppOut = sqlite3_malloc(*pnOut);
+ if( !*ppOut ) return SQLITE_NOMEM;
+ sqlite3Fts3PutVarint(*ppOut, docid);
+ }
+
+ return SQLITE_OK;
+}
+
/*
-** This function retreives the doclist for the specified term (or term
-** prefix) from the database.
-**
-** The returned doclist may be in one of two formats, depending on the
-** value of parameter isReqPos. If isReqPos is zero, then the doclist is
-** a sorted list of delta-compressed docids (a bare doclist). If isReqPos
-** is non-zero, then the returned list is in the same format as is stored
-** in the database without the found length specifier at the start of on-disk
-** doclists.
+** An Fts3SegReaderArray is used to store an array of Fts3SegReader objects.
+** Elements are added to the array using fts3SegReaderArrayAdd().
*/
-static int fts3TermSelect(
- Fts3Table *p, /* Virtual table handle */
- int iColumn, /* Column to query (or -ve for all columns) */
+struct Fts3SegReaderArray {
+ int nSegment; /* Number of valid entries in apSegment[] */
+ int nAlloc; /* Allocated size of apSegment[] */
+ int nCost; /* The cost of executing SegReaderIterate() */
+ Fts3SegReader *apSegment[1]; /* Array of seg-reader objects */
+};
+
+
+/*
+** Free an Fts3SegReaderArray object. Also free all seg-readers in the
+** array (using sqlite3Fts3SegReaderFree()).
+*/
+static void fts3SegReaderArrayFree(Fts3SegReaderArray *pArray){
+ if( pArray ){
+ int i;
+ for(i=0; i<pArray->nSegment; i++){
+ sqlite3Fts3SegReaderFree(pArray->apSegment[i]);
+ }
+ sqlite3_free(pArray);
+ }
+}
+
+static int fts3SegReaderArrayAdd(
+ Fts3SegReaderArray **ppArray,
+ Fts3SegReader *pNew
+){
+ Fts3SegReaderArray *pArray = *ppArray;
+
+ if( !pArray || pArray->nAlloc==pArray->nSegment ){
+ int nNew = (pArray ? pArray->nAlloc+16 : 16);
+ pArray = (Fts3SegReaderArray *)sqlite3_realloc(pArray,
+ sizeof(Fts3SegReaderArray) + (nNew-1) * sizeof(Fts3SegReader*)
+ );
+ if( !pArray ){
+ sqlite3Fts3SegReaderFree(pNew);
+ return SQLITE_NOMEM;
+ }
+ if( nNew==16 ){
+ pArray->nSegment = 0;
+ pArray->nCost = 0;
+ }
+ pArray->nAlloc = nNew;
+ *ppArray = pArray;
+ }
+
+ pArray->apSegment[pArray->nSegment++] = pNew;
+ return SQLITE_OK;
+}
+
+static int fts3TermSegReaderArray(
+ Fts3Cursor *pCsr, /* Virtual table cursor handle */
const char *zTerm, /* Term to query for */
int nTerm, /* Size of zTerm in bytes */
int isPrefix, /* True for a prefix search */
- int isReqPos, /* True to include position lists in output */
- int *pnOut, /* OUT: Size of buffer at *ppOut */
- char **ppOut /* OUT: Malloced result buffer */
+ Fts3SegReaderArray **ppArray /* OUT: Allocated seg-reader array */
){
- int i;
- TermSelect tsc;
- Fts3SegFilter filter; /* Segment term filter configuration */
- Fts3SegReader **apSegment; /* Array of segments to read data from */
- int nSegment = 0; /* Size of apSegment array */
- int nAlloc = 16; /* Allocated size of segment array */
+ Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
int rc; /* Return code */
+ Fts3SegReaderArray *pArray = 0; /* Array object to build */
+ Fts3SegReader *pReader = 0; /* Seg-reader to add to pArray */
sqlite3_stmt *pStmt = 0; /* SQL statement to scan %_segdir table */
int iAge = 0; /* Used to assign ages to segments */
- apSegment = (Fts3SegReader **)sqlite3_malloc(sizeof(Fts3SegReader*)*nAlloc);
- if( !apSegment ) return SQLITE_NOMEM;
- rc = sqlite3Fts3SegReaderPending(p, zTerm, nTerm, isPrefix, &apSegment[0]);
- if( rc!=SQLITE_OK ) goto finished;
- if( apSegment[0] ){
- nSegment = 1;
+ /* Allocate a seg-reader to scan the pending terms, if any. */
+ rc = sqlite3Fts3SegReaderPending(p, zTerm, nTerm, isPrefix, &pReader);
+ if( rc==SQLITE_OK && pReader ) {
+ rc = fts3SegReaderArrayAdd(&pArray, pReader);
}
/* Loop through the entire %_segdir table. For each segment, create a
@@ -108561,12 +110578,10 @@ static int fts3TermSelect(
** that may contain a term that matches zTerm/nTerm. For non-prefix
** searches, this is always a single leaf. For prefix searches, this
** may be a contiguous block of leaves.
- **
- ** The code in this loop does not actually load any leaves into memory
- ** (unless the root node happens to be a leaf). It simply examines the
- ** b-tree structure to determine which leaves need to be inspected.
*/
- rc = sqlite3Fts3AllSegdirs(p, &pStmt);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3Fts3AllSegdirs(p, &pStmt);
+ }
while( rc==SQLITE_OK && SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){
Fts3SegReader *pNew = 0;
int nRoot = sqlite3_column_bytes(pStmt, 4);
@@ -108576,66 +110591,79 @@ static int fts3TermSelect(
** leaf). Do not bother inspecting any data in this case, just
** create a Fts3SegReader to scan the single leaf.
*/
- rc = sqlite3Fts3SegReaderNew(p, iAge, 0, 0, 0, zRoot, nRoot, &pNew);
+ rc = sqlite3Fts3SegReaderNew(iAge, 0, 0, 0, zRoot, nRoot, &pNew);
}else{
- int rc2; /* Return value of sqlite3Fts3ReadBlock() */
- sqlite3_int64 i1; /* Blockid of leaf that may contain zTerm */
- rc = fts3SelectLeaf(p, zTerm, nTerm, zRoot, nRoot, &i1);
+ sqlite3_int64 i1; /* First leaf that may contain zTerm */
+ sqlite3_int64 i2; /* Final leaf that may contain zTerm */
+ rc = fts3SelectLeaf(p, zTerm, nTerm, zRoot, nRoot, &i1, (isPrefix?&i2:0));
+ if( isPrefix==0 ) i2 = i1;
if( rc==SQLITE_OK ){
- sqlite3_int64 i2 = sqlite3_column_int64(pStmt, 2);
- rc = sqlite3Fts3SegReaderNew(p, iAge, i1, i2, 0, 0, 0, &pNew);
+ rc = sqlite3Fts3SegReaderNew(iAge, i1, i2, 0, 0, 0, &pNew);
}
+ }
+ assert( (pNew==0)==(rc!=SQLITE_OK) );
- /* The following call to ReadBlock() serves to reset the SQL statement
- ** used to retrieve blocks of data from the %_segments table. If it is
- ** not reset here, then it may remain classified as an active statement
- ** by SQLite, which may lead to "DROP TABLE" or "DETACH" commands
- ** failing.
- */
- rc2 = sqlite3Fts3ReadBlock(p, 0, 0, 0);
- if( rc==SQLITE_OK ){
- rc = rc2;
- }
+ /* If a new Fts3SegReader was allocated, add it to the array. */
+ if( rc==SQLITE_OK ){
+ rc = fts3SegReaderArrayAdd(&pArray, pNew);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3Fts3SegReaderCost(pCsr, pNew, &pArray->nCost);
}
iAge++;
+ }
- /* If a new Fts3SegReader was allocated, add it to the apSegment array. */
- assert( pNew!=0 || rc!=SQLITE_OK );
- if( pNew ){
- if( nSegment==nAlloc ){
- Fts3SegReader **pArray;
- nAlloc += 16;
- pArray = (Fts3SegReader **)sqlite3_realloc(
- apSegment, nAlloc*sizeof(Fts3SegReader *)
- );
- if( !pArray ){
- sqlite3Fts3SegReaderFree(p, pNew);
- rc = SQLITE_NOMEM;
- goto finished;
- }
- apSegment = pArray;
- }
- apSegment[nSegment++] = pNew;
- }
+ if( rc==SQLITE_DONE ){
+ rc = sqlite3_reset(pStmt);
+ }else{
+ sqlite3_reset(pStmt);
}
- if( rc!=SQLITE_DONE ){
- assert( rc!=SQLITE_OK );
- goto finished;
+ if( rc!=SQLITE_OK ){
+ fts3SegReaderArrayFree(pArray);
+ pArray = 0;
}
+ *ppArray = pArray;
+ return rc;
+}
+/*
+** This function retreives the doclist for the specified term (or term
+** prefix) from the database.
+**
+** The returned doclist may be in one of two formats, depending on the
+** value of parameter isReqPos. If isReqPos is zero, then the doclist is
+** a sorted list of delta-compressed docids (a bare doclist). If isReqPos
+** is non-zero, then the returned list is in the same format as is stored
+** in the database without the found length specifier at the start of on-disk
+** doclists.
+*/
+static int fts3TermSelect(
+ Fts3Table *p, /* Virtual table handle */
+ Fts3PhraseToken *pTok, /* Token to query for */
+ int iColumn, /* Column to query (or -ve for all columns) */
+ int isReqPos, /* True to include position lists in output */
+ int *pnOut, /* OUT: Size of buffer at *ppOut */
+ char **ppOut /* OUT: Malloced result buffer */
+){
+ int rc; /* Return code */
+ Fts3SegReaderArray *pArray; /* Seg-reader array for this term */
+ TermSelect tsc; /* Context object for fts3TermSelectCb() */
+ Fts3SegFilter filter; /* Segment term filter configuration */
+
+ pArray = pTok->pArray;
memset(&tsc, 0, sizeof(TermSelect));
tsc.isReqPos = isReqPos;
filter.flags = FTS3_SEGMENT_IGNORE_EMPTY
- | (isPrefix ? FTS3_SEGMENT_PREFIX : 0)
+ | (pTok->isPrefix ? FTS3_SEGMENT_PREFIX : 0)
| (isReqPos ? FTS3_SEGMENT_REQUIRE_POS : 0)
| (iColumn<p->nColumn ? FTS3_SEGMENT_COLUMN_FILTER : 0);
filter.iCol = iColumn;
- filter.zTerm = zTerm;
- filter.nTerm = nTerm;
+ filter.zTerm = pTok->z;
+ filter.nTerm = pTok->n;
- rc = sqlite3Fts3SegReaderIterate(p, apSegment, nSegment, &filter,
- fts3TermSelectCb, (void *)&tsc
+ rc = sqlite3Fts3SegReaderIterate(p, pArray->apSegment, pArray->nSegment,
+ &filter, fts3TermSelectCb, (void *)&tsc
);
if( rc==SQLITE_OK ){
rc = fts3TermSelectMerge(&tsc);
@@ -108645,26 +110673,112 @@ static int fts3TermSelect(
*ppOut = tsc.aaOutput[0];
*pnOut = tsc.anOutput[0];
}else{
+ int i;
for(i=0; i<SizeofArray(tsc.aaOutput); i++){
sqlite3_free(tsc.aaOutput[i]);
}
}
-finished:
- sqlite3_reset(pStmt);
- for(i=0; i<nSegment; i++){
- sqlite3Fts3SegReaderFree(p, apSegment[i]);
+ fts3SegReaderArrayFree(pArray);
+ pTok->pArray = 0;
+ return rc;
+}
+
+/*
+** This function counts the total number of docids in the doclist stored
+** in buffer aList[], size nList bytes.
+**
+** If the isPoslist argument is true, then it is assumed that the doclist
+** contains a position-list following each docid. Otherwise, it is assumed
+** that the doclist is simply a list of docids stored as delta encoded
+** varints.
+*/
+static int fts3DoclistCountDocids(int isPoslist, char *aList, int nList){
+ int nDoc = 0; /* Return value */
+ if( aList ){
+ char *aEnd = &aList[nList]; /* Pointer to one byte after EOF */
+ char *p = aList; /* Cursor */
+ if( !isPoslist ){
+ /* The number of docids in the list is the same as the number of
+ ** varints. In FTS3 a varint consists of a single byte with the 0x80
+ ** bit cleared and zero or more bytes with the 0x80 bit set. So to
+ ** count the varints in the buffer, just count the number of bytes
+ ** with the 0x80 bit clear. */
+ while( p<aEnd ) nDoc += (((*p++)&0x80)==0);
+ }else{
+ while( p<aEnd ){
+ nDoc++;
+ while( (*p++)&0x80 ); /* Skip docid varint */
+ fts3PoslistCopy(0, &p); /* Skip over position list */
+ }
+ }
+ }
+
+ return nDoc;
+}
+
+/*
+** Call sqlite3Fts3DeferToken() for each token in the expression pExpr.
+*/
+static int fts3DeferExpression(Fts3Cursor *pCsr, Fts3Expr *pExpr){
+ int rc = SQLITE_OK;
+ if( pExpr ){
+ rc = fts3DeferExpression(pCsr, pExpr->pLeft);
+ if( rc==SQLITE_OK ){
+ rc = fts3DeferExpression(pCsr, pExpr->pRight);
+ }
+ if( pExpr->eType==FTSQUERY_PHRASE ){
+ int iCol = pExpr->pPhrase->iColumn;
+ int i;
+ for(i=0; rc==SQLITE_OK && i<pExpr->pPhrase->nToken; i++){
+ Fts3PhraseToken *pToken = &pExpr->pPhrase->aToken[i];
+ if( pToken->pDeferred==0 ){
+ rc = sqlite3Fts3DeferToken(pCsr, pToken, iCol);
+ }
+ }
+ }
}
- sqlite3_free(apSegment);
return rc;
}
+/*
+** This function removes the position information from a doclist. When
+** called, buffer aList (size *pnList bytes) contains a doclist that includes
+** position information. This function removes the position information so
+** that aList contains only docids, and adjusts *pnList to reflect the new
+** (possibly reduced) size of the doclist.
+*/
+static void fts3DoclistStripPositions(
+ char *aList, /* IN/OUT: Buffer containing doclist */
+ int *pnList /* IN/OUT: Size of doclist in bytes */
+){
+ if( aList ){
+ char *aEnd = &aList[*pnList]; /* Pointer to one byte after EOF */
+ char *p = aList; /* Input cursor */
+ char *pOut = aList; /* Output cursor */
+
+ while( p<aEnd ){
+ sqlite3_int64 delta;
+ p += sqlite3Fts3GetVarint(p, &delta);
+ fts3PoslistCopy(0, &p);
+ pOut += sqlite3Fts3PutVarint(pOut, delta);
+ }
+
+ *pnList = (int)(pOut - aList);
+ }
+}
/*
** Return a DocList corresponding to the phrase *pPhrase.
+**
+** If this function returns SQLITE_OK, but *pnOut is set to a negative value,
+** then no tokens in the phrase were looked up in the full-text index. This
+** is only possible when this function is called from within xFilter(). The
+** caller should assume that all documents match the phrase. The actual
+** filtering will take place in xNext().
*/
static int fts3PhraseSelect(
- Fts3Table *p, /* Virtual table handle */
+ Fts3Cursor *pCsr, /* Virtual table cursor handle */
Fts3Phrase *pPhrase, /* Phrase to return a doclist for */
int isReqPos, /* True if output should contain positions */
char **paOut, /* OUT: Pointer to malloc'd result buffer */
@@ -108676,42 +110790,137 @@ static int fts3PhraseSelect(
int ii;
int iCol = pPhrase->iColumn;
int isTermPos = (pPhrase->nToken>1 || isReqPos);
+ Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
+ int isFirst = 1;
+
+ int iPrevTok = 0;
+ int nDoc = 0;
+ /* If this is an xFilter() evaluation, create a segment-reader for each
+ ** phrase token. Or, if this is an xNext() or snippet/offsets/matchinfo
+ ** evaluation, only create segment-readers if there are no Fts3DeferredToken
+ ** objects attached to the phrase-tokens.
+ */
for(ii=0; ii<pPhrase->nToken; ii++){
- struct PhraseToken *pTok = &pPhrase->aToken[ii];
- char *z = pTok->z; /* Next token of the phrase */
- int n = pTok->n; /* Size of z in bytes */
- int isPrefix = pTok->isPrefix;/* True if token is a prefix */
- char *pList; /* Pointer to token doclist */
- int nList; /* Size of buffer at pList */
-
- rc = fts3TermSelect(p, iCol, z, n, isPrefix, isTermPos, &nList, &pList);
+ Fts3PhraseToken *pTok = &pPhrase->aToken[ii];
+ if( pTok->pArray==0 ){
+ if( (pCsr->eEvalmode==FTS3_EVAL_FILTER)
+ || (pCsr->eEvalmode==FTS3_EVAL_NEXT && pCsr->pDeferred==0)
+ || (pCsr->eEvalmode==FTS3_EVAL_MATCHINFO && pTok->bFulltext)
+ ){
+ rc = fts3TermSegReaderArray(
+ pCsr, pTok->z, pTok->n, pTok->isPrefix, &pTok->pArray
+ );
+ if( rc!=SQLITE_OK ) return rc;
+ }
+ }
+ }
+
+ for(ii=0; ii<pPhrase->nToken; ii++){
+ Fts3PhraseToken *pTok; /* Token to find doclist for */
+ int iTok = 0; /* The token being queried this iteration */
+ char *pList = 0; /* Pointer to token doclist */
+ int nList = 0; /* Size of buffer at pList */
+
+ /* Select a token to process. If this is an xFilter() call, then tokens
+ ** are processed in order from least to most costly. Otherwise, tokens
+ ** are processed in the order in which they occur in the phrase.
+ */
+ if( pCsr->eEvalmode==FTS3_EVAL_MATCHINFO ){
+ assert( isReqPos );
+ iTok = ii;
+ pTok = &pPhrase->aToken[iTok];
+ if( pTok->bFulltext==0 ) continue;
+ }else if( pCsr->eEvalmode==FTS3_EVAL_NEXT || isReqPos ){
+ iTok = ii;
+ pTok = &pPhrase->aToken[iTok];
+ }else{
+ int nMinCost = 0x7FFFFFFF;
+ int jj;
+
+ /* Find the remaining token with the lowest cost. */
+ for(jj=0; jj<pPhrase->nToken; jj++){
+ Fts3SegReaderArray *pArray = pPhrase->aToken[jj].pArray;
+ if( pArray && pArray->nCost<nMinCost ){
+ iTok = jj;
+ nMinCost = pArray->nCost;
+ }
+ }
+ pTok = &pPhrase->aToken[iTok];
+
+ /* This branch is taken if it is determined that loading the doclist
+ ** for the next token would require more IO than loading all documents
+ ** currently identified by doclist pOut/nOut. No further doclists will
+ ** be loaded from the full-text index for this phrase.
+ */
+ if( nMinCost>nDoc && ii>0 ){
+ rc = fts3DeferExpression(pCsr, pCsr->pExpr);
+ break;
+ }
+ }
+
+ if( pCsr->eEvalmode==FTS3_EVAL_NEXT && pTok->pDeferred ){
+ rc = fts3DeferredTermSelect(pTok->pDeferred, isTermPos, &nList, &pList);
+ }else{
+ if( pTok->pArray ){
+ rc = fts3TermSelect(p, pTok, iCol, isTermPos, &nList, &pList);
+ }
+ pTok->bFulltext = 1;
+ }
+ assert( rc!=SQLITE_OK || pCsr->eEvalmode || pTok->pArray==0 );
if( rc!=SQLITE_OK ) break;
- if( ii==0 ){
+ if( isFirst ){
pOut = pList;
nOut = nList;
+ if( pCsr->eEvalmode==FTS3_EVAL_FILTER && pPhrase->nToken>1 ){
+ nDoc = fts3DoclistCountDocids(1, pOut, nOut);
+ }
+ isFirst = 0;
+ iPrevTok = iTok;
}else{
- /* Merge the new term list and the current output. If this is the
- ** last term in the phrase, and positions are not required in the
- ** output of this function, the positions can be dropped as part
- ** of this merge. Either way, the result of this merge will be
- ** smaller than nList bytes. The code in fts3DoclistMerge() is written
- ** so that it is safe to use pList as the output as well as an input
- ** in this case.
+ /* Merge the new term list and the current output. */
+ char *aLeft, *aRight;
+ int nLeft, nRight;
+ int nDist;
+ int mt;
+
+ /* If this is the final token of the phrase, and positions were not
+ ** requested by the caller, use MERGE_PHRASE instead of POS_PHRASE.
+ ** This drops the position information from the output list.
*/
- int mergetype = MERGE_POS_PHRASE;
- if( ii==pPhrase->nToken-1 && !isReqPos ){
- mergetype = MERGE_PHRASE;
- }
- fts3DoclistMerge(mergetype, 0, 0, pList, &nOut, pOut, nOut, pList, nList);
- sqlite3_free(pOut);
- pOut = pList;
+ mt = MERGE_POS_PHRASE;
+ if( ii==pPhrase->nToken-1 && !isReqPos ) mt = MERGE_PHRASE;
+
+ assert( iPrevTok!=iTok );
+ if( iPrevTok<iTok ){
+ aLeft = pOut;
+ nLeft = nOut;
+ aRight = pList;
+ nRight = nList;
+ nDist = iTok-iPrevTok;
+ iPrevTok = iTok;
+ }else{
+ aRight = pOut;
+ nRight = nOut;
+ aLeft = pList;
+ nLeft = nList;
+ nDist = iPrevTok-iTok;
+ }
+ pOut = aRight;
+ fts3DoclistMerge(
+ mt, nDist, 0, pOut, &nOut, aLeft, nLeft, aRight, nRight, &nDoc
+ );
+ sqlite3_free(aLeft);
}
assert( nOut==0 || pOut!=0 );
}
if( rc==SQLITE_OK ){
+ if( ii!=pPhrase->nToken ){
+ assert( pCsr->eEvalmode==FTS3_EVAL_FILTER && isReqPos==0 );
+ fts3DoclistStripPositions(pOut, &nOut);
+ }
*paOut = pOut;
*pnOut = nOut;
}else{
@@ -108720,6 +110929,14 @@ static int fts3PhraseSelect(
return rc;
}
+/*
+** This function merges two doclists according to the requirements of a
+** NEAR operator.
+**
+** Both input doclists must include position information. The output doclist
+** includes position information if the first argument to this function
+** is MERGE_POS_NEAR, or does not if it is MERGE_NEAR.
+*/
static int fts3NearMerge(
int mergetype, /* MERGE_POS_NEAR or MERGE_NEAR */
int nNear, /* Parameter to NEAR operator */
@@ -108732,8 +110949,8 @@ static int fts3NearMerge(
char **paOut, /* OUT: Results of merge (malloced) */
int *pnOut /* OUT: Sized of output buffer */
){
- char *aOut;
- int rc;
+ char *aOut; /* Buffer to write output doclist to */
+ int rc; /* Return code */
assert( mergetype==MERGE_POS_NEAR || MERGE_NEAR );
@@ -108742,7 +110959,7 @@ static int fts3NearMerge(
rc = SQLITE_NOMEM;
}else{
rc = fts3DoclistMerge(mergetype, nNear+nTokenRight, nNear+nTokenLeft,
- aOut, pnOut, aLeft, nLeft, aRight, nRight
+ aOut, pnOut, aLeft, nLeft, aRight, nRight, 0
);
if( rc!=SQLITE_OK ){
sqlite3_free(aOut);
@@ -108754,8 +110971,23 @@ static int fts3NearMerge(
return rc;
}
+/*
+** This function is used as part of the processing for the snippet() and
+** offsets() functions.
+**
+** Both pLeft and pRight are expression nodes of type FTSQUERY_PHRASE. Both
+** have their respective doclists (including position information) loaded
+** in Fts3Expr.aDoclist/nDoclist. This function removes all entries from
+** each doclist that are not within nNear tokens of a corresponding entry
+** in the other doclist.
+*/
SQLITE_PRIVATE int sqlite3Fts3ExprNearTrim(Fts3Expr *pLeft, Fts3Expr *pRight, int nNear){
- int rc;
+ int rc; /* Return code */
+
+ assert( pLeft->eType==FTSQUERY_PHRASE );
+ assert( pRight->eType==FTSQUERY_PHRASE );
+ assert( pLeft->isLoaded && pRight->isLoaded );
+
if( pLeft->aDoclist==0 || pRight->aDoclist==0 ){
sqlite3_free(pLeft->aDoclist);
sqlite3_free(pRight->aDoclist);
@@ -108763,8 +110995,8 @@ SQLITE_PRIVATE int sqlite3Fts3ExprNearTrim(Fts3Expr *pLeft, Fts3Expr *pRight, in
pLeft->aDoclist = 0;
rc = SQLITE_OK;
}else{
- char *aOut;
- int nOut;
+ char *aOut; /* Buffer in which to assemble new doclist */
+ int nOut; /* Size of buffer aOut in bytes */
rc = fts3NearMerge(MERGE_POS_NEAR, nNear,
pLeft->pPhrase->nToken, pLeft->aDoclist, pLeft->nDoclist,
@@ -108788,14 +111020,156 @@ SQLITE_PRIVATE int sqlite3Fts3ExprNearTrim(Fts3Expr *pLeft, Fts3Expr *pRight, in
return rc;
}
+
/*
-** Evaluate the full-text expression pExpr against fts3 table pTab. Store
-** the resulting doclist in *paOut and *pnOut. This routine mallocs for
-** the space needed to store the output. The caller is responsible for
-** freeing the space when it has finished.
+** Allocate an Fts3SegReaderArray for each token in the expression pExpr.
+** The allocated objects are stored in the Fts3PhraseToken.pArray member
+** variables of each token structure.
*/
-static int evalFts3Expr(
- Fts3Table *p, /* Virtual table handle */
+static int fts3ExprAllocateSegReaders(
+ Fts3Cursor *pCsr, /* FTS3 table */
+ Fts3Expr *pExpr, /* Expression to create seg-readers for */
+ int *pnExpr /* OUT: Number of AND'd expressions */
+){
+ int rc = SQLITE_OK; /* Return code */
+
+ assert( pCsr->eEvalmode==FTS3_EVAL_FILTER );
+ if( pnExpr && pExpr->eType!=FTSQUERY_AND ){
+ (*pnExpr)++;
+ pnExpr = 0;
+ }
+
+ if( pExpr->eType==FTSQUERY_PHRASE ){
+ Fts3Phrase *pPhrase = pExpr->pPhrase;
+ int ii;
+
+ for(ii=0; rc==SQLITE_OK && ii<pPhrase->nToken; ii++){
+ Fts3PhraseToken *pTok = &pPhrase->aToken[ii];
+ if( pTok->pArray==0 ){
+ rc = fts3TermSegReaderArray(
+ pCsr, pTok->z, pTok->n, pTok->isPrefix, &pTok->pArray
+ );
+ }
+ }
+ }else{
+ rc = fts3ExprAllocateSegReaders(pCsr, pExpr->pLeft, pnExpr);
+ if( rc==SQLITE_OK ){
+ rc = fts3ExprAllocateSegReaders(pCsr, pExpr->pRight, pnExpr);
+ }
+ }
+ return rc;
+}
+
+/*
+** Free the Fts3SegReaderArray objects associated with each token in the
+** expression pExpr. In other words, this function frees the resources
+** allocated by fts3ExprAllocateSegReaders().
+*/
+static void fts3ExprFreeSegReaders(Fts3Expr *pExpr){
+ if( pExpr ){
+ Fts3Phrase *pPhrase = pExpr->pPhrase;
+ if( pPhrase ){
+ int kk;
+ for(kk=0; kk<pPhrase->nToken; kk++){
+ fts3SegReaderArrayFree(pPhrase->aToken[kk].pArray);
+ pPhrase->aToken[kk].pArray = 0;
+ }
+ }
+ fts3ExprFreeSegReaders(pExpr->pLeft);
+ fts3ExprFreeSegReaders(pExpr->pRight);
+ }
+}
+
+/*
+** Return the sum of the costs of all tokens in the expression pExpr. This
+** function must be called after Fts3SegReaderArrays have been allocated
+** for all tokens using fts3ExprAllocateSegReaders().
+*/
+static int fts3ExprCost(Fts3Expr *pExpr){
+ int nCost; /* Return value */
+ if( pExpr->eType==FTSQUERY_PHRASE ){
+ Fts3Phrase *pPhrase = pExpr->pPhrase;
+ int ii;
+ nCost = 0;
+ for(ii=0; ii<pPhrase->nToken; ii++){
+ Fts3SegReaderArray *pArray = pPhrase->aToken[ii].pArray;
+ if( pArray ){
+ nCost += pPhrase->aToken[ii].pArray->nCost;
+ }
+ }
+ }else{
+ nCost = fts3ExprCost(pExpr->pLeft) + fts3ExprCost(pExpr->pRight);
+ }
+ return nCost;
+}
+
+/*
+** The following is a helper function (and type) for fts3EvalExpr(). It
+** must be called after Fts3SegReaders have been allocated for every token
+** in the expression. See the context it is called from in fts3EvalExpr()
+** for further explanation.
+*/
+typedef struct ExprAndCost ExprAndCost;
+struct ExprAndCost {
+ Fts3Expr *pExpr;
+ int nCost;
+};
+static void fts3ExprAssignCosts(
+ Fts3Expr *pExpr, /* Expression to create seg-readers for */
+ ExprAndCost **ppExprCost /* OUT: Write to *ppExprCost */
+){
+ if( pExpr->eType==FTSQUERY_AND ){
+ fts3ExprAssignCosts(pExpr->pLeft, ppExprCost);
+ fts3ExprAssignCosts(pExpr->pRight, ppExprCost);
+ }else{
+ (*ppExprCost)->pExpr = pExpr;
+ (*ppExprCost)->nCost = fts3ExprCost(pExpr);
+ (*ppExprCost)++;
+ }
+}
+
+/*
+** Evaluate the full-text expression pExpr against FTS3 table pTab. Store
+** the resulting doclist in *paOut and *pnOut. This routine mallocs for
+** the space needed to store the output. The caller is responsible for
+** freeing the space when it has finished.
+**
+** This function is called in two distinct contexts:
+**
+** * From within the virtual table xFilter() method. In this case, the
+** output doclist contains entries for all rows in the table, based on
+** data read from the full-text index.
+**
+** In this case, if the query expression contains one or more tokens that
+** are very common, then the returned doclist may contain a superset of
+** the documents that actually match the expression.
+**
+** * From within the virtual table xNext() method. This call is only made
+** if the call from within xFilter() found that there were very common
+** tokens in the query expression and did return a superset of the
+** matching documents. In this case the returned doclist contains only
+** entries that correspond to the current row of the table. Instead of
+** reading the data for each token from the full-text index, the data is
+** already available in-memory in the Fts3PhraseToken.pDeferred structures.
+** See fts3EvalDeferred() for how it gets there.
+**
+** In the first case above, Fts3Cursor.doDeferred==0. In the second (if it is
+** required) Fts3Cursor.doDeferred==1.
+**
+** If the SQLite invokes the snippet(), offsets() or matchinfo() function
+** as part of a SELECT on an FTS3 table, this function is called on each
+** individual phrase expression in the query. If there were very common tokens
+** found in the xFilter() call, then this function is called once for phrase
+** for each row visited, and the returned doclist contains entries for the
+** current row only. Otherwise, if there were no very common tokens, then this
+** function is called once only for each phrase in the query and the returned
+** doclist contains entries for all rows of the table.
+**
+** Fts3Cursor.doDeferred==1 when this function is called on phrases as a
+** result of a snippet(), offsets() or matchinfo() invocation.
+*/
+static int fts3EvalExpr(
+ Fts3Cursor *p, /* Virtual table cursor handle */
Fts3Expr *pExpr, /* Parsed fts3 expression */
char **paOut, /* OUT: Pointer to malloc'd result buffer */
int *pnOut, /* OUT: Size of buffer at *paOut */
@@ -108808,33 +111182,102 @@ static int evalFts3Expr(
*pnOut = 0;
if( pExpr ){
- assert( pExpr->eType==FTSQUERY_PHRASE
- || pExpr->eType==FTSQUERY_NEAR
- || isReqPos==0
+ assert( pExpr->eType==FTSQUERY_NEAR || pExpr->eType==FTSQUERY_OR
+ || pExpr->eType==FTSQUERY_AND || pExpr->eType==FTSQUERY_NOT
+ || pExpr->eType==FTSQUERY_PHRASE
);
+ assert( pExpr->eType==FTSQUERY_PHRASE || isReqPos==0 );
+
if( pExpr->eType==FTSQUERY_PHRASE ){
- rc = fts3PhraseSelect(p, pExpr->pPhrase,
+ rc = fts3PhraseSelect(p, pExpr->pPhrase,
isReqPos || (pExpr->pParent && pExpr->pParent->eType==FTSQUERY_NEAR),
paOut, pnOut
);
+ fts3ExprFreeSegReaders(pExpr);
+ }else if( p->eEvalmode==FTS3_EVAL_FILTER && pExpr->eType==FTSQUERY_AND ){
+ ExprAndCost *aExpr = 0; /* Array of AND'd expressions and costs */
+ int nExpr = 0; /* Size of aExpr[] */
+ char *aRet = 0; /* Doclist to return to caller */
+ int nRet = 0; /* Length of aRet[] in bytes */
+ int nDoc = 0x7FFFFFFF;
+
+ assert( !isReqPos );
+
+ rc = fts3ExprAllocateSegReaders(p, pExpr, &nExpr);
+ if( rc==SQLITE_OK ){
+ assert( nExpr>1 );
+ aExpr = sqlite3_malloc(sizeof(ExprAndCost) * nExpr);
+ if( !aExpr ) rc = SQLITE_NOMEM;
+ }
+ if( rc==SQLITE_OK ){
+ int ii; /* Used to iterate through expressions */
+
+ fts3ExprAssignCosts(pExpr, &aExpr);
+ aExpr -= nExpr;
+ for(ii=0; ii<nExpr; ii++){
+ char *aNew;
+ int nNew;
+ int jj;
+ ExprAndCost *pBest = 0;
+
+ for(jj=0; jj<nExpr; jj++){
+ ExprAndCost *pCand = &aExpr[jj];
+ if( pCand->pExpr && (pBest==0 || pCand->nCost<pBest->nCost) ){
+ pBest = pCand;
+ }
+ }
+
+ if( pBest->nCost>nDoc ){
+ rc = fts3DeferExpression(p, p->pExpr);
+ break;
+ }else{
+ rc = fts3EvalExpr(p, pBest->pExpr, &aNew, &nNew, 0);
+ if( rc!=SQLITE_OK ) break;
+ pBest->pExpr = 0;
+ if( ii==0 ){
+ aRet = aNew;
+ nRet = nNew;
+ nDoc = fts3DoclistCountDocids(0, aRet, nRet);
+ }else{
+ fts3DoclistMerge(
+ MERGE_AND, 0, 0, aRet, &nRet, aRet, nRet, aNew, nNew, &nDoc
+ );
+ sqlite3_free(aNew);
+ }
+ }
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ *paOut = aRet;
+ *pnOut = nRet;
+ }else{
+ assert( *paOut==0 );
+ sqlite3_free(aRet);
+ }
+ sqlite3_free(aExpr);
+ fts3ExprFreeSegReaders(pExpr);
+
}else{
char *aLeft;
char *aRight;
int nLeft;
int nRight;
- if( 0==(rc = evalFts3Expr(p, pExpr->pRight, &aRight, &nRight, isReqPos))
- && 0==(rc = evalFts3Expr(p, pExpr->pLeft, &aLeft, &nLeft, isReqPos))
+ assert( pExpr->eType==FTSQUERY_NEAR
+ || pExpr->eType==FTSQUERY_OR
+ || pExpr->eType==FTSQUERY_NOT
+ || (pExpr->eType==FTSQUERY_AND && p->eEvalmode==FTS3_EVAL_NEXT)
+ );
+
+ if( 0==(rc = fts3EvalExpr(p, pExpr->pRight, &aRight, &nRight, isReqPos))
+ && 0==(rc = fts3EvalExpr(p, pExpr->pLeft, &aLeft, &nLeft, isReqPos))
){
- assert( pExpr->eType==FTSQUERY_NEAR || pExpr->eType==FTSQUERY_OR
- || pExpr->eType==FTSQUERY_AND || pExpr->eType==FTSQUERY_NOT
- );
switch( pExpr->eType ){
case FTSQUERY_NEAR: {
Fts3Expr *pLeft;
Fts3Expr *pRight;
- int mergetype = isReqPos ? MERGE_POS_NEAR : MERGE_NEAR;
-
+ int mergetype = MERGE_NEAR;
if( pExpr->pParent && pExpr->pParent->eType==FTSQUERY_NEAR ){
mergetype = MERGE_POS_NEAR;
}
@@ -108863,7 +111306,7 @@ static int evalFts3Expr(
*/
char *aBuffer = sqlite3_malloc(nRight+nLeft+1);
rc = fts3DoclistMerge(MERGE_OR, 0, 0, aBuffer, pnOut,
- aLeft, nLeft, aRight, nRight
+ aLeft, nLeft, aRight, nRight, 0
);
*paOut = aBuffer;
sqlite3_free(aLeft);
@@ -108873,7 +111316,7 @@ static int evalFts3Expr(
default: {
assert( FTSQUERY_NOT==MERGE_NOT && FTSQUERY_AND==MERGE_AND );
fts3DoclistMerge(pExpr->eType, 0, 0, aLeft, pnOut,
- aLeft, nLeft, aRight, nRight
+ aLeft, nLeft, aRight, nRight, 0
);
*paOut = aLeft;
break;
@@ -108884,6 +111327,89 @@ static int evalFts3Expr(
}
}
+ assert( rc==SQLITE_OK || *paOut==0 );
+ return rc;
+}
+
+/*
+** This function is called from within xNext() for each row visited by
+** an FTS3 query. If evaluating the FTS3 query expression within xFilter()
+** was able to determine the exact set of matching rows, this function sets
+** *pbRes to true and returns SQLITE_IO immediately.
+**
+** Otherwise, if evaluating the query expression within xFilter() returned a
+** superset of the matching documents instead of an exact set (this happens
+** when the query includes very common tokens and it is deemed too expensive to
+** load their doclists from disk), this function tests if the current row
+** really does match the FTS3 query.
+**
+** If an error occurs, an SQLite error code is returned. Otherwise, SQLITE_OK
+** is returned and *pbRes is set to true if the current row matches the
+** FTS3 query (and should be included in the results returned to SQLite), or
+** false otherwise.
+*/
+static int fts3EvalDeferred(
+ Fts3Cursor *pCsr, /* FTS3 cursor pointing at row to test */
+ int *pbRes /* OUT: Set to true if row is a match */
+){
+ int rc = SQLITE_OK;
+ if( pCsr->pDeferred==0 ){
+ *pbRes = 1;
+ }else{
+ rc = fts3CursorSeek(0, pCsr);
+ if( rc==SQLITE_OK ){
+ sqlite3Fts3FreeDeferredDoclists(pCsr);
+ rc = sqlite3Fts3CacheDeferredDoclists(pCsr);
+ }
+ if( rc==SQLITE_OK ){
+ char *a = 0;
+ int n = 0;
+ rc = fts3EvalExpr(pCsr, pCsr->pExpr, &a, &n, 0);
+ assert( n>=0 );
+ *pbRes = (n>0);
+ sqlite3_free(a);
+ }
+ }
+ return rc;
+}
+
+/*
+** Advance the cursor to the next row in the %_content table that
+** matches the search criteria. For a MATCH search, this will be
+** the next row that matches. For a full-table scan, this will be
+** simply the next row in the %_content table. For a docid lookup,
+** this routine simply sets the EOF flag.
+**
+** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned
+** even if we reach end-of-file. The fts3EofMethod() will be called
+** subsequently to determine whether or not an EOF was hit.
+*/
+static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
+ int res;
+ int rc = SQLITE_OK; /* Return code */
+ Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
+
+ pCsr->eEvalmode = FTS3_EVAL_NEXT;
+ do {
+ if( pCsr->aDoclist==0 ){
+ if( SQLITE_ROW!=sqlite3_step(pCsr->pStmt) ){
+ pCsr->isEof = 1;
+ rc = sqlite3_reset(pCsr->pStmt);
+ break;
+ }
+ pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0);
+ }else{
+ if( pCsr->pNextId>=&pCsr->aDoclist[pCsr->nDoclist] ){
+ pCsr->isEof = 1;
+ break;
+ }
+ sqlite3_reset(pCsr->pStmt);
+ fts3GetDeltaVarint(&pCsr->pNextId, &pCsr->iPrevId);
+ pCsr->isRequireSeek = 1;
+ pCsr->isMatchinfoNeeded = 1;
+ }
+ }while( SQLITE_OK==(rc = fts3EvalDeferred(pCsr, &res)) && res==0 );
+
return rc;
}
@@ -108903,11 +111429,6 @@ static int evalFts3Expr(
** number idxNum-FTS3_FULLTEXT_SEARCH, 0 indexed. argv[0] is the right-hand
** side of the MATCH operator.
*/
-/* TODO(shess) Upgrade the cursor initialization and destruction to
-** account for fts3FilterMethod() being called multiple times on the
-** same cursor. The current solution is very fragile. Apply fix to
-** fts3 as appropriate.
-*/
static int fts3FilterMethod(
sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */
int idxNum, /* Strategy index */
@@ -108930,6 +111451,7 @@ static int fts3FilterMethod(
assert( idxNum>=0 && idxNum<=(FTS3_FULLTEXT_SEARCH+p->nColumn) );
assert( nVal==0 || nVal==1 );
assert( (nVal==0)==(idxNum==FTS3_FULLSCAN_SEARCH) );
+ assert( p->pSegments==0 );
/* In case the cursor has been used before, clear it now. */
sqlite3_finalize(pCsr->pStmt);
@@ -108937,24 +111459,7 @@ static int fts3FilterMethod(
sqlite3Fts3ExprFree(pCsr->pExpr);
memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));
- /* Compile a SELECT statement for this cursor. For a full-table-scan, the
- ** statement loops through all rows of the %_content table. For a
- ** full-text query or docid lookup, the statement retrieves a single
- ** row by docid.
- */
- zSql = sqlite3_mprintf(azSql[idxNum==FTS3_FULLSCAN_SEARCH], p->zDb, p->zName);
- if( !zSql ){
- rc = SQLITE_NOMEM;
- }else{
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
- sqlite3_free(zSql);
- }
- if( rc!=SQLITE_OK ) return rc;
- pCsr->eSearch = (i16)idxNum;
-
- if( idxNum==FTS3_DOCID_SEARCH ){
- rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
- }else if( idxNum!=FTS3_FULLSCAN_SEARCH ){
+ if( idxNum!=FTS3_DOCID_SEARCH && idxNum!=FTS3_FULLSCAN_SEARCH ){
int iCol = idxNum-FTS3_FULLTEXT_SEARCH;
const char *zQuery = (const char *)sqlite3_value_text(apVal[0]);
@@ -108973,11 +111478,33 @@ static int fts3FilterMethod(
return rc;
}
- rc = evalFts3Expr(p, pCsr->pExpr, &pCsr->aDoclist, &pCsr->nDoclist, 0);
+ rc = sqlite3Fts3ReadLock(p);
+ if( rc!=SQLITE_OK ) return rc;
+
+ rc = fts3EvalExpr(pCsr, pCsr->pExpr, &pCsr->aDoclist, &pCsr->nDoclist, 0);
+ sqlite3Fts3SegmentsClose(p);
+ if( rc!=SQLITE_OK ) return rc;
pCsr->pNextId = pCsr->aDoclist;
pCsr->iPrevId = 0;
}
+ /* Compile a SELECT statement for this cursor. For a full-table-scan, the
+ ** statement loops through all rows of the %_content table. For a
+ ** full-text query or docid lookup, the statement retrieves a single
+ ** row by docid.
+ */
+ zSql = sqlite3_mprintf(azSql[idxNum==FTS3_FULLSCAN_SEARCH], p->zDb, p->zName);
+ if( !zSql ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
+ sqlite3_free(zSql);
+ }
+ if( rc==SQLITE_OK && idxNum==FTS3_DOCID_SEARCH ){
+ rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
+ }
+ pCsr->eSearch = (i16)idxNum;
+
if( rc!=SQLITE_OK ) return rc;
return fts3NextMethod(pCursor);
}
@@ -109001,6 +111528,11 @@ static int fts3RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
if( pCsr->aDoclist ){
*pRowid = pCsr->iPrevId;
}else{
+ /* This branch runs if the query is implemented using a full-table scan
+ ** (not using the full-text index). In this case grab the rowid from the
+ ** SELECT statement.
+ */
+ assert( pCsr->isRequireSeek==0 );
*pRowid = sqlite3_column_int64(pCsr->pStmt, 0);
}
return SQLITE_OK;
@@ -109063,7 +111595,9 @@ static int fts3UpdateMethod(
** hash-table to the database.
*/
static int fts3SyncMethod(sqlite3_vtab *pVtab){
- return sqlite3Fts3PendingTermsFlush((Fts3Table *)pVtab);
+ int rc = sqlite3Fts3PendingTermsFlush((Fts3Table *)pVtab);
+ sqlite3Fts3SegmentsClose((Fts3Table *)pVtab);
+ return rc;
}
/*
@@ -109101,8 +111635,27 @@ static int fts3RollbackMethod(sqlite3_vtab *pVtab){
** This is used by the matchinfo(), snippet() and offsets() auxillary
** functions.
*/
-SQLITE_PRIVATE int sqlite3Fts3ExprLoadDoclist(Fts3Table *pTab, Fts3Expr *pExpr){
- return evalFts3Expr(pTab, pExpr, &pExpr->aDoclist, &pExpr->nDoclist, 1);
+SQLITE_PRIVATE int sqlite3Fts3ExprLoadDoclist(Fts3Cursor *pCsr, Fts3Expr *pExpr){
+ int rc;
+ assert( pExpr->eType==FTSQUERY_PHRASE && pExpr->pPhrase );
+ assert( pCsr->eEvalmode==FTS3_EVAL_NEXT );
+ rc = fts3EvalExpr(pCsr, pExpr, &pExpr->aDoclist, &pExpr->nDoclist, 1);
+ return rc;
+}
+
+SQLITE_PRIVATE int sqlite3Fts3ExprLoadFtDoclist(
+ Fts3Cursor *pCsr,
+ Fts3Expr *pExpr,
+ char **paDoclist,
+ int *pnDoclist
+){
+ int rc;
+ assert( pCsr->eEvalmode==FTS3_EVAL_NEXT );
+ assert( pExpr->eType==FTSQUERY_PHRASE && pExpr->pPhrase );
+ pCsr->eEvalmode = FTS3_EVAL_MATCHINFO;
+ rc = fts3EvalExpr(pCsr, pExpr, paDoclist, pnDoclist, 1);
+ pCsr->eEvalmode = FTS3_EVAL_NEXT;
+ return rc;
}
/*
@@ -109118,9 +111671,16 @@ SQLITE_PRIVATE char *sqlite3Fts3FindPositions(
assert( pExpr->isLoaded );
if( pExpr->aDoclist ){
char *pEnd = &pExpr->aDoclist[pExpr->nDoclist];
- char *pCsr = pExpr->pCurrent;
+ char *pCsr;
+ if( pExpr->pCurrent==0 ){
+ pExpr->pCurrent = pExpr->aDoclist;
+ pExpr->iCurrent = 0;
+ pExpr->pCurrent += sqlite3Fts3GetVarint(pExpr->pCurrent,&pExpr->iCurrent);
+ }
+ pCsr = pExpr->pCurrent;
assert( pCsr );
+
while( pCsr<pEnd ){
if( pExpr->iCurrent<iDocid ){
fts3PoslistCopy(0, &pCsr);
@@ -109168,7 +111728,7 @@ static int fts3FunctionArg(
sqlite3_context *pContext, /* SQL function call context */
const char *zFunc, /* Function name */
sqlite3_value *pVal, /* argv[0] passed to function */
- Fts3Cursor **ppCsr /* OUT: Store cursor handle here */
+ Fts3Cursor **ppCsr /* OUT: Store cursor handle here */
){
Fts3Cursor *pRet;
if( sqlite3_value_type(pVal)!=SQLITE_BLOB
@@ -109294,15 +111854,13 @@ static void fts3MatchinfoFunc(
sqlite3_value **apVal /* Array of arguments */
){
Fts3Cursor *pCsr; /* Cursor handle passed through apVal[0] */
-
- if( nVal!=1 ){
- sqlite3_result_error(pContext,
- "wrong number of arguments to function matchinfo()", -1);
- return;
- }
-
+ assert( nVal==1 || nVal==2 );
if( SQLITE_OK==fts3FunctionArg(pContext, "matchinfo", apVal[0], &pCsr) ){
- sqlite3Fts3Matchinfo(pContext, pCsr);
+ const char *zArg = 0;
+ if( nVal>1 ){
+ zArg = (const char *)sqlite3_value_text(apVal[1]);
+ }
+ sqlite3Fts3Matchinfo(pContext, pCsr, zArg);
}
}
@@ -109351,21 +111909,25 @@ static int fts3RenameMethod(
const char *zName /* New name of table */
){
Fts3Table *p = (Fts3Table *)pVtab;
- sqlite3 *db; /* Database connection */
+ sqlite3 *db = p->db; /* Database connection */
int rc; /* Return Code */
-
- db = p->db;
- rc = SQLITE_OK;
+
+ rc = sqlite3Fts3PendingTermsFlush(p);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+
fts3DbExec(&rc, db,
"ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';",
p->zDb, p->zName, zName
);
- if( rc==SQLITE_ERROR ) rc = SQLITE_OK;
if( p->bHasDocsize ){
fts3DbExec(&rc, db,
"ALTER TABLE %Q.'%q_docsize' RENAME TO '%q_docsize';",
p->zDb, p->zName, zName
);
+ }
+ if( p->bHasStat ){
fts3DbExec(&rc, db,
"ALTER TABLE %Q.'%q_stat' RENAME TO '%q_stat';",
p->zDb, p->zName, zName
@@ -109390,7 +111952,7 @@ static const sqlite3_module fts3Module = {
/* xDisconnect */ fts3DisconnectMethod,
/* xDestroy */ fts3DestroyMethod,
/* xOpen */ fts3OpenMethod,
- /* xClose */ fulltextClose,
+ /* xClose */ fts3CloseMethod,
/* xFilter */ fts3FilterMethod,
/* xNext */ fts3NextMethod,
/* xEof */ fts3EofMethod,
@@ -109417,19 +111979,20 @@ static void hashDestroy(void *p){
}
/*
-** The fts3 built-in tokenizers - "simple" and "porter" - are implemented
-** in files fts3_tokenizer1.c and fts3_porter.c respectively. The following
-** two forward declarations are for functions declared in these files
-** used to retrieve the respective implementations.
+** The fts3 built-in tokenizers - "simple", "porter" and "icu"- are
+** implemented in files fts3_tokenizer1.c, fts3_porter.c and fts3_icu.c
+** respectively. The following three forward declarations are for functions
+** declared in these files used to retrieve the respective implementations.
**
** Calling sqlite3Fts3SimpleTokenizerModule() sets the value pointed
** to by the argument to point to the "simple" tokenizer implementation.
-** Function ...PorterTokenizerModule() sets *pModule to point to the
-** porter tokenizer/stemmer implementation.
+** And so on.
*/
SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule);
SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(sqlite3_tokenizer_module const**ppModule);
+#ifdef SQLITE_ENABLE_ICU
SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule);
+#endif
/*
** Initialise the fts3 extension. If this extension is built as part
@@ -109485,7 +112048,8 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
&& SQLITE_OK==(rc = sqlite3Fts3InitHashTable(db, pHash, "fts3_tokenizer"))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", 1))
- && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", -1))
+ && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 1))
+ && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 2))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", 1))
){
rc = sqlite3_create_module_v2(
@@ -109629,6 +112193,18 @@ static int fts3isspace(char c){
}
/*
+** Allocate nByte bytes of memory using sqlite3_malloc(). If successful,
+** zero the memory before returning a pointer to it. If unsuccessful,
+** return NULL.
+*/
+static void *fts3MallocZero(int nByte){
+ void *pRet = sqlite3_malloc(nByte);
+ if( pRet ) memset(pRet, 0, nByte);
+ return pRet;
+}
+
+
+/*
** Extract the next token from buffer z (length n) using the tokenizer
** and other information (column names etc.) in pParse. Create an Fts3Expr
** structure of type FTSQUERY_PHRASE containing a phrase consisting of this
@@ -109665,11 +112241,10 @@ static int getNextToken(
if( rc==SQLITE_OK ){
nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken;
- pRet = (Fts3Expr *)sqlite3_malloc(nByte);
+ pRet = (Fts3Expr *)fts3MallocZero(nByte);
if( !pRet ){
rc = SQLITE_NOMEM;
}else{
- memset(pRet, 0, nByte);
pRet->eType = FTSQUERY_PHRASE;
pRet->pPhrase = (Fts3Phrase *)&pRet[1];
pRet->pPhrase->nToken = 1;
@@ -109745,7 +112320,7 @@ static int getNextString(
rc = pModule->xNext(pCursor, &zToken, &nToken, &iBegin, &iEnd, &iPos);
if( rc==SQLITE_OK ){
int nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
- p = fts3ReallocOrFree(p, nByte+ii*sizeof(struct PhraseToken));
+ p = fts3ReallocOrFree(p, nByte+ii*sizeof(Fts3PhraseToken));
zTemp = fts3ReallocOrFree(zTemp, nTemp + nToken);
if( !p || !zTemp ){
goto no_mem;
@@ -109755,6 +112330,7 @@ static int getNextString(
p->pPhrase = (Fts3Phrase *)&p[1];
}
p->pPhrase = (Fts3Phrase *)&p[1];
+ memset(&p->pPhrase->aToken[ii], 0, sizeof(Fts3PhraseToken));
p->pPhrase->nToken = ii+1;
p->pPhrase->aToken[ii].n = nToken;
memcpy(&zTemp[nTemp], zToken, nToken);
@@ -109776,7 +112352,7 @@ static int getNextString(
char *zNew = NULL;
int nNew = 0;
int nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
- nByte += (p?(p->pPhrase->nToken-1):0) * sizeof(struct PhraseToken);
+ nByte += (p?(p->pPhrase->nToken-1):0) * sizeof(Fts3PhraseToken);
p = fts3ReallocOrFree(p, nByte + nTemp);
if( !p ){
goto no_mem;
@@ -109894,11 +112470,10 @@ static int getNextNode(
if( fts3isspace(cNext)
|| cNext=='"' || cNext=='(' || cNext==')' || cNext==0
){
- pRet = (Fts3Expr *)sqlite3_malloc(sizeof(Fts3Expr));
+ pRet = (Fts3Expr *)fts3MallocZero(sizeof(Fts3Expr));
if( !pRet ){
return SQLITE_NOMEM;
}
- memset(pRet, 0, sizeof(Fts3Expr));
pRet->eType = pKey->eType;
pRet->nNear = nNear;
*ppExpr = pRet;
@@ -109916,7 +112491,6 @@ static int getNextNode(
if( sqlite3_fts3_enable_parentheses ){
if( *zInput=='(' ){
int nConsumed;
- int rc;
pParse->nNest++;
rc = fts3ExprParse(pParse, &zInput[1], nInput-1, ppExpr, &nConsumed);
if( rc==SQLITE_OK && !*ppExpr ){
@@ -110074,13 +112648,12 @@ static int fts3ExprParse(
&& p->eType==FTSQUERY_PHRASE && p->pPhrase->isNot
){
/* Create an implicit NOT operator. */
- Fts3Expr *pNot = sqlite3_malloc(sizeof(Fts3Expr));
+ Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr));
if( !pNot ){
sqlite3Fts3ExprFree(p);
rc = SQLITE_NOMEM;
goto exprparse_out;
}
- memset(pNot, 0, sizeof(Fts3Expr));
pNot->eType = FTSQUERY_NOT;
pNot->pRight = p;
if( pNotBranch ){
@@ -110108,13 +112681,12 @@ static int fts3ExprParse(
/* Insert an implicit AND operator. */
Fts3Expr *pAnd;
assert( pRet && pPrev );
- pAnd = sqlite3_malloc(sizeof(Fts3Expr));
+ pAnd = fts3MallocZero(sizeof(Fts3Expr));
if( !pAnd ){
sqlite3Fts3ExprFree(p);
rc = SQLITE_NOMEM;
goto exprparse_out;
}
- memset(pAnd, 0, sizeof(Fts3Expr));
pAnd->eType = FTSQUERY_AND;
insertBinaryOperator(&pRet, pPrev, pAnd);
pPrev = pAnd;
@@ -110298,47 +112870,53 @@ static int queryTestTokenizer(
}
/*
-** This function is part of the test interface for the query parser. It
-** writes a text representation of the query expression pExpr into the
-** buffer pointed to by argument zBuf. It is assumed that zBuf is large
-** enough to store the required text representation.
+** Return a pointer to a buffer containing a text representation of the
+** expression passed as the first argument. The buffer is obtained from
+** sqlite3_malloc(). It is the responsibility of the caller to use
+** sqlite3_free() to release the memory. If an OOM condition is encountered,
+** NULL is returned.
+**
+** If the second argument is not NULL, then its contents are prepended to
+** the returned expression text and then freed using sqlite3_free().
*/
-static void exprToString(Fts3Expr *pExpr, char *zBuf){
+static char *exprToString(Fts3Expr *pExpr, char *zBuf){
switch( pExpr->eType ){
case FTSQUERY_PHRASE: {
Fts3Phrase *pPhrase = pExpr->pPhrase;
int i;
- zBuf += sprintf(zBuf, "PHRASE %d %d", pPhrase->iColumn, pPhrase->isNot);
- for(i=0; i<pPhrase->nToken; i++){
- zBuf += sprintf(zBuf," %.*s",pPhrase->aToken[i].n,pPhrase->aToken[i].z);
- zBuf += sprintf(zBuf,"%s", (pPhrase->aToken[i].isPrefix?"+":""));
+ zBuf = sqlite3_mprintf(
+ "%zPHRASE %d %d", zBuf, pPhrase->iColumn, pPhrase->isNot);
+ for(i=0; zBuf && i<pPhrase->nToken; i++){
+ zBuf = sqlite3_mprintf("%z %.*s%s", zBuf,
+ pPhrase->aToken[i].n, pPhrase->aToken[i].z,
+ (pPhrase->aToken[i].isPrefix?"+":"")
+ );
}
- return;
+ return zBuf;
}
case FTSQUERY_NEAR:
- zBuf += sprintf(zBuf, "NEAR/%d ", pExpr->nNear);
+ zBuf = sqlite3_mprintf("%zNEAR/%d ", zBuf, pExpr->nNear);
break;
case FTSQUERY_NOT:
- zBuf += sprintf(zBuf, "NOT ");
+ zBuf = sqlite3_mprintf("%zNOT ", zBuf);
break;
case FTSQUERY_AND:
- zBuf += sprintf(zBuf, "AND ");
+ zBuf = sqlite3_mprintf("%zAND ", zBuf);
break;
case FTSQUERY_OR:
- zBuf += sprintf(zBuf, "OR ");
+ zBuf = sqlite3_mprintf("%zOR ", zBuf);
break;
}
- zBuf += sprintf(zBuf, "{");
- exprToString(pExpr->pLeft, zBuf);
- zBuf += strlen(zBuf);
- zBuf += sprintf(zBuf, "} ");
+ if( zBuf ) zBuf = sqlite3_mprintf("%z{", zBuf);
+ if( zBuf ) zBuf = exprToString(pExpr->pLeft, zBuf);
+ if( zBuf ) zBuf = sqlite3_mprintf("%z} {", zBuf);
+
+ if( zBuf ) zBuf = exprToString(pExpr->pRight, zBuf);
+ if( zBuf ) zBuf = sqlite3_mprintf("%z}", zBuf);
- zBuf += sprintf(zBuf, "{");
- exprToString(pExpr->pRight, zBuf);
- zBuf += strlen(zBuf);
- zBuf += sprintf(zBuf, "}");
+ return zBuf;
}
/*
@@ -110369,6 +112947,7 @@ static void fts3ExprTest(
int nCol;
int ii;
Fts3Expr *pExpr;
+ char *zBuf = 0;
sqlite3 *db = sqlite3_context_db_handle(context);
if( argc<3 ){
@@ -110411,18 +112990,17 @@ static void fts3ExprTest(
rc = sqlite3Fts3ExprParse(
pTokenizer, azCol, nCol, nCol, zExpr, nExpr, &pExpr
);
- if( rc==SQLITE_NOMEM ){
+ if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
+ sqlite3_result_error(context, "Error parsing expression", -1);
+ }else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){
sqlite3_result_error_nomem(context);
- goto exprtest_out;
- }else if( rc==SQLITE_OK ){
- char zBuf[4096];
- exprToString(pExpr, zBuf);
- sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
- sqlite3Fts3ExprFree(pExpr);
}else{
- sqlite3_result_error(context, "Error parsing expression", -1);
+ sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
+ sqlite3_free(zBuf);
}
+ sqlite3Fts3ExprFree(pExpr);
+
exprtest_out:
if( pModule && pTokenizer ){
rc = pModule->xDestroy(pTokenizer);
@@ -111165,7 +113743,7 @@ static void porter_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){
int i, j;
char zReverse[28];
char *z, *z2;
- if( nIn<3 || nIn>=sizeof(zReverse)-7 ){
+ if( nIn<3 || nIn>=(int)sizeof(zReverse)-7 ){
/* The word is too big or too small for the porter stemmer.
** Fallback to the copy stemmer */
copy_stemmer(zIn, nIn, zOut, pnOut);
@@ -111564,7 +114142,7 @@ static void scalarFunc(
sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT);
}
-static int fts3IsIdChar(char c){
+SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char c){
static const char isFtsIdChar[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */
@@ -111602,9 +114180,9 @@ SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *zStr, int *pn){
break;
default:
- if( fts3IsIdChar(*z1) ){
+ if( sqlite3Fts3IsIdChar(*z1) ){
z2 = &z1[1];
- while( fts3IsIdChar(*z2) ) z2++;
+ while( sqlite3Fts3IsIdChar(*z2) ) z2++;
}else{
z1++;
}
@@ -111617,9 +114195,8 @@ SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *zStr, int *pn){
SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
Fts3Hash *pHash, /* Tokenizer hash table */
- const char *zArg, /* Possible tokenizer specification */
+ const char *zArg, /* Tokenizer name */
sqlite3_tokenizer **ppTok, /* OUT: Tokenizer (if applicable) */
- const char **pzTokenizer, /* OUT: Set to zArg if is tokenizer */
char **pzErr /* OUT: Set to malloced error message */
){
int rc;
@@ -111629,26 +114206,15 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
char *zEnd; /* Pointer to nul-term of zCopy */
sqlite3_tokenizer_module *m;
- if( !z ){
- zCopy = sqlite3_mprintf("simple");
- }else{
- if( sqlite3_strnicmp(z, "tokenize", 8) || fts3IsIdChar(z[8])){
- return SQLITE_OK;
- }
- zCopy = sqlite3_mprintf("%s", &z[8]);
- *pzTokenizer = zArg;
- }
- if( !zCopy ){
- return SQLITE_NOMEM;
- }
-
+ zCopy = sqlite3_mprintf("%s", zArg);
+ if( !zCopy ) return SQLITE_NOMEM;
zEnd = &zCopy[strlen(zCopy)];
z = (char *)sqlite3Fts3NextToken(zCopy, &n);
z[n] = '\0';
sqlite3Fts3Dequote(z);
- m = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, z, (int)strlen(z)+1);
+ m = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash,z,(int)strlen(z)+1);
if( !m ){
*pzErr = sqlite3_mprintf("unknown tokenizer: %s", z);
rc = SQLITE_ERROR;
@@ -111942,15 +114508,23 @@ SQLITE_PRIVATE int sqlite3Fts3InitHashTable(
}
#endif
- if( SQLITE_OK!=rc
- || SQLITE_OK!=(rc = sqlite3_create_function(db, zName, 1, any, p, scalarFunc, 0, 0))
- || SQLITE_OK!=(rc = sqlite3_create_function(db, zName, 2, any, p, scalarFunc, 0, 0))
+ if( SQLITE_OK==rc ){
+ rc = sqlite3_create_function(db, zName, 1, any, p, scalarFunc, 0, 0);
+ }
+ if( SQLITE_OK==rc ){
+ rc = sqlite3_create_function(db, zName, 2, any, p, scalarFunc, 0, 0);
+ }
#ifdef SQLITE_TEST
- || SQLITE_OK!=(rc = sqlite3_create_function(db, zTest, 2, any, p, testFunc, 0, 0))
- || SQLITE_OK!=(rc = sqlite3_create_function(db, zTest, 3, any, p, testFunc, 0, 0))
- || SQLITE_OK!=(rc = sqlite3_create_function(db, zTest2, 0, any, pdb, intTestFunc, 0, 0))
+ if( SQLITE_OK==rc ){
+ rc = sqlite3_create_function(db, zTest, 2, any, p, testFunc, 0, 0);
+ }
+ if( SQLITE_OK==rc ){
+ rc = sqlite3_create_function(db, zTest, 3, any, p, testFunc, 0, 0);
+ }
+ if( SQLITE_OK==rc ){
+ rc = sqlite3_create_function(db, zTest2, 0, any, pdb, intTestFunc, 0, 0);
+ }
#endif
- );
#ifdef SQLITE_TEST
sqlite3_free(zTest);
@@ -112217,6 +114791,18 @@ SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
+/*
+** When full-text index nodes are loaded from disk, the buffer that they
+** are loaded into has the following number of bytes of padding at the end
+** of it. i.e. if a full-text index node is 900 bytes in size, then a buffer
+** of 920 bytes is allocated for it.
+**
+** This means that if we have a pointer into a buffer containing node data,
+** it is always safe to read up to two varints from it without risking an
+** overread, even if the node data is corrupted.
+*/
+#define FTS3_NODE_PADDING (FTS3_VARINT_MAX*2)
+
typedef struct PendingList PendingList;
typedef struct SegmentNode SegmentNode;
typedef struct SegmentWriter SegmentWriter;
@@ -112235,6 +114821,17 @@ struct PendingList {
sqlite3_int64 iLastPos;
};
+
+/*
+** Each cursor has a (possibly empty) linked list of the following objects.
+*/
+struct Fts3DeferredToken {
+ Fts3PhraseToken *pToken; /* Pointer to corresponding expr token */
+ int iCol; /* Column token must occur in */
+ Fts3DeferredToken *pNext; /* Next in list of deferred tokens */
+ PendingList *pList; /* Doclist is assembled here */
+};
+
/*
** An instance of this structure is used to iterate through the terms on
** a contiguous set of segment b-tree leaf nodes. Although the details of
@@ -112244,6 +114841,7 @@ struct PendingList {
**
** sqlite3Fts3SegReaderNew()
** sqlite3Fts3SegReaderFree()
+** sqlite3Fts3SegReaderCost()
** sqlite3Fts3SegReaderIterate()
**
** Methods used to manipulate Fts3SegReader structures:
@@ -112254,12 +114852,14 @@ struct PendingList {
*/
struct Fts3SegReader {
int iIdx; /* Index within level, or 0x7FFFFFFF for PT */
- sqlite3_int64 iStartBlock;
- sqlite3_int64 iEndBlock;
- sqlite3_stmt *pStmt; /* SQL Statement to access leaf nodes */
+
+ sqlite3_int64 iStartBlock; /* Rowid of first leaf block to traverse */
+ sqlite3_int64 iLeafEndBlock; /* Rowid of final leaf block to traverse */
+ sqlite3_int64 iEndBlock; /* Rowid of final block in segment (or 0) */
+ sqlite3_int64 iCurrentBlock; /* Current leaf block (or 0) */
+
char *aNode; /* Pointer to node data (or NULL) */
int nNode; /* Size of buffer at aNode (or 0) */
- int nTermAlloc; /* Allocated size of zTerm buffer */
Fts3HashElem **ppNextElem;
/* Variables set by fts3SegReaderNext(). These may be read directly
@@ -112269,6 +114869,7 @@ struct Fts3SegReader {
*/
int nTerm; /* Number of bytes in current term */
char *zTerm; /* Pointer to current term */
+ int nTermAlloc; /* Allocated size of zTerm buffer */
char *aDoclist; /* Pointer to doclist of current entry */
int nDoclist; /* Size of doclist in current entry */
@@ -112278,6 +114879,7 @@ struct Fts3SegReader {
};
#define fts3SegReaderIsPending(p) ((p)->ppNextElem!=0)
+#define fts3SegReaderIsRootOnly(p) ((p)->aNode==(char *)&(p)[1])
/*
** An instance of this structure is used to create a segment b-tree in the
@@ -112346,12 +114948,11 @@ struct SegmentNode {
#define SQL_DELETE_SEGDIR_BY_LEVEL 16
#define SQL_DELETE_SEGMENTS_RANGE 17
#define SQL_CONTENT_INSERT 18
-#define SQL_GET_BLOCK 19
-#define SQL_DELETE_DOCSIZE 20
-#define SQL_REPLACE_DOCSIZE 21
-#define SQL_SELECT_DOCSIZE 22
-#define SQL_SELECT_DOCTOTAL 23
-#define SQL_REPLACE_DOCTOTAL 24
+#define SQL_DELETE_DOCSIZE 19
+#define SQL_REPLACE_DOCSIZE 20
+#define SQL_SELECT_DOCSIZE 21
+#define SQL_SELECT_DOCTOTAL 22
+#define SQL_REPLACE_DOCTOTAL 23
/*
** This function is used to obtain an SQLite prepared statement handle
@@ -112396,12 +114997,11 @@ static int fts3SqlStmt(
/* 16 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ?",
/* 17 */ "DELETE FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ?",
/* 18 */ "INSERT INTO %Q.'%q_content' VALUES(%z)",
-/* 19 */ "SELECT block FROM %Q.'%q_segments' WHERE blockid = ?",
-/* 20 */ "DELETE FROM %Q.'%q_docsize' WHERE docid = ?",
-/* 21 */ "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)",
-/* 22 */ "SELECT size FROM %Q.'%q_docsize' WHERE docid=?",
-/* 23 */ "SELECT value FROM %Q.'%q_stat' WHERE id=0",
-/* 24 */ "REPLACE INTO %Q.'%q_stat' VALUES(0,?)",
+/* 19 */ "DELETE FROM %Q.'%q_docsize' WHERE docid = ?",
+/* 20 */ "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)",
+/* 21 */ "SELECT size FROM %Q.'%q_docsize' WHERE docid=?",
+/* 22 */ "SELECT value FROM %Q.'%q_stat' WHERE id=0",
+/* 23 */ "REPLACE INTO %Q.'%q_stat' VALUES(0,?)",
};
int rc = SQLITE_OK;
sqlite3_stmt *pStmt;
@@ -112450,6 +115050,51 @@ static int fts3SqlStmt(
return rc;
}
+static int fts3SelectDocsize(
+ Fts3Table *pTab, /* FTS3 table handle */
+ int eStmt, /* Either SQL_SELECT_DOCSIZE or DOCTOTAL */
+ sqlite3_int64 iDocid, /* Docid to bind for SQL_SELECT_DOCSIZE */
+ sqlite3_stmt **ppStmt /* OUT: Statement handle */
+){
+ sqlite3_stmt *pStmt = 0; /* Statement requested from fts3SqlStmt() */
+ int rc; /* Return code */
+
+ assert( eStmt==SQL_SELECT_DOCSIZE || eStmt==SQL_SELECT_DOCTOTAL );
+
+ rc = fts3SqlStmt(pTab, eStmt, &pStmt, 0);
+ if( rc==SQLITE_OK ){
+ if( eStmt==SQL_SELECT_DOCSIZE ){
+ sqlite3_bind_int64(pStmt, 1, iDocid);
+ }
+ rc = sqlite3_step(pStmt);
+ if( rc!=SQLITE_ROW ){
+ rc = sqlite3_reset(pStmt);
+ if( rc==SQLITE_OK ) rc = SQLITE_CORRUPT;
+ pStmt = 0;
+ }else{
+ rc = SQLITE_OK;
+ }
+ }
+
+ *ppStmt = pStmt;
+ return rc;
+}
+
+SQLITE_PRIVATE int sqlite3Fts3SelectDoctotal(
+ Fts3Table *pTab, /* Fts3 table handle */
+ sqlite3_stmt **ppStmt /* OUT: Statement handle */
+){
+ return fts3SelectDocsize(pTab, SQL_SELECT_DOCTOTAL, 0, ppStmt);
+}
+
+SQLITE_PRIVATE int sqlite3Fts3SelectDocsize(
+ Fts3Table *pTab, /* Fts3 table handle */
+ sqlite3_int64 iDocid, /* Docid to read size data for */
+ sqlite3_stmt **ppStmt /* OUT: Statement handle */
+){
+ return fts3SelectDocsize(pTab, SQL_SELECT_DOCSIZE, iDocid, ppStmt);
+}
+
/*
** Similar to fts3SqlStmt(). Except, after binding the parameters in
** array apVal[] to the SQL statement identified by eStmt, the statement
@@ -112477,42 +115122,33 @@ static void fts3SqlExec(
/*
-** Read a single block from the %_segments table. If the specified block
-** does not exist, return SQLITE_CORRUPT. If some other error (malloc, IO
-** etc.) occurs, return the appropriate SQLite error code.
+** This function ensures that the caller has obtained a shared-cache
+** table-lock on the %_content table. This is required before reading
+** data from the fts3 table. If this lock is not acquired first, then
+** the caller may end up holding read-locks on the %_segments and %_segdir
+** tables, but no read-lock on the %_content table. If this happens
+** a second connection will be able to write to the fts3 table, but
+** attempting to commit those writes might return SQLITE_LOCKED or
+** SQLITE_LOCKED_SHAREDCACHE (because the commit attempts to obtain
+** write-locks on the %_segments and %_segdir ** tables).
**
-** Otherwise, if successful, set *pzBlock to point to a buffer containing
-** the block read from the database, and *pnBlock to the size of the read
-** block in bytes.
-**
-** WARNING: The returned buffer is only valid until the next call to
-** sqlite3Fts3ReadBlock().
+** We try to avoid this because if FTS3 returns any error when committing
+** a transaction, the whole transaction will be rolled back. And this is
+** not what users expect when they get SQLITE_LOCKED_SHAREDCACHE. It can
+** still happen if the user reads data directly from the %_segments or
+** %_segdir tables instead of going through FTS3 though.
*/
-SQLITE_PRIVATE int sqlite3Fts3ReadBlock(
- Fts3Table *p,
- sqlite3_int64 iBlock,
- char const **pzBlock,
- int *pnBlock
-){
- sqlite3_stmt *pStmt;
- int rc = fts3SqlStmt(p, SQL_GET_BLOCK, &pStmt, 0);
- if( rc!=SQLITE_OK ) return rc;
- sqlite3_reset(pStmt);
+SQLITE_PRIVATE int sqlite3Fts3ReadLock(Fts3Table *p){
+ int rc; /* Return code */
+ sqlite3_stmt *pStmt; /* Statement used to obtain lock */
- if( pzBlock ){
- sqlite3_bind_int64(pStmt, 1, iBlock);
- rc = sqlite3_step(pStmt);
- if( rc!=SQLITE_ROW ){
- return (rc==SQLITE_DONE ? SQLITE_CORRUPT : rc);
- }
-
- *pnBlock = sqlite3_column_bytes(pStmt, 0);
- *pzBlock = (char *)sqlite3_column_blob(pStmt, 0);
- if( sqlite3_column_type(pStmt, 0)!=SQLITE_BLOB ){
- return SQLITE_CORRUPT;
- }
+ rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pStmt, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_null(pStmt, 1);
+ sqlite3_step(pStmt);
+ rc = sqlite3_reset(pStmt);
}
- return SQLITE_OK;
+ return rc;
}
/*
@@ -112653,10 +115289,10 @@ static int fts3PendingListAppend(
** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code.
*/
static int fts3PendingTermsAdd(
- Fts3Table *p, /* FTS table into which text will be inserted */
- const char *zText, /* Text of document to be inseted */
- int iCol, /* Column number into which text is inserted */
- u32 *pnWord /* OUT: Number of tokens inserted */
+ Fts3Table *p, /* Table into which text will be inserted */
+ const char *zText, /* Text of document to be inserted */
+ int iCol, /* Column into which text is being inserted */
+ u32 *pnWord /* OUT: Number of tokens inserted */
){
int rc;
int iStart;
@@ -112741,6 +115377,9 @@ static int fts3PendingTermsDocid(Fts3Table *p, sqlite_int64 iDocid){
return SQLITE_OK;
}
+/*
+** Discard the contents of the pending-terms hash table.
+*/
SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *p){
Fts3HashElem *pElem;
for(pElem=fts3HashFirst(&p->pendingTerms); pElem; pElem=fts3HashNext(pElem)){
@@ -112768,6 +115407,7 @@ static int fts3InsertTerms(Fts3Table *p, sqlite3_value **apVal, u32 *aSz){
return rc;
}
}
+ aSz[p->nColumn] += sqlite3_value_bytes(apVal[i]);
}
return SQLITE_OK;
}
@@ -112855,6 +115495,8 @@ static int fts3DeleteAll(Fts3Table *p){
fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGDIR, 0);
if( p->bHasDocsize ){
fts3SqlExec(&rc, p, SQL_DELETE_ALL_DOCSIZE, 0);
+ }
+ if( p->bHasStat ){
fts3SqlExec(&rc, p, SQL_DELETE_ALL_STAT, 0);
}
return rc;
@@ -112865,7 +115507,7 @@ static int fts3DeleteAll(Fts3Table *p){
** (an integer) of a row about to be deleted. Remove all terms from the
** full-text index.
*/
-static void fts3DeleteTerms(
+static void fts3DeleteTerms(
int *pRC, /* Result code */
Fts3Table *p, /* The FTS table to delete from */
sqlite3_value **apVal, /* apVal[] contains the docid to be deleted */
@@ -112887,6 +115529,7 @@ static void fts3DeleteTerms(
*pRC = rc;
return;
}
+ aSz[p->nColumn] += sqlite3_column_bytes(pSelect, i);
}
}
rc = sqlite3_reset(pSelect);
@@ -112950,11 +115593,92 @@ static int fts3AllocateSegdirIdx(Fts3Table *p, int iLevel, int *piIdx){
}
/*
+** The %_segments table is declared as follows:
+**
+** CREATE TABLE %_segments(blockid INTEGER PRIMARY KEY, block BLOB)
+**
+** This function reads data from a single row of the %_segments table. The
+** specific row is identified by the iBlockid parameter. If paBlob is not
+** NULL, then a buffer is allocated using sqlite3_malloc() and populated
+** with the contents of the blob stored in the "block" column of the
+** identified table row is. Whether or not paBlob is NULL, *pnBlob is set
+** to the size of the blob in bytes before returning.
+**
+** If an error occurs, or the table does not contain the specified row,
+** an SQLite error code is returned. Otherwise, SQLITE_OK is returned. If
+** paBlob is non-NULL, then it is the responsibility of the caller to
+** eventually free the returned buffer.
+**
+** This function may leave an open sqlite3_blob* handle in the
+** Fts3Table.pSegments variable. This handle is reused by subsequent calls
+** to this function. The handle may be closed by calling the
+** sqlite3Fts3SegmentsClose() function. Reusing a blob handle is a handy
+** performance improvement, but the blob handle should always be closed
+** before control is returned to the user (to prevent a lock being held
+** on the database file for longer than necessary). Thus, any virtual table
+** method (xFilter etc.) that may directly or indirectly call this function
+** must call sqlite3Fts3SegmentsClose() before returning.
+*/
+SQLITE_PRIVATE int sqlite3Fts3ReadBlock(
+ Fts3Table *p, /* FTS3 table handle */
+ sqlite3_int64 iBlockid, /* Access the row with blockid=$iBlockid */
+ char **paBlob, /* OUT: Blob data in malloc'd buffer */
+ int *pnBlob /* OUT: Size of blob data */
+){
+ int rc; /* Return code */
+
+ /* pnBlob must be non-NULL. paBlob may be NULL or non-NULL. */
+ assert( pnBlob);
+
+ if( p->pSegments ){
+ rc = sqlite3_blob_reopen(p->pSegments, iBlockid);
+ }else{
+ if( 0==p->zSegmentsTbl ){
+ p->zSegmentsTbl = sqlite3_mprintf("%s_segments", p->zName);
+ if( 0==p->zSegmentsTbl ) return SQLITE_NOMEM;
+ }
+ rc = sqlite3_blob_open(
+ p->db, p->zDb, p->zSegmentsTbl, "block", iBlockid, 0, &p->pSegments
+ );
+ }
+
+ if( rc==SQLITE_OK ){
+ int nByte = sqlite3_blob_bytes(p->pSegments);
+ if( paBlob ){
+ char *aByte = sqlite3_malloc(nByte + FTS3_NODE_PADDING);
+ if( !aByte ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_blob_read(p->pSegments, aByte, nByte, 0);
+ memset(&aByte[nByte], 0, FTS3_NODE_PADDING);
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(aByte);
+ aByte = 0;
+ }
+ }
+ *paBlob = aByte;
+ }
+ *pnBlob = nByte;
+ }
+
+ return rc;
+}
+
+/*
+** Close the blob handle at p->pSegments, if it is open. See comments above
+** the sqlite3Fts3ReadBlock() function for details.
+*/
+SQLITE_PRIVATE void sqlite3Fts3SegmentsClose(Fts3Table *p){
+ sqlite3_blob_close(p->pSegments);
+ p->pSegments = 0;
+}
+
+/*
** Move the iterator passed as the first argument to the next term in the
** segment. If successful, SQLITE_OK is returned. If there is no next term,
** SQLITE_DONE. Otherwise, an SQLite error code.
*/
-static int fts3SegReaderNext(Fts3SegReader *pReader){
+static int fts3SegReaderNext(Fts3Table *p, Fts3SegReader *pReader){
char *pNext; /* Cursor variable */
int nPrefix; /* Number of bytes in term prefix */
int nSuffix; /* Number of bytes in term suffix */
@@ -112966,7 +115690,8 @@ static int fts3SegReaderNext(Fts3SegReader *pReader){
}
if( !pNext || pNext>=&pReader->aNode[pReader->nNode] ){
- int rc;
+ int rc; /* Return code from Fts3ReadBlock() */
+
if( fts3SegReaderIsPending(pReader) ){
Fts3HashElem *pElem = *(pReader->ppNextElem);
if( pElem==0 ){
@@ -112982,22 +115707,36 @@ static int fts3SegReaderNext(Fts3SegReader *pReader){
}
return SQLITE_OK;
}
- if( !pReader->pStmt ){
- pReader->aNode = 0;
- return SQLITE_OK;
+
+ if( !fts3SegReaderIsRootOnly(pReader) ){
+ sqlite3_free(pReader->aNode);
}
- rc = sqlite3_step(pReader->pStmt);
- if( rc!=SQLITE_ROW ){
- pReader->aNode = 0;
- return (rc==SQLITE_DONE ? SQLITE_OK : rc);
+ pReader->aNode = 0;
+
+ /* If iCurrentBlock>=iLeafEndBlock, this is an EOF condition. All leaf
+ ** blocks have already been traversed. */
+ assert( pReader->iCurrentBlock<=pReader->iLeafEndBlock );
+ if( pReader->iCurrentBlock>=pReader->iLeafEndBlock ){
+ return SQLITE_OK;
}
- pReader->nNode = sqlite3_column_bytes(pReader->pStmt, 0);
- pReader->aNode = (char *)sqlite3_column_blob(pReader->pStmt, 0);
+
+ rc = sqlite3Fts3ReadBlock(
+ p, ++pReader->iCurrentBlock, &pReader->aNode, &pReader->nNode
+ );
+ if( rc!=SQLITE_OK ) return rc;
pNext = pReader->aNode;
}
+ /* Because of the FTS3_NODE_PADDING bytes of padding, the following is
+ ** safe (no risk of overread) even if the node data is corrupted.
+ */
pNext += sqlite3Fts3GetVarint32(pNext, &nPrefix);
pNext += sqlite3Fts3GetVarint32(pNext, &nSuffix);
+ if( nPrefix<0 || nSuffix<=0
+ || &pNext[nSuffix]>&pReader->aNode[pReader->nNode]
+ ){
+ return SQLITE_CORRUPT;
+ }
if( nPrefix+nSuffix>pReader->nTermAlloc ){
int nNew = (nPrefix+nSuffix)*2;
@@ -113012,9 +115751,18 @@ static int fts3SegReaderNext(Fts3SegReader *pReader){
pReader->nTerm = nPrefix+nSuffix;
pNext += nSuffix;
pNext += sqlite3Fts3GetVarint32(pNext, &pReader->nDoclist);
- assert( pNext<&pReader->aNode[pReader->nNode] );
pReader->aDoclist = pNext;
pReader->pOffsetList = 0;
+
+ /* Check that the doclist does not appear to extend past the end of the
+ ** b-tree node. And that the final byte of the doclist is 0x00. If either
+ ** of these statements is untrue, then the data structure is corrupt.
+ */
+ if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode]
+ || pReader->aDoclist[pReader->nDoclist-1]
+ ){
+ return SQLITE_CORRUPT;
+ }
return SQLITE_OK;
}
@@ -113078,31 +115826,109 @@ static void fts3SegReaderNextDocid(
}
/*
-** Free all allocations associated with the iterator passed as the
-** second argument.
+** This function is called to estimate the amount of data that will be
+** loaded from the disk If SegReaderIterate() is called on this seg-reader,
+** in units of average document size.
+**
+** This can be used as follows: If the caller has a small doclist that
+** contains references to N documents, and is considering merging it with
+** a large doclist (size X "average documents"), it may opt not to load
+** the large doclist if X>N.
*/
-SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3Table *p, Fts3SegReader *pReader){
- if( pReader ){
- if( pReader->pStmt ){
- /* Move the leaf-range SELECT statement to the aLeavesStmt[] array,
- ** so that it can be reused when required by another query.
+SQLITE_PRIVATE int sqlite3Fts3SegReaderCost(
+ Fts3Cursor *pCsr, /* FTS3 cursor handle */
+ Fts3SegReader *pReader, /* Segment-reader handle */
+ int *pnCost /* IN/OUT: Number of bytes read */
+){
+ Fts3Table *p = (Fts3Table*)pCsr->base.pVtab;
+ int rc = SQLITE_OK; /* Return code */
+ int nCost = 0; /* Cost in bytes to return */
+ int pgsz = p->nPgsz; /* Database page size */
+
+ /* If this seg-reader is reading the pending-terms table, or if all data
+ ** for the segment is stored on the root page of the b-tree, then the cost
+ ** is zero. In this case all required data is already in main memory.
+ */
+ if( p->bHasStat
+ && !fts3SegReaderIsPending(pReader)
+ && !fts3SegReaderIsRootOnly(pReader)
+ ){
+ int nBlob = 0;
+ sqlite3_int64 iBlock;
+
+ if( pCsr->nRowAvg==0 ){
+ /* The average document size, which is required to calculate the cost
+ ** of each doclist, has not yet been determined. Read the required
+ ** data from the %_stat table to calculate it.
+ **
+ ** Entry 0 of the %_stat table is a blob containing (nCol+1) FTS3
+ ** varints, where nCol is the number of columns in the FTS3 table.
+ ** The first varint is the number of documents currently stored in
+ ** the table. The following nCol varints contain the total amount of
+ ** data stored in all rows of each column of the table, from left
+ ** to right.
*/
- assert( p->nLeavesStmt<p->nLeavesTotal );
- sqlite3_reset(pReader->pStmt);
- p->aLeavesStmt[p->nLeavesStmt++] = pReader->pStmt;
+ sqlite3_stmt *pStmt;
+ sqlite3_int64 nDoc = 0;
+ sqlite3_int64 nByte = 0;
+ const char *a;
+ rc = sqlite3Fts3SelectDoctotal(p, &pStmt);
+ if( rc ) return rc;
+ a = sqlite3_column_blob(pStmt, 0);
+ if( a ){
+ const char *pEnd = &a[sqlite3_column_bytes(pStmt, 0)];
+ a += sqlite3Fts3GetVarint(a, &nDoc);
+ while( a<pEnd ){
+ a += sqlite3Fts3GetVarint(a, &nByte);
+ }
+ }
+ if( nDoc==0 || nByte==0 ){
+ sqlite3_reset(pStmt);
+ return SQLITE_CORRUPT;
+ }
+
+ pCsr->nRowAvg = (int)(((nByte / nDoc) + pgsz) / pgsz);
+ assert( pCsr->nRowAvg>0 );
+ rc = sqlite3_reset(pStmt);
+ if( rc!=SQLITE_OK ) return rc;
+ }
+
+ /* Assume that a blob flows over onto overflow pages if it is larger
+ ** than (pgsz-35) bytes in size (the file-format documentation
+ ** confirms this).
+ */
+ for(iBlock=pReader->iStartBlock; iBlock<=pReader->iLeafEndBlock; iBlock++){
+ rc = sqlite3Fts3ReadBlock(p, iBlock, 0, &nBlob);
+ if( rc!=SQLITE_OK ) break;
+ if( (nBlob+35)>pgsz ){
+ int nOvfl = (nBlob + 34)/pgsz;
+ nCost += ((nOvfl + pCsr->nRowAvg - 1)/pCsr->nRowAvg);
+ }
}
- if( !fts3SegReaderIsPending(pReader) ){
- sqlite3_free(pReader->zTerm);
+ }
+
+ *pnCost += nCost;
+ return rc;
+}
+
+/*
+** Free all allocations associated with the iterator passed as the
+** second argument.
+*/
+SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){
+ if( pReader && !fts3SegReaderIsPending(pReader) ){
+ sqlite3_free(pReader->zTerm);
+ if( !fts3SegReaderIsRootOnly(pReader) ){
+ sqlite3_free(pReader->aNode);
}
- sqlite3_free(pReader);
}
+ sqlite3_free(pReader);
}
/*
** Allocate a new SegReader object.
*/
SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
- Fts3Table *p, /* Virtual table handle */
int iAge, /* Segment "age". */
sqlite3_int64 iStartLeaf, /* First leaf to traverse */
sqlite3_int64 iEndLeaf, /* Final leaf to traverse */
@@ -113115,8 +115941,9 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
Fts3SegReader *pReader; /* Newly allocated SegReader object */
int nExtra = 0; /* Bytes to allocate segment root node */
+ assert( iStartLeaf<=iEndLeaf );
if( iStartLeaf==0 ){
- nExtra = nRoot;
+ nExtra = nRoot + FTS3_NODE_PADDING;
}
pReader = (Fts3SegReader *)sqlite3_malloc(sizeof(Fts3SegReader) + nExtra);
@@ -113124,8 +115951,9 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
return SQLITE_NOMEM;
}
memset(pReader, 0, sizeof(Fts3SegReader));
- pReader->iStartBlock = iStartLeaf;
pReader->iIdx = iAge;
+ pReader->iStartBlock = iStartLeaf;
+ pReader->iLeafEndBlock = iEndLeaf;
pReader->iEndBlock = iEndBlock;
if( nExtra ){
@@ -113133,59 +115961,15 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
pReader->aNode = (char *)&pReader[1];
pReader->nNode = nRoot;
memcpy(pReader->aNode, zRoot, nRoot);
+ memset(&pReader->aNode[nRoot], 0, FTS3_NODE_PADDING);
}else{
- /* If the text of the SQL statement to iterate through a contiguous
- ** set of entries in the %_segments table has not yet been composed,
- ** compose it now.
- */
- if( !p->zSelectLeaves ){
- p->zSelectLeaves = sqlite3_mprintf(
- "SELECT block FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ? "
- "ORDER BY blockid", p->zDb, p->zName
- );
- if( !p->zSelectLeaves ){
- rc = SQLITE_NOMEM;
- goto finished;
- }
- }
-
- /* If there are no free statements in the aLeavesStmt[] array, prepare
- ** a new statement now. Otherwise, reuse a prepared statement from
- ** aLeavesStmt[].
- */
- if( p->nLeavesStmt==0 ){
- if( p->nLeavesTotal==p->nLeavesAlloc ){
- int nNew = p->nLeavesAlloc + 16;
- sqlite3_stmt **aNew = (sqlite3_stmt **)sqlite3_realloc(
- p->aLeavesStmt, nNew*sizeof(sqlite3_stmt *)
- );
- if( !aNew ){
- rc = SQLITE_NOMEM;
- goto finished;
- }
- p->nLeavesAlloc = nNew;
- p->aLeavesStmt = aNew;
- }
- rc = sqlite3_prepare_v2(p->db, p->zSelectLeaves, -1, &pReader->pStmt, 0);
- if( rc!=SQLITE_OK ){
- goto finished;
- }
- p->nLeavesTotal++;
- }else{
- pReader->pStmt = p->aLeavesStmt[--p->nLeavesStmt];
- }
-
- /* Bind the start and end leaf blockids to the prepared SQL statement. */
- sqlite3_bind_int64(pReader->pStmt, 1, iStartLeaf);
- sqlite3_bind_int64(pReader->pStmt, 2, iEndLeaf);
+ pReader->iCurrentBlock = iStartLeaf-1;
}
- rc = fts3SegReaderNext(pReader);
- finished:
if( rc==SQLITE_OK ){
*ppReader = pReader;
}else{
- sqlite3Fts3SegReaderFree(p, pReader);
+ sqlite3Fts3SegReaderFree(pReader);
}
return rc;
}
@@ -113276,7 +116060,6 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
pReader->iIdx = 0x7FFFFFFF;
pReader->ppNextElem = (Fts3HashElem **)&pReader[1];
memcpy(pReader->ppNextElem, aElem, nElem*sizeof(Fts3HashElem *));
- fts3SegReaderNext(pReader);
}
}
@@ -113309,12 +116092,11 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
** code is returned.
*/
static int fts3SegReaderNew(
- Fts3Table *p, /* Virtual table handle */
sqlite3_stmt *pStmt, /* See above */
int iAge, /* Segment "age". */
Fts3SegReader **ppReader /* OUT: Allocated Fts3SegReader */
){
- return sqlite3Fts3SegReaderNew(p, iAge,
+ return sqlite3Fts3SegReaderNew(iAge,
sqlite3_column_int64(pStmt, 1),
sqlite3_column_int64(pStmt, 2),
sqlite3_column_int64(pStmt, 3),
@@ -113518,7 +116300,7 @@ static int fts3PrefixCompress(
** (according to memcmp) than the previous term.
*/
static int fts3NodeAddTerm(
- Fts3Table *p, /* Virtual table handle */
+ Fts3Table *p, /* Virtual table handle */
SegmentNode **ppTree, /* IN/OUT: SegmentNode handle */
int isCopyTerm, /* True if zTerm/nTerm is transient */
const char *zTerm, /* Pointer to buffer containing term */
@@ -114148,15 +116930,14 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderIterate(
** unnecessary merge/sort operations for the case where single segment
** b-tree leaf nodes contain more than one term.
*/
- if( pFilter->zTerm ){
+ for(i=0; i<nSegment; i++){
int nTerm = pFilter->nTerm;
const char *zTerm = pFilter->zTerm;
- for(i=0; i<nSegment; i++){
- Fts3SegReader *pSeg = apSegment[i];
- while( fts3SegReaderTermCmp(pSeg, zTerm, nTerm)<0 ){
- rc = fts3SegReaderNext(pSeg);
- if( rc!=SQLITE_OK ) goto finished; }
- }
+ Fts3SegReader *pSeg = apSegment[i];
+ do {
+ rc = fts3SegReaderNext(p, pSeg);
+ if( rc!=SQLITE_OK ) goto finished;
+ }while( zTerm && fts3SegReaderTermCmp(pSeg, zTerm, nTerm)<0 );
}
fts3SegReaderSort(apSegment, nSegment, nSegment, fts3SegReaderCmp);
@@ -114230,7 +117011,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderIterate(
nByte = sqlite3Fts3VarintLen(iDocid-iPrev) + (isRequirePos?nList+1:0);
if( nDoclist+nByte>nAlloc ){
char *aNew;
- nAlloc = nDoclist+nByte*2;
+ nAlloc = (nDoclist+nByte)*2;
aNew = sqlite3_realloc(aBuffer, nAlloc);
if( !aNew ){
rc = SQLITE_NOMEM;
@@ -114265,7 +117046,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderIterate(
}
for(i=0; i<nMerge; i++){
- rc = fts3SegReaderNext(apSegment[i]);
+ rc = fts3SegReaderNext(p, apSegment[i]);
if( rc!=SQLITE_OK ) goto finished;
}
fts3SegReaderSort(apSegment, nSegment, nMerge, fts3SegReaderCmp);
@@ -114291,7 +117072,7 @@ static int fts3SegmentMerge(Fts3Table *p, int iLevel){
int i; /* Iterator variable */
int rc; /* Return code */
int iIdx; /* Index of new segment */
- int iNewLevel; /* Level to create new segment at */
+ int iNewLevel = 0; /* Level to create new segment at */
sqlite3_stmt *pStmt = 0;
SegmentWriter *pWriter = 0;
int nSegment = 0; /* Number of segments being merged */
@@ -114346,7 +117127,7 @@ static int fts3SegmentMerge(Fts3Table *p, int iLevel){
if( rc!=SQLITE_OK ) goto finished;
sqlite3_bind_int(pStmt, 1, iLevel);
for(i=0; SQLITE_ROW==(sqlite3_step(pStmt)); i++){
- rc = fts3SegReaderNew(p, pStmt, i, &apSegment[i]);
+ rc = fts3SegReaderNew(pStmt, i, &apSegment[i]);
if( rc!=SQLITE_OK ){
goto finished;
}
@@ -114376,11 +117157,11 @@ static int fts3SegmentMerge(Fts3Table *p, int iLevel){
fts3SegWriterFree(pWriter);
if( apSegment ){
for(i=0; i<nSegment; i++){
- sqlite3Fts3SegReaderFree(p, apSegment[i]);
+ sqlite3Fts3SegReaderFree(apSegment[i]);
}
sqlite3_free(apSegment);
}
- sqlite3Fts3SegReaderFree(p, pPending);
+ sqlite3Fts3SegReaderFree(pPending);
sqlite3_reset(pStmt);
return rc;
}
@@ -114433,7 +117214,7 @@ SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){
rc = fts3SegWriterFlush(p, pWriter, 0, idx);
}
fts3SegWriterFree(pWriter);
- sqlite3Fts3SegReaderFree(p, pReader);
+ sqlite3Fts3SegReaderFree(pReader);
if( rc==SQLITE_OK ){
sqlite3Fts3PendingTermsClear(p);
@@ -114477,75 +117258,6 @@ static void fts3DecodeIntArray(
}
/*
-** Fill in the document size auxiliary information for the matchinfo
-** structure. The auxiliary information is:
-**
-** N Total number of documents in the full-text index
-** a0 Average length of column 0 over the whole index
-** n0 Length of column 0 on the matching row
-** ...
-** aM Average length of column M over the whole index
-** nM Length of column M on the matching row
-**
-** The fts3MatchinfoDocsizeLocal() routine fills in the nX values.
-** The fts3MatchinfoDocsizeGlobal() routine fills in N and the aX values.
-*/
-SQLITE_PRIVATE int sqlite3Fts3MatchinfoDocsizeLocal(Fts3Cursor *pCur, u32 *a){
- const char *pBlob; /* The BLOB holding %_docsize info */
- int nBlob; /* Size of the BLOB */
- sqlite3_stmt *pStmt; /* Statement for reading and writing */
- int i, j; /* Loop counters */
- sqlite3_int64 x; /* Varint value */
- int rc; /* Result code from subfunctions */
- Fts3Table *p; /* The FTS table */
-
- p = (Fts3Table*)pCur->base.pVtab;
- rc = fts3SqlStmt(p, SQL_SELECT_DOCSIZE, &pStmt, 0);
- if( rc ){
- return rc;
- }
- sqlite3_bind_int64(pStmt, 1, pCur->iPrevId);
- if( sqlite3_step(pStmt)==SQLITE_ROW ){
- nBlob = sqlite3_column_bytes(pStmt, 0);
- pBlob = (const char*)sqlite3_column_blob(pStmt, 0);
- for(i=j=0; i<p->nColumn && j<nBlob; i++){
- j = sqlite3Fts3GetVarint(&pBlob[j], &x);
- a[2+i*2] = (u32)(x & 0xffffffff);
- }
- }
- sqlite3_reset(pStmt);
- return SQLITE_OK;
-}
-SQLITE_PRIVATE int sqlite3Fts3MatchinfoDocsizeGlobal(Fts3Cursor *pCur, u32 *a){
- const char *pBlob; /* The BLOB holding %_stat info */
- int nBlob; /* Size of the BLOB */
- sqlite3_stmt *pStmt; /* Statement for reading and writing */
- int i, j; /* Loop counters */
- sqlite3_int64 x; /* Varint value */
- int nDoc; /* Number of documents */
- int rc; /* Result code from subfunctions */
- Fts3Table *p; /* The FTS table */
-
- p = (Fts3Table*)pCur->base.pVtab;
- rc = fts3SqlStmt(p, SQL_SELECT_DOCTOTAL, &pStmt, 0);
- if( rc ){
- return rc;
- }
- if( sqlite3_step(pStmt)==SQLITE_ROW ){
- nBlob = sqlite3_column_bytes(pStmt, 0);
- pBlob = (const char*)sqlite3_column_blob(pStmt, 0);
- j = sqlite3Fts3GetVarint(pBlob, &x);
- a[0] = nDoc = (u32)(x & 0xffffffff);
- for(i=0; i<p->nColumn && j<nBlob; i++){
- j = sqlite3Fts3GetVarint(&pBlob[j], &x);
- a[1+i*2] = ((u32)(x & 0xffffffff) + nDoc/2)/nDoc;
- }
- }
- sqlite3_reset(pStmt);
- return SQLITE_OK;
-}
-
-/*
** Insert the sizes (in tokens) for each column of the document
** with docid equal to p->iPrevDocid. The sizes are encoded as
** a blob of varints.
@@ -114580,16 +117292,26 @@ static void fts3InsertDocsize(
}
/*
-** Update the 0 record of the %_stat table so that it holds a blob
-** which contains the document count followed by the cumulative
-** document sizes for all columns.
+** Record 0 of the %_stat table contains a blob consisting of N varints,
+** where N is the number of user defined columns in the fts3 table plus
+** two. If nCol is the number of user defined columns, then values of the
+** varints are set as follows:
+**
+** Varint 0: Total number of rows in the table.
+**
+** Varint 1..nCol: For each column, the total number of tokens stored in
+** the column for all rows of the table.
+**
+** Varint 1+nCol: The total size, in bytes, of all text values in all
+** columns of all rows of the table.
+**
*/
static void fts3UpdateDocTotals(
- int *pRC, /* The result code */
- Fts3Table *p, /* Table being updated */
- u32 *aSzIns, /* Size increases */
- u32 *aSzDel, /* Size decreases */
- int nChng /* Change in the number of documents */
+ int *pRC, /* The result code */
+ Fts3Table *p, /* Table being updated */
+ u32 *aSzIns, /* Size increases */
+ u32 *aSzDel, /* Size decreases */
+ int nChng /* Change in the number of documents */
){
char *pBlob; /* Storage for BLOB written into %_stat */
int nBlob; /* Size of BLOB written into %_stat */
@@ -114598,13 +117320,15 @@ static void fts3UpdateDocTotals(
int i; /* Loop counter */
int rc; /* Result code from subfunctions */
+ const int nStat = p->nColumn+2;
+
if( *pRC ) return;
- a = sqlite3_malloc( (sizeof(u32)+10)*(p->nColumn+1) );
+ a = sqlite3_malloc( (sizeof(u32)+10)*nStat );
if( a==0 ){
*pRC = SQLITE_NOMEM;
return;
}
- pBlob = (char*)&a[p->nColumn+1];
+ pBlob = (char*)&a[nStat];
rc = fts3SqlStmt(p, SQL_SELECT_DOCTOTAL, &pStmt, 0);
if( rc ){
sqlite3_free(a);
@@ -114612,11 +117336,11 @@ static void fts3UpdateDocTotals(
return;
}
if( sqlite3_step(pStmt)==SQLITE_ROW ){
- fts3DecodeIntArray(p->nColumn+1, a,
+ fts3DecodeIntArray(nStat, a,
sqlite3_column_blob(pStmt, 0),
sqlite3_column_bytes(pStmt, 0));
}else{
- memset(a, 0, sizeof(u32)*(p->nColumn+1) );
+ memset(a, 0, sizeof(u32)*(nStat) );
}
sqlite3_reset(pStmt);
if( nChng<0 && a[0]<(u32)(-nChng) ){
@@ -114624,7 +117348,7 @@ static void fts3UpdateDocTotals(
}else{
a[0] += nChng;
}
- for(i=0; i<p->nColumn; i++){
+ for(i=0; i<p->nColumn+1; i++){
u32 x = a[i+1];
if( x+aSzIns[i] < aSzDel[i] ){
x = 0;
@@ -114633,7 +117357,7 @@ static void fts3UpdateDocTotals(
}
a[i+1] = x;
}
- fts3EncodeIntArray(p->nColumn+1, a, pBlob, &nBlob);
+ fts3EncodeIntArray(nStat, a, pBlob, &nBlob);
rc = fts3SqlStmt(p, SQL_REPLACE_DOCTOTAL, &pStmt, 0);
if( rc ){
sqlite3_free(a);
@@ -114680,10 +117404,160 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
rc = SQLITE_ERROR;
}
+ sqlite3Fts3SegmentsClose(p);
return rc;
}
/*
+** Return the deferred doclist associated with deferred token pDeferred.
+** This function assumes that sqlite3Fts3CacheDeferredDoclists() has already
+** been called to allocate and populate the doclist.
+*/
+SQLITE_PRIVATE char *sqlite3Fts3DeferredDoclist(Fts3DeferredToken *pDeferred, int *pnByte){
+ if( pDeferred->pList ){
+ *pnByte = pDeferred->pList->nData;
+ return pDeferred->pList->aData;
+ }
+ *pnByte = 0;
+ return 0;
+}
+
+/*
+** Helper fucntion for FreeDeferredDoclists(). This function removes all
+** references to deferred doclists from within the tree of Fts3Expr
+** structures headed by
+*/
+static void fts3DeferredDoclistClear(Fts3Expr *pExpr){
+ if( pExpr ){
+ fts3DeferredDoclistClear(pExpr->pLeft);
+ fts3DeferredDoclistClear(pExpr->pRight);
+ if( pExpr->isLoaded ){
+ sqlite3_free(pExpr->aDoclist);
+ pExpr->isLoaded = 0;
+ pExpr->aDoclist = 0;
+ pExpr->nDoclist = 0;
+ pExpr->pCurrent = 0;
+ pExpr->iCurrent = 0;
+ }
+ }
+}
+
+/*
+** Delete all cached deferred doclists. Deferred doclists are cached
+** (allocated) by the sqlite3Fts3CacheDeferredDoclists() function.
+*/
+SQLITE_PRIVATE void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *pCsr){
+ Fts3DeferredToken *pDef;
+ for(pDef=pCsr->pDeferred; pDef; pDef=pDef->pNext){
+ sqlite3_free(pDef->pList);
+ pDef->pList = 0;
+ }
+ if( pCsr->pDeferred ){
+ fts3DeferredDoclistClear(pCsr->pExpr);
+ }
+}
+
+/*
+** Free all entries in the pCsr->pDeffered list. Entries are added to
+** this list using sqlite3Fts3DeferToken().
+*/
+SQLITE_PRIVATE void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *pCsr){
+ Fts3DeferredToken *pDef;
+ Fts3DeferredToken *pNext;
+ for(pDef=pCsr->pDeferred; pDef; pDef=pNext){
+ pNext = pDef->pNext;
+ sqlite3_free(pDef->pList);
+ sqlite3_free(pDef);
+ }
+ pCsr->pDeferred = 0;
+}
+
+/*
+** Generate deferred-doclists for all tokens in the pCsr->pDeferred list
+** based on the row that pCsr currently points to.
+**
+** A deferred-doclist is like any other doclist with position information
+** included, except that it only contains entries for a single row of the
+** table, not for all rows.
+*/
+SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){
+ int rc = SQLITE_OK; /* Return code */
+ if( pCsr->pDeferred ){
+ int i; /* Used to iterate through table columns */
+ sqlite3_int64 iDocid; /* Docid of the row pCsr points to */
+ Fts3DeferredToken *pDef; /* Used to iterate through deferred tokens */
+
+ Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
+ sqlite3_tokenizer *pT = p->pTokenizer;
+ sqlite3_tokenizer_module const *pModule = pT->pModule;
+
+ assert( pCsr->isRequireSeek==0 );
+ iDocid = sqlite3_column_int64(pCsr->pStmt, 0);
+
+ for(i=0; i<p->nColumn && rc==SQLITE_OK; i++){
+ const char *zText = (const char *)sqlite3_column_text(pCsr->pStmt, i+1);
+ sqlite3_tokenizer_cursor *pTC = 0;
+
+ rc = pModule->xOpen(pT, zText, -1, &pTC);
+ while( rc==SQLITE_OK ){
+ char const *zToken; /* Buffer containing token */
+ int nToken; /* Number of bytes in token */
+ int iDum1, iDum2; /* Dummy variables */
+ int iPos; /* Position of token in zText */
+
+ pTC->pTokenizer = pT;
+ rc = pModule->xNext(pTC, &zToken, &nToken, &iDum1, &iDum2, &iPos);
+ for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){
+ Fts3PhraseToken *pPT = pDef->pToken;
+ if( (pDef->iCol>=p->nColumn || pDef->iCol==i)
+ && (pPT->n==nToken || (pPT->isPrefix && pPT->n<nToken))
+ && (0==memcmp(zToken, pPT->z, pPT->n))
+ ){
+ fts3PendingListAppend(&pDef->pList, iDocid, i, iPos, &rc);
+ }
+ }
+ }
+ if( pTC ) pModule->xClose(pTC);
+ if( rc==SQLITE_DONE ) rc = SQLITE_OK;
+ }
+
+ for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){
+ if( pDef->pList ){
+ rc = fts3PendingListAppendVarint(&pDef->pList, 0);
+ }
+ }
+ }
+
+ return rc;
+}
+
+/*
+** Add an entry for token pToken to the pCsr->pDeferred list.
+*/
+SQLITE_PRIVATE int sqlite3Fts3DeferToken(
+ Fts3Cursor *pCsr, /* Fts3 table cursor */
+ Fts3PhraseToken *pToken, /* Token to defer */
+ int iCol /* Column that token must appear in (or -1) */
+){
+ Fts3DeferredToken *pDeferred;
+ pDeferred = sqlite3_malloc(sizeof(*pDeferred));
+ if( !pDeferred ){
+ return SQLITE_NOMEM;
+ }
+ memset(pDeferred, 0, sizeof(*pDeferred));
+ pDeferred->pToken = pToken;
+ pDeferred->pNext = pCsr->pDeferred;
+ pDeferred->iCol = iCol;
+ pCsr->pDeferred = pDeferred;
+
+ assert( pToken->pDeferred==0 );
+ pToken->pDeferred = pDeferred;
+
+ return SQLITE_OK;
+}
+
+
+/*
** This function does the work for the xUpdate method of FTS3 virtual
** tables.
*/
@@ -114701,16 +117575,17 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
u32 *aSzDel; /* Sizes of deleted documents */
int nChng = 0; /* Net change in number of documents */
+ assert( p->pSegments==0 );
/* Allocate space to hold the change in document sizes */
- aSzIns = sqlite3_malloc( sizeof(aSzIns[0])*p->nColumn*2 );
+ aSzIns = sqlite3_malloc( sizeof(aSzIns[0])*(p->nColumn+1)*2 );
if( aSzIns==0 ) return SQLITE_NOMEM;
- aSzDel = &aSzIns[p->nColumn];
- memset(aSzIns, 0, sizeof(aSzIns[0])*p->nColumn*2);
+ aSzDel = &aSzIns[p->nColumn+1];
+ memset(aSzIns, 0, sizeof(aSzIns[0])*(p->nColumn+1)*2);
/* If this is a DELETE or UPDATE operation, remove the old record. */
if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
- int isEmpty;
+ int isEmpty = 0;
rc = fts3IsEmpty(p, apVal, &isEmpty);
if( rc==SQLITE_OK ){
if( isEmpty ){
@@ -114727,8 +117602,8 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, apVal);
if( p->bHasDocsize ){
fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, apVal);
- nChng--;
}
+ nChng--;
}
}
}else if( sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL ){
@@ -114746,16 +117621,17 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
rc = fts3InsertTerms(p, apVal, aSzIns);
}
if( p->bHasDocsize ){
- nChng++;
fts3InsertDocsize(&rc, p, aSzIns);
}
+ nChng++;
}
- if( p->bHasDocsize ){
+ if( p->bHasStat ){
fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nChng);
}
sqlite3_free(aSzIns);
+ sqlite3Fts3SegmentsClose(p);
return rc;
}
@@ -114779,6 +117655,7 @@ SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){
sqlite3_exec(p->db, "RELEASE fts3", 0, 0, 0);
}
}
+ sqlite3Fts3SegmentsClose(p);
return rc;
}
@@ -114802,6 +117679,22 @@ SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
+/*
+** Characters that may appear in the second argument to matchinfo().
+*/
+#define FTS3_MATCHINFO_NPHRASE 'p' /* 1 value */
+#define FTS3_MATCHINFO_NCOL 'c' /* 1 value */
+#define FTS3_MATCHINFO_NDOC 'n' /* 1 value */
+#define FTS3_MATCHINFO_AVGLENGTH 'a' /* nCol values */
+#define FTS3_MATCHINFO_LENGTH 'l' /* nCol values */
+#define FTS3_MATCHINFO_LCS 's' /* nCol values */
+#define FTS3_MATCHINFO_HITS 'x' /* 3*nCol*nPhrase values */
+
+/*
+** The default value for the second argument to matchinfo().
+*/
+#define FTS3_MATCHINFO_DEFAULT "pcx"
+
/*
** Used as an fts3ExprIterate() context when loading phrase doclists to
@@ -114809,7 +117702,7 @@ SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){
*/
typedef struct LoadDoclistCtx LoadDoclistCtx;
struct LoadDoclistCtx {
- Fts3Table *pTab; /* FTS3 Table */
+ Fts3Cursor *pCsr; /* FTS3 Cursor */
int nPhrase; /* Number of phrases seen so far */
int nToken; /* Number of tokens seen so far */
};
@@ -114855,6 +117748,8 @@ typedef struct MatchInfo MatchInfo;
struct MatchInfo {
Fts3Cursor *pCursor; /* FTS3 Cursor */
int nCol; /* Number of columns in table */
+ int nPhrase; /* Number of matchable phrases in query */
+ sqlite3_int64 nDoc; /* Number of docs in database */
u32 *aMatchinfo; /* Pre-allocated buffer */
};
@@ -114993,7 +117888,7 @@ static int fts3ExprNearTrim(Fts3Expr *pExpr){
** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
** fts3ExprLoadDoclists().
*/
-static int fts3ExprLoadDoclistsCb1(Fts3Expr *pExpr, int iPhrase, void *ctx){
+static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
int rc = SQLITE_OK;
LoadDoclistCtx *p = (LoadDoclistCtx *)ctx;
@@ -115003,7 +117898,7 @@ static int fts3ExprLoadDoclistsCb1(Fts3Expr *pExpr, int iPhrase, void *ctx){
p->nToken += pExpr->pPhrase->nToken;
if( pExpr->isLoaded==0 ){
- rc = sqlite3Fts3ExprLoadDoclist(p->pTab, pExpr);
+ rc = sqlite3Fts3ExprLoadDoclist(p->pCsr, pExpr);
pExpr->isLoaded = 1;
if( rc==SQLITE_OK ){
rc = fts3ExprNearTrim(pExpr);
@@ -115014,22 +117909,6 @@ static int fts3ExprLoadDoclistsCb1(Fts3Expr *pExpr, int iPhrase, void *ctx){
}
/*
-** This is an fts3ExprIterate() callback used while loading the doclists
-** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
-** fts3ExprLoadDoclists().
-*/
-static int fts3ExprLoadDoclistsCb2(Fts3Expr *pExpr, int iPhrase, void *ctx){
- UNUSED_PARAMETER(iPhrase);
- UNUSED_PARAMETER(ctx);
- if( pExpr->aDoclist ){
- pExpr->pCurrent = pExpr->aDoclist;
- pExpr->iCurrent = 0;
- pExpr->pCurrent += sqlite3Fts3GetVarint(pExpr->pCurrent, &pExpr->iCurrent);
- }
- return SQLITE_OK;
-}
-
-/*
** Load the doclists for each phrase in the query associated with FTS3 cursor
** pCsr.
**
@@ -115046,16 +117925,25 @@ static int fts3ExprLoadDoclists(
){
int rc; /* Return Code */
LoadDoclistCtx sCtx = {0,0,0}; /* Context for fts3ExprIterate() */
- sCtx.pTab = (Fts3Table *)pCsr->base.pVtab;
- rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb1, (void *)&sCtx);
- if( rc==SQLITE_OK ){
- (void)fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb2, 0);
- }
+ sCtx.pCsr = pCsr;
+ rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb, (void *)&sCtx);
if( pnPhrase ) *pnPhrase = sCtx.nPhrase;
if( pnToken ) *pnToken = sCtx.nToken;
return rc;
}
+static int fts3ExprPhraseCountCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
+ (*(int *)ctx)++;
+ UNUSED_PARAMETER(pExpr);
+ UNUSED_PARAMETER(iPhrase);
+ return SQLITE_OK;
+}
+static int fts3ExprPhraseCount(Fts3Expr *pExpr){
+ int nPhrase = 0;
+ (void)fts3ExprIterate(pExpr, fts3ExprPhraseCountCb, (void *)&nPhrase);
+ return nPhrase;
+}
+
/*
** Advance the position list iterator specified by the first two
** arguments so that it points to the first element with a value greater
@@ -115568,38 +118456,87 @@ static void fts3LoadColumnlistCounts(char **pp, u32 *aOut, int isGlobal){
/*
** fts3ExprIterate() callback used to collect the "global" matchinfo stats
-** for a single query. The "global" stats are those elements of the matchinfo
-** array that are constant for all rows returned by the current query.
+** for a single query.
+**
+** fts3ExprIterate() callback to load the 'global' elements of a
+** FTS3_MATCHINFO_HITS matchinfo array. The global stats are those elements
+** of the matchinfo array that are constant for all rows returned by the
+** current query.
+**
+** Argument pCtx is actually a pointer to a struct of type MatchInfo. This
+** function populates Matchinfo.aMatchinfo[] as follows:
+**
+** for(iCol=0; iCol<nCol; iCol++){
+** aMatchinfo[3*iPhrase*nCol + 3*iCol + 1] = X;
+** aMatchinfo[3*iPhrase*nCol + 3*iCol + 2] = Y;
+** }
+**
+** where X is the number of matches for phrase iPhrase is column iCol of all
+** rows of the table. Y is the number of rows for which column iCol contains
+** at least one instance of phrase iPhrase.
+**
+** If the phrase pExpr consists entirely of deferred tokens, then all X and
+** Y values are set to nDoc, where nDoc is the number of documents in the
+** file system. This is done because the full-text index doclist is required
+** to calculate these values properly, and the full-text index doclist is
+** not available for deferred tokens.
*/
-static int fts3ExprGlobalMatchinfoCb(
+static int fts3ExprGlobalHitsCb(
Fts3Expr *pExpr, /* Phrase expression node */
int iPhrase, /* Phrase number (numbered from zero) */
void *pCtx /* Pointer to MatchInfo structure */
){
MatchInfo *p = (MatchInfo *)pCtx;
- char *pCsr;
+ Fts3Cursor *pCsr = p->pCursor;
+ char *pIter;
char *pEnd;
- const int iStart = 2 + (iPhrase * p->nCol * 3) + 1;
+ char *pFree = 0;
+ u32 *aOut = &p->aMatchinfo[3*iPhrase*p->nCol];
assert( pExpr->isLoaded );
+ assert( pExpr->eType==FTSQUERY_PHRASE );
+
+ if( pCsr->pDeferred ){
+ Fts3Phrase *pPhrase = pExpr->pPhrase;
+ int ii;
+ for(ii=0; ii<pPhrase->nToken; ii++){
+ if( pPhrase->aToken[ii].bFulltext ) break;
+ }
+ if( ii<pPhrase->nToken ){
+ int nFree = 0;
+ int rc = sqlite3Fts3ExprLoadFtDoclist(pCsr, pExpr, &pFree, &nFree);
+ if( rc!=SQLITE_OK ) return rc;
+ pIter = pFree;
+ pEnd = &pFree[nFree];
+ }else{
+ int iCol; /* Column index */
+ for(iCol=0; iCol<p->nCol; iCol++){
+ aOut[iCol*3 + 1] = (u32)p->nDoc;
+ aOut[iCol*3 + 2] = (u32)p->nDoc;
+ }
+ return SQLITE_OK;
+ }
+ }else{
+ pIter = pExpr->aDoclist;
+ pEnd = &pExpr->aDoclist[pExpr->nDoclist];
+ }
/* Fill in the global hit count matrix row for this phrase. */
- pCsr = pExpr->aDoclist;
- pEnd = &pExpr->aDoclist[pExpr->nDoclist];
- while( pCsr<pEnd ){
- while( *pCsr++ & 0x80 ); /* Skip past docid. */
- fts3LoadColumnlistCounts(&pCsr, &p->aMatchinfo[iStart], 1);
+ while( pIter<pEnd ){
+ while( *pIter++ & 0x80 ); /* Skip past docid. */
+ fts3LoadColumnlistCounts(&pIter, &aOut[1], 1);
}
+ sqlite3_free(pFree);
return SQLITE_OK;
}
/*
-** fts3ExprIterate() callback used to collect the "local" matchinfo stats
-** for a single query. The "local" stats are those elements of the matchinfo
+** fts3ExprIterate() callback used to collect the "local" part of the
+** FTS3_MATCHINFO_HITS array. The local stats are those elements of the
** array that are different for each row returned by the query.
*/
-static int fts3ExprLocalMatchinfoCb(
+static int fts3ExprLocalHitsCb(
Fts3Expr *pExpr, /* Phrase expression node */
int iPhrase, /* Phrase number */
void *pCtx /* Pointer to MatchInfo structure */
@@ -115608,7 +118545,7 @@ static int fts3ExprLocalMatchinfoCb(
if( pExpr->aDoclist ){
char *pCsr;
- int iStart = 2 + (iPhrase * p->nCol * 3);
+ int iStart = iPhrase * p->nCol * 3;
int i;
for(i=0; i<p->nCol; i++) p->aMatchinfo[iStart+i*3] = 0;
@@ -115622,67 +118559,400 @@ static int fts3ExprLocalMatchinfoCb(
return SQLITE_OK;
}
+static int fts3MatchinfoCheck(
+ Fts3Table *pTab,
+ char cArg,
+ char **pzErr
+){
+ if( (cArg==FTS3_MATCHINFO_NPHRASE)
+ || (cArg==FTS3_MATCHINFO_NCOL)
+ || (cArg==FTS3_MATCHINFO_NDOC && pTab->bHasStat)
+ || (cArg==FTS3_MATCHINFO_AVGLENGTH && pTab->bHasStat)
+ || (cArg==FTS3_MATCHINFO_LENGTH && pTab->bHasDocsize)
+ || (cArg==FTS3_MATCHINFO_LCS)
+ || (cArg==FTS3_MATCHINFO_HITS)
+ ){
+ return SQLITE_OK;
+ }
+ *pzErr = sqlite3_mprintf("unrecognized matchinfo request: %c", cArg);
+ return SQLITE_ERROR;
+}
+
+static int fts3MatchinfoSize(MatchInfo *pInfo, char cArg){
+ int nVal; /* Number of integers output by cArg */
+
+ switch( cArg ){
+ case FTS3_MATCHINFO_NDOC:
+ case FTS3_MATCHINFO_NPHRASE:
+ case FTS3_MATCHINFO_NCOL:
+ nVal = 1;
+ break;
+
+ case FTS3_MATCHINFO_AVGLENGTH:
+ case FTS3_MATCHINFO_LENGTH:
+ case FTS3_MATCHINFO_LCS:
+ nVal = pInfo->nCol;
+ break;
+
+ default:
+ assert( cArg==FTS3_MATCHINFO_HITS );
+ nVal = pInfo->nCol * pInfo->nPhrase * 3;
+ break;
+ }
+
+ return nVal;
+}
+
+static int fts3MatchinfoSelectDoctotal(
+ Fts3Table *pTab,
+ sqlite3_stmt **ppStmt,
+ sqlite3_int64 *pnDoc,
+ const char **paLen
+){
+ sqlite3_stmt *pStmt;
+ const char *a;
+ sqlite3_int64 nDoc;
+
+ if( !*ppStmt ){
+ int rc = sqlite3Fts3SelectDoctotal(pTab, ppStmt);
+ if( rc!=SQLITE_OK ) return rc;
+ }
+ pStmt = *ppStmt;
+ assert( sqlite3_data_count(pStmt)==1 );
+
+ a = sqlite3_column_blob(pStmt, 0);
+ a += sqlite3Fts3GetVarint(a, &nDoc);
+ *pnDoc = (u32)nDoc;
+
+ if( paLen ) *paLen = a;
+ return SQLITE_OK;
+}
+
+/*
+** An instance of the following structure is used to store state while
+** iterating through a multi-column position-list corresponding to the
+** hits for a single phrase on a single row in order to calculate the
+** values for a matchinfo() FTS3_MATCHINFO_LCS request.
+*/
+typedef struct LcsIterator LcsIterator;
+struct LcsIterator {
+ Fts3Expr *pExpr; /* Pointer to phrase expression */
+ char *pRead; /* Cursor used to iterate through aDoclist */
+ int iPosOffset; /* Tokens count up to end of this phrase */
+ int iCol; /* Current column number */
+ int iPos; /* Current position */
+};
+
+/*
+** If LcsIterator.iCol is set to the following value, the iterator has
+** finished iterating through all offsets for all columns.
+*/
+#define LCS_ITERATOR_FINISHED 0x7FFFFFFF;
+
+static int fts3MatchinfoLcsCb(
+ Fts3Expr *pExpr, /* Phrase expression node */
+ int iPhrase, /* Phrase number (numbered from zero) */
+ void *pCtx /* Pointer to MatchInfo structure */
+){
+ LcsIterator *aIter = (LcsIterator *)pCtx;
+ aIter[iPhrase].pExpr = pExpr;
+ return SQLITE_OK;
+}
+
+/*
+** Advance the iterator passed as an argument to the next position. Return
+** 1 if the iterator is at EOF or if it now points to the start of the
+** position list for the next column.
+*/
+static int fts3LcsIteratorAdvance(LcsIterator *pIter){
+ char *pRead = pIter->pRead;
+ sqlite3_int64 iRead;
+ int rc = 0;
+
+ pRead += sqlite3Fts3GetVarint(pRead, &iRead);
+ if( iRead==0 ){
+ pIter->iCol = LCS_ITERATOR_FINISHED;
+ rc = 1;
+ }else{
+ if( iRead==1 ){
+ pRead += sqlite3Fts3GetVarint(pRead, &iRead);
+ pIter->iCol = (int)iRead;
+ pIter->iPos = pIter->iPosOffset;
+ pRead += sqlite3Fts3GetVarint(pRead, &iRead);
+ rc = 1;
+ }
+ pIter->iPos += (int)(iRead-2);
+ }
+
+ pIter->pRead = pRead;
+ return rc;
+}
+
+/*
+** This function implements the FTS3_MATCHINFO_LCS matchinfo() flag.
+**
+** If the call is successful, the longest-common-substring lengths for each
+** column are written into the first nCol elements of the pInfo->aMatchinfo[]
+** array before returning. SQLITE_OK is returned in this case.
+**
+** Otherwise, if an error occurs, an SQLite error code is returned and the
+** data written to the first nCol elements of pInfo->aMatchinfo[] is
+** undefined.
+*/
+static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
+ LcsIterator *aIter;
+ int i;
+ int iCol;
+ int nToken = 0;
+
+ /* Allocate and populate the array of LcsIterator objects. The array
+ ** contains one element for each matchable phrase in the query.
+ **/
+ aIter = sqlite3_malloc(sizeof(LcsIterator) * pCsr->nPhrase);
+ if( !aIter ) return SQLITE_NOMEM;
+ memset(aIter, 0, sizeof(LcsIterator) * pCsr->nPhrase);
+ (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter);
+ for(i=0; i<pInfo->nPhrase; i++){
+ LcsIterator *pIter = &aIter[i];
+ nToken -= pIter->pExpr->pPhrase->nToken;
+ pIter->iPosOffset = nToken;
+ pIter->pRead = sqlite3Fts3FindPositions(pIter->pExpr, pCsr->iPrevId, -1);
+ if( pIter->pRead ){
+ pIter->iPos = pIter->iPosOffset;
+ fts3LcsIteratorAdvance(&aIter[i]);
+ }else{
+ pIter->iCol = LCS_ITERATOR_FINISHED;
+ }
+ }
+
+ for(iCol=0; iCol<pInfo->nCol; iCol++){
+ int nLcs = 0; /* LCS value for this column */
+ int nLive = 0; /* Number of iterators in aIter not at EOF */
+
+ /* Loop through the iterators in aIter[]. Set nLive to the number of
+ ** iterators that point to a position-list corresponding to column iCol.
+ */
+ for(i=0; i<pInfo->nPhrase; i++){
+ assert( aIter[i].iCol>=iCol );
+ if( aIter[i].iCol==iCol ) nLive++;
+ }
+
+ /* The following loop runs until all iterators in aIter[] have finished
+ ** iterating through positions in column iCol. Exactly one of the
+ ** iterators is advanced each time the body of the loop is run.
+ */
+ while( nLive>0 ){
+ LcsIterator *pAdv = 0; /* The iterator to advance by one position */
+ int nThisLcs = 0; /* LCS for the current iterator positions */
+
+ for(i=0; i<pInfo->nPhrase; i++){
+ LcsIterator *pIter = &aIter[i];
+ if( iCol!=pIter->iCol ){
+ /* This iterator is already at EOF for this column. */
+ nThisLcs = 0;
+ }else{
+ if( pAdv==0 || pIter->iPos<pAdv->iPos ){
+ pAdv = pIter;
+ }
+ if( nThisLcs==0 || pIter->iPos==pIter[-1].iPos ){
+ nThisLcs++;
+ }else{
+ nThisLcs = 1;
+ }
+ if( nThisLcs>nLcs ) nLcs = nThisLcs;
+ }
+ }
+ if( fts3LcsIteratorAdvance(pAdv) ) nLive--;
+ }
+
+ pInfo->aMatchinfo[iCol] = nLcs;
+ }
+
+ sqlite3_free(aIter);
+ return SQLITE_OK;
+}
+
+/*
+** Populate the buffer pInfo->aMatchinfo[] with an array of integers to
+** be returned by the matchinfo() function. Argument zArg contains the
+** format string passed as the second argument to matchinfo (or the
+** default value "pcx" if no second argument was specified). The format
+** string has already been validated and the pInfo->aMatchinfo[] array
+** is guaranteed to be large enough for the output.
+**
+** If bGlobal is true, then populate all fields of the matchinfo() output.
+** If it is false, then assume that those fields that do not change between
+** rows (i.e. FTS3_MATCHINFO_NPHRASE, NCOL, NDOC, AVGLENGTH and part of HITS)
+** have already been populated.
+**
+** Return SQLITE_OK if successful, or an SQLite error code if an error
+** occurs. If a value other than SQLITE_OK is returned, the state the
+** pInfo->aMatchinfo[] buffer is left in is undefined.
+*/
+static int fts3MatchinfoValues(
+ Fts3Cursor *pCsr, /* FTS3 cursor object */
+ int bGlobal, /* True to grab the global stats */
+ MatchInfo *pInfo, /* Matchinfo context object */
+ const char *zArg /* Matchinfo format string */
+){
+ int rc = SQLITE_OK;
+ int i;
+ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
+ sqlite3_stmt *pSelect = 0;
+
+ for(i=0; rc==SQLITE_OK && zArg[i]; i++){
+
+ switch( zArg[i] ){
+ case FTS3_MATCHINFO_NPHRASE:
+ if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nPhrase;
+ break;
+
+ case FTS3_MATCHINFO_NCOL:
+ if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nCol;
+ break;
+
+ case FTS3_MATCHINFO_NDOC:
+ if( bGlobal ){
+ sqlite3_int64 nDoc;
+ rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0);
+ pInfo->aMatchinfo[0] = (u32)nDoc;
+ }
+ break;
+
+ case FTS3_MATCHINFO_AVGLENGTH:
+ if( bGlobal ){
+ sqlite3_int64 nDoc; /* Number of rows in table */
+ const char *a; /* Aggregate column length array */
+
+ rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, &a);
+ if( rc==SQLITE_OK ){
+ int iCol;
+ for(iCol=0; iCol<pInfo->nCol; iCol++){
+ sqlite3_int64 nToken;
+ a += sqlite3Fts3GetVarint(a, &nToken);
+ pInfo->aMatchinfo[iCol] = (u32)(((u32)(nToken&0xffffffff)+nDoc/2)/nDoc);
+ }
+ }
+ }
+ break;
+
+ case FTS3_MATCHINFO_LENGTH: {
+ sqlite3_stmt *pSelectDocsize = 0;
+ rc = sqlite3Fts3SelectDocsize(pTab, pCsr->iPrevId, &pSelectDocsize);
+ if( rc==SQLITE_OK ){
+ int iCol;
+ const char *a = sqlite3_column_blob(pSelectDocsize, 0);
+ for(iCol=0; iCol<pInfo->nCol; iCol++){
+ sqlite3_int64 nToken;
+ a += sqlite3Fts3GetVarint(a, &nToken);
+ pInfo->aMatchinfo[iCol] = (u32)nToken;
+ }
+ }
+ sqlite3_reset(pSelectDocsize);
+ break;
+ }
+
+ case FTS3_MATCHINFO_LCS:
+ rc = fts3ExprLoadDoclists(pCsr, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = fts3MatchinfoLcs(pCsr, pInfo);
+ }
+ break;
+
+ default: {
+ Fts3Expr *pExpr;
+ assert( zArg[i]==FTS3_MATCHINFO_HITS );
+ pExpr = pCsr->pExpr;
+ rc = fts3ExprLoadDoclists(pCsr, 0, 0);
+ if( rc!=SQLITE_OK ) break;
+ if( bGlobal ){
+ if( pCsr->pDeferred ){
+ rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc, 0);
+ if( rc!=SQLITE_OK ) break;
+ }
+ rc = fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo);
+ if( rc!=SQLITE_OK ) break;
+ }
+ (void)fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo);
+ break;
+ }
+ }
+
+ pInfo->aMatchinfo += fts3MatchinfoSize(pInfo, zArg[i]);
+ }
+
+ sqlite3_reset(pSelect);
+ return rc;
+}
+
+
/*
** Populate pCsr->aMatchinfo[] with data for the current row. The
** 'matchinfo' data is an array of 32-bit unsigned integers (C type u32).
*/
-static int fts3GetMatchinfo(Fts3Cursor *pCsr){
+static int fts3GetMatchinfo(
+ Fts3Cursor *pCsr, /* FTS3 Cursor object */
+ const char *zArg /* Second argument to matchinfo() function */
+){
MatchInfo sInfo;
Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
int rc = SQLITE_OK;
+ int bGlobal = 0; /* Collect 'global' stats as well as local */
+ memset(&sInfo, 0, sizeof(MatchInfo));
sInfo.pCursor = pCsr;
sInfo.nCol = pTab->nColumn;
+ /* If there is cached matchinfo() data, but the format string for the
+ ** cache does not match the format string for this request, discard
+ ** the cached data. */
+ if( pCsr->zMatchinfo && strcmp(pCsr->zMatchinfo, zArg) ){
+ assert( pCsr->aMatchinfo );
+ sqlite3_free(pCsr->aMatchinfo);
+ pCsr->zMatchinfo = 0;
+ pCsr->aMatchinfo = 0;
+ }
+
+ /* If Fts3Cursor.aMatchinfo[] is NULL, then this is the first time the
+ ** matchinfo function has been called for this query. In this case
+ ** allocate the array used to accumulate the matchinfo data and
+ ** initialize those elements that are constant for every row.
+ */
if( pCsr->aMatchinfo==0 ){
- /* If Fts3Cursor.aMatchinfo[] is NULL, then this is the first time the
- ** matchinfo function has been called for this query. In this case
- ** allocate the array used to accumulate the matchinfo data and
- ** initialize those elements that are constant for every row.
- */
- int nPhrase; /* Number of phrases */
- int nMatchinfo; /* Number of u32 elements in match-info */
+ int nMatchinfo = 0; /* Number of u32 elements in match-info */
+ int nArg; /* Bytes in zArg */
+ int i; /* Used to iterate through zArg */
- /* Load doclists for each phrase in the query. */
- rc = fts3ExprLoadDoclists(pCsr, &nPhrase, 0);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- nMatchinfo = 2 + 3*sInfo.nCol*nPhrase;
- if( pTab->bHasDocsize ){
- nMatchinfo += 1 + 2*pTab->nColumn;
- }
+ /* Determine the number of phrases in the query */
+ pCsr->nPhrase = fts3ExprPhraseCount(pCsr->pExpr);
+ sInfo.nPhrase = pCsr->nPhrase;
- sInfo.aMatchinfo = (u32 *)sqlite3_malloc(sizeof(u32)*nMatchinfo);
- if( !sInfo.aMatchinfo ){
- return SQLITE_NOMEM;
+ /* Determine the number of integers in the buffer returned by this call. */
+ for(i=0; zArg[i]; i++){
+ nMatchinfo += fts3MatchinfoSize(&sInfo, zArg[i]);
}
- memset(sInfo.aMatchinfo, 0, sizeof(u32)*nMatchinfo);
+ /* Allocate space for Fts3Cursor.aMatchinfo[] and Fts3Cursor.zMatchinfo. */
+ nArg = (int)strlen(zArg);
+ pCsr->aMatchinfo = (u32 *)sqlite3_malloc(sizeof(u32)*nMatchinfo + nArg + 1);
+ if( !pCsr->aMatchinfo ) return SQLITE_NOMEM;
- /* First element of match-info is the number of phrases in the query */
- sInfo.aMatchinfo[0] = nPhrase;
- sInfo.aMatchinfo[1] = sInfo.nCol;
- (void)fts3ExprIterate(pCsr->pExpr, fts3ExprGlobalMatchinfoCb,(void*)&sInfo);
- if( pTab->bHasDocsize ){
- int ofst = 2 + 3*sInfo.aMatchinfo[0]*sInfo.aMatchinfo[1];
- rc = sqlite3Fts3MatchinfoDocsizeGlobal(pCsr, &sInfo.aMatchinfo[ofst]);
- }
- pCsr->aMatchinfo = sInfo.aMatchinfo;
+ pCsr->zMatchinfo = (char *)&pCsr->aMatchinfo[nMatchinfo];
+ pCsr->nMatchinfo = nMatchinfo;
+ memcpy(pCsr->zMatchinfo, zArg, nArg+1);
+ memset(pCsr->aMatchinfo, 0, sizeof(u32)*nMatchinfo);
pCsr->isMatchinfoNeeded = 1;
+ bGlobal = 1;
}
sInfo.aMatchinfo = pCsr->aMatchinfo;
- if( rc==SQLITE_OK && pCsr->isMatchinfoNeeded ){
- (void)fts3ExprIterate(pCsr->pExpr, fts3ExprLocalMatchinfoCb, (void*)&sInfo);
- if( pTab->bHasDocsize ){
- int ofst = 2 + 3*sInfo.aMatchinfo[0]*sInfo.aMatchinfo[1];
- rc = sqlite3Fts3MatchinfoDocsizeLocal(pCsr, &sInfo.aMatchinfo[ofst]);
- }
+ sInfo.nPhrase = pCsr->nPhrase;
+ if( pCsr->isMatchinfoNeeded ){
+ rc = fts3MatchinfoValues(pCsr, bGlobal, &sInfo, zArg);
pCsr->isMatchinfoNeeded = 0;
}
- return SQLITE_OK;
+ return rc;
}
/*
@@ -115743,7 +119013,7 @@ SQLITE_PRIVATE void sqlite3Fts3Snippet(
** columns of the FTS3 table. Otherwise, only column iCol is considered.
*/
for(iRead=0; iRead<pTab->nColumn; iRead++){
- SnippetFragment sF;
+ SnippetFragment sF = {0, 0, 0, 0};
int iS;
if( iCol>=0 && iRead!=iCol ) continue;
@@ -115777,6 +119047,7 @@ SQLITE_PRIVATE void sqlite3Fts3Snippet(
}
snippet_out:
+ sqlite3Fts3SegmentsClose(pTab);
if( rc!=SQLITE_OK ){
sqlite3_result_error_code(pCtx, rc);
sqlite3_free(res.z);
@@ -115956,6 +119227,7 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
offsets_out:
sqlite3_free(sCtx.aTerm);
assert( rc!=SQLITE_DONE );
+ sqlite3Fts3SegmentsClose(pTab);
if( rc!=SQLITE_OK ){
sqlite3_result_error_code(pCtx, rc);
sqlite3_free(res.z);
@@ -115968,21 +119240,43 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
/*
** Implementation of matchinfo() function.
*/
-SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *pContext, Fts3Cursor *pCsr){
+SQLITE_PRIVATE void sqlite3Fts3Matchinfo(
+ sqlite3_context *pContext, /* Function call context */
+ Fts3Cursor *pCsr, /* FTS3 table cursor */
+ const char *zArg /* Second arg to matchinfo() function */
+){
+ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
int rc;
+ int i;
+ const char *zFormat;
+
+ if( zArg ){
+ for(i=0; zArg[i]; i++){
+ char *zErr = 0;
+ if( fts3MatchinfoCheck(pTab, zArg[i], &zErr) ){
+ sqlite3_result_error(pContext, zErr, -1);
+ sqlite3_free(zErr);
+ return;
+ }
+ }
+ zFormat = zArg;
+ }else{
+ zFormat = FTS3_MATCHINFO_DEFAULT;
+ }
+
if( !pCsr->pExpr ){
sqlite3_result_blob(pContext, "", 0, SQLITE_STATIC);
return;
}
- rc = fts3GetMatchinfo(pCsr);
+
+ /* Retrieve matchinfo() data. */
+ rc = fts3GetMatchinfo(pCsr, zFormat);
+ sqlite3Fts3SegmentsClose(pTab);
+
if( rc!=SQLITE_OK ){
sqlite3_result_error_code(pContext, rc);
}else{
- Fts3Table *pTab = (Fts3Table*)pCsr->base.pVtab;
- int n = sizeof(u32)*(2+pCsr->aMatchinfo[0]*pCsr->aMatchinfo[1]*3);
- if( pTab->bHasDocsize ){
- n += sizeof(u32)*(1 + 2*pTab->nColumn);
- }
+ int n = pCsr->nMatchinfo * sizeof(u32);
sqlite3_result_blob(pContext, pCsr->aMatchinfo, n, SQLITE_TRANSIENT);
}
}
@@ -116006,6 +119300,45 @@ SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *pContext, Fts3Cursor *
** algorithms packaged as an SQLite virtual table module.
*/
+/*
+** Database Format of R-Tree Tables
+** --------------------------------
+**
+** The data structure for a single virtual r-tree table is stored in three
+** native SQLite tables declared as follows. In each case, the '%' character
+** in the table name is replaced with the user-supplied name of the r-tree
+** table.
+**
+** CREATE TABLE %_node(nodeno INTEGER PRIMARY KEY, data BLOB)
+** CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER)
+** CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER)
+**
+** The data for each node of the r-tree structure is stored in the %_node
+** table. For each node that is not the root node of the r-tree, there is
+** an entry in the %_parent table associating the node with its parent.
+** And for each row of data in the table, there is an entry in the %_rowid
+** table that maps from the entries rowid to the id of the node that it
+** is stored on.
+**
+** The root node of an r-tree always exists, even if the r-tree table is
+** empty. The nodeno of the root node is always 1. All other nodes in the
+** table must be the same size as the root node. The content of each node
+** is formatted as follows:
+**
+** 1. If the node is the root node (node 1), then the first 2 bytes
+** of the node contain the tree depth as a big-endian integer.
+** For non-root nodes, the first 2 bytes are left unused.
+**
+** 2. The next 2 bytes contain the number of entries currently
+** stored in the node.
+**
+** 3. The remainder of the node contains the node entries. Each entry
+** consists of a single 8-byte integer followed by an even number
+** of 4-byte coordinates. For leaf nodes the integer is the rowid
+** of a record. For internal nodes it is the node number of a
+** child page.
+*/
+
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RTREE)
/*
@@ -116046,6 +119379,9 @@ SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *pContext, Fts3Cursor *
#define AssignCells splitNodeStartree
#endif
+#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
+# define NDEBUG 1
+#endif
#ifndef SQLITE_CORE
SQLITE_EXTENSION_INIT1
@@ -116054,16 +119390,25 @@ SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *pContext, Fts3Cursor *
#ifndef SQLITE_AMALGAMATION
+#include "sqlite3rtree.h"
typedef sqlite3_int64 i64;
typedef unsigned char u8;
typedef unsigned int u32;
#endif
+/* The following macro is used to suppress compiler warnings.
+*/
+#ifndef UNUSED_PARAMETER
+# define UNUSED_PARAMETER(x) (void)(x)
+#endif
+
typedef struct Rtree Rtree;
typedef struct RtreeCursor RtreeCursor;
typedef struct RtreeNode RtreeNode;
typedef struct RtreeCell RtreeCell;
typedef struct RtreeConstraint RtreeConstraint;
+typedef struct RtreeMatchArg RtreeMatchArg;
+typedef struct RtreeGeomCallback RtreeGeomCallback;
typedef union RtreeCoord RtreeCoord;
/* The rtree may have between 1 and RTREE_MAX_DIMENSIONS dimensions. */
@@ -116133,6 +119478,15 @@ struct Rtree {
#define RTREE_REINSERT(p) RTREE_MINCELLS(p)
#define RTREE_MAXCELLS 51
+/*
+** The smallest possible node-size is (512-64)==448 bytes. And the largest
+** supported cell size is 48 bytes (8 byte rowid + ten 4 byte coordinates).
+** Therefore all non-root nodes must contain at least 3 entries. Since
+** 2^40 is greater than 2^64, an r-tree structure always has a depth of
+** 40 or less.
+*/
+#define RTREE_MAX_DEPTH 40
+
/*
** An rtree cursor object.
*/
@@ -116165,35 +119519,23 @@ union RtreeCoord {
** A search constraint.
*/
struct RtreeConstraint {
- int iCoord; /* Index of constrained coordinate */
- int op; /* Constraining operation */
- double rValue; /* Constraint value. */
+ int iCoord; /* Index of constrained coordinate */
+ int op; /* Constraining operation */
+ double rValue; /* Constraint value. */
+ int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *);
+ sqlite3_rtree_geometry *pGeom; /* Constraint callback argument for a MATCH */
};
/* Possible values for RtreeConstraint.op */
-#define RTREE_EQ 0x41
-#define RTREE_LE 0x42
-#define RTREE_LT 0x43
-#define RTREE_GE 0x44
-#define RTREE_GT 0x45
+#define RTREE_EQ 0x41
+#define RTREE_LE 0x42
+#define RTREE_LT 0x43
+#define RTREE_GE 0x44
+#define RTREE_GT 0x45
+#define RTREE_MATCH 0x46
/*
** An rtree structure node.
-**
-** Data format (RtreeNode.zData):
-**
-** 1. If the node is the root node (node 1), then the first 2 bytes
-** of the node contain the tree depth as a big-endian integer.
-** For non-root nodes, the first 2 bytes are left unused.
-**
-** 2. The next 2 bytes contain the number of entries currently
-** stored in the node.
-**
-** 3. The remainder of the node contains the node entries. Each entry
-** consists of a single 8-byte integer followed by an even number
-** of 4-byte coordinates. For leaf nodes the integer is the rowid
-** of a record. For internal nodes it is the node number of a
-** child page.
*/
struct RtreeNode {
RtreeNode *pParent; /* Parent node */
@@ -116213,6 +119555,40 @@ struct RtreeCell {
RtreeCoord aCoord[RTREE_MAX_DIMENSIONS*2];
};
+
+/*
+** Value for the first field of every RtreeMatchArg object. The MATCH
+** operator tests that the first field of a blob operand matches this
+** value to avoid operating on invalid blobs (which could cause a segfault).
+*/
+#define RTREE_GEOMETRY_MAGIC 0x891245AB
+
+/*
+** An instance of this structure must be supplied as a blob argument to
+** the right-hand-side of an SQL MATCH operator used to constrain an
+** r-tree query.
+*/
+struct RtreeMatchArg {
+ u32 magic; /* Always RTREE_GEOMETRY_MAGIC */
+ int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *);
+ void *pContext;
+ int nParam;
+ double aParam[1];
+};
+
+/*
+** When a geometry callback is created (see sqlite3_rtree_geometry_callback),
+** a single instance of the following structure is allocated. It is used
+** as the context for the user-function created by by s_r_g_c(). The object
+** is eventually deleted by the destructor mechanism provided by
+** sqlite3_create_function_v2() (which is called by s_r_g_c() to create
+** the geometry callback function).
+*/
+struct RtreeGeomCallback {
+ int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *);
+ void *pContext;
+};
+
#ifndef MAX
# define MAX(x,y) ((x) < (y) ? (y) : (x))
#endif
@@ -116295,10 +119671,8 @@ static void nodeReference(RtreeNode *p){
** Clear the content of node p (set all bytes to 0x00).
*/
static void nodeZero(Rtree *pRtree, RtreeNode *p){
- if( p ){
- memset(&p->zData[2], 0, pRtree->iNodeSize-2);
- p->isDirty = 1;
- }
+ memset(&p->zData[2], 0, pRtree->iNodeSize-2);
+ p->isDirty = 1;
}
/*
@@ -116318,7 +119692,6 @@ static int nodeHash(i64 iNode){
*/
static RtreeNode *nodeHashLookup(Rtree *pRtree, i64 iNode){
RtreeNode *p;
- assert( iNode!=0 );
for(p=pRtree->aHash[nodeHash(iNode)]; p && p->iNode!=iNode; p=p->pNext);
return p;
}
@@ -116327,13 +119700,11 @@ static RtreeNode *nodeHashLookup(Rtree *pRtree, i64 iNode){
** Add node pNode to the node hash table.
*/
static void nodeHashInsert(Rtree *pRtree, RtreeNode *pNode){
- if( pNode ){
- int iHash;
- assert( pNode->pNext==0 );
- iHash = nodeHash(pNode->iNode);
- pNode->pNext = pRtree->aHash[iHash];
- pRtree->aHash[iHash] = pNode;
- }
+ int iHash;
+ assert( pNode->pNext==0 );
+ iHash = nodeHash(pNode->iNode);
+ pNode->pNext = pRtree->aHash[iHash];
+ pRtree->aHash[iHash] = pNode;
}
/*
@@ -116355,11 +119726,11 @@ static void nodeHashDelete(Rtree *pRtree, RtreeNode *pNode){
** assigned a node number when nodeWrite() is called to write the
** node contents out to the database.
*/
-static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent, int zero){
+static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
RtreeNode *pNode;
pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode) + pRtree->iNodeSize);
if( pNode ){
- memset(pNode, 0, sizeof(RtreeNode) + (zero?pRtree->iNodeSize:0));
+ memset(pNode, 0, sizeof(RtreeNode) + pRtree->iNodeSize);
pNode->zData = (u8 *)&pNode[1];
pNode->nRef = 1;
pNode->pParent = pParent;
@@ -116380,6 +119751,7 @@ nodeAcquire(
RtreeNode **ppNode /* OUT: Acquired node */
){
int rc;
+ int rc2 = SQLITE_OK;
RtreeNode *pNode;
/* Check if the requested node is already in the hash table. If so,
@@ -116396,39 +119768,63 @@ nodeAcquire(
return SQLITE_OK;
}
- pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode) + pRtree->iNodeSize);
- if( !pNode ){
- *ppNode = 0;
- return SQLITE_NOMEM;
- }
- pNode->pParent = pParent;
- pNode->zData = (u8 *)&pNode[1];
- pNode->nRef = 1;
- pNode->iNode = iNode;
- pNode->isDirty = 0;
- pNode->pNext = 0;
-
sqlite3_bind_int64(pRtree->pReadNode, 1, iNode);
rc = sqlite3_step(pRtree->pReadNode);
if( rc==SQLITE_ROW ){
const u8 *zBlob = sqlite3_column_blob(pRtree->pReadNode, 0);
- assert( sqlite3_column_bytes(pRtree->pReadNode, 0)==pRtree->iNodeSize );
- memcpy(pNode->zData, zBlob, pRtree->iNodeSize);
- nodeReference(pParent);
- }else{
- sqlite3_free(pNode);
- pNode = 0;
+ if( pRtree->iNodeSize==sqlite3_column_bytes(pRtree->pReadNode, 0) ){
+ pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode)+pRtree->iNodeSize);
+ if( !pNode ){
+ rc2 = SQLITE_NOMEM;
+ }else{
+ pNode->pParent = pParent;
+ pNode->zData = (u8 *)&pNode[1];
+ pNode->nRef = 1;
+ pNode->iNode = iNode;
+ pNode->isDirty = 0;
+ pNode->pNext = 0;
+ memcpy(pNode->zData, zBlob, pRtree->iNodeSize);
+ nodeReference(pParent);
+ }
+ }
}
-
- *ppNode = pNode;
rc = sqlite3_reset(pRtree->pReadNode);
+ if( rc==SQLITE_OK ) rc = rc2;
- if( rc==SQLITE_OK && iNode==1 ){
+ /* If the root node was just loaded, set pRtree->iDepth to the height
+ ** of the r-tree structure. A height of zero means all data is stored on
+ ** the root node. A height of one means the children of the root node
+ ** are the leaves, and so on. If the depth as specified on the root node
+ ** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt.
+ */
+ if( pNode && iNode==1 ){
pRtree->iDepth = readInt16(pNode->zData);
+ if( pRtree->iDepth>RTREE_MAX_DEPTH ){
+ rc = SQLITE_CORRUPT;
+ }
}
- assert( (rc==SQLITE_OK && pNode) || (pNode==0 && rc!=SQLITE_OK) );
- nodeHashInsert(pRtree, pNode);
+ /* If no error has occurred so far, check if the "number of entries"
+ ** field on the node is too large. If so, set the return code to
+ ** SQLITE_CORRUPT.
+ */
+ if( pNode && rc==SQLITE_OK ){
+ if( NCELL(pNode)>((pRtree->iNodeSize-4)/pRtree->nBytesPerCell) ){
+ rc = SQLITE_CORRUPT;
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ if( pNode!=0 ){
+ nodeHashInsert(pRtree, pNode);
+ }else{
+ rc = SQLITE_CORRUPT;
+ }
+ *ppNode = pNode;
+ }else{
+ sqlite3_free(pNode);
+ *ppNode = 0;
+ }
return rc;
}
@@ -116481,8 +119877,7 @@ nodeInsertCell(
nMaxCell = (pRtree->iNodeSize-4)/pRtree->nBytesPerCell;
nCell = NCELL(pNode);
- assert(nCell<=nMaxCell);
-
+ assert( nCell<=nMaxCell );
if( nCell<nMaxCell ){
nodeOverwriteCell(pRtree, pNode, pCell, nCell);
writeInt16(&pNode->zData[2], nCell+1);
@@ -116702,6 +120097,25 @@ static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
return rc;
}
+
+/*
+** Free the RtreeCursor.aConstraint[] array and its contents.
+*/
+static void freeCursorConstraints(RtreeCursor *pCsr){
+ if( pCsr->aConstraint ){
+ int i; /* Used to iterate through constraint array */
+ for(i=0; i<pCsr->nConstraint; i++){
+ sqlite3_rtree_geometry *pGeom = pCsr->aConstraint[i].pGeom;
+ if( pGeom ){
+ if( pGeom->xDelUser ) pGeom->xDelUser(pGeom->pUser);
+ sqlite3_free(pGeom);
+ }
+ }
+ sqlite3_free(pCsr->aConstraint);
+ pCsr->aConstraint = 0;
+ }
+}
+
/*
** Rtree virtual table module xClose method.
*/
@@ -116709,7 +120123,7 @@ static int rtreeClose(sqlite3_vtab_cursor *cur){
Rtree *pRtree = (Rtree *)(cur->pVtab);
int rc;
RtreeCursor *pCsr = (RtreeCursor *)cur;
- sqlite3_free(pCsr->aConstraint);
+ freeCursorConstraints(pCsr);
rc = nodeRelease(pRtree, pCsr->pNode);
sqlite3_free(pCsr);
return rc;
@@ -116726,16 +120140,43 @@ static int rtreeEof(sqlite3_vtab_cursor *cur){
return (pCsr->pNode==0);
}
+/*
+** The r-tree constraint passed as the second argument to this function is
+** guaranteed to be a MATCH constraint.
+*/
+static int testRtreeGeom(
+ Rtree *pRtree, /* R-Tree object */
+ RtreeConstraint *pConstraint, /* MATCH constraint to test */
+ RtreeCell *pCell, /* Cell to test */
+ int *pbRes /* OUT: Test result */
+){
+ int i;
+ double aCoord[RTREE_MAX_DIMENSIONS*2];
+ int nCoord = pRtree->nDim*2;
+
+ assert( pConstraint->op==RTREE_MATCH );
+ assert( pConstraint->pGeom );
+
+ for(i=0; i<nCoord; i++){
+ aCoord[i] = DCOORD(pCell->aCoord[i]);
+ }
+ return pConstraint->xGeom(pConstraint->pGeom, nCoord, aCoord, pbRes);
+}
+
/*
** Cursor pCursor currently points to a cell in a non-leaf page.
-** Return true if the sub-tree headed by the cell is filtered
+** Set *pbEof to true if the sub-tree headed by the cell is filtered
** (excluded) by the constraints in the pCursor->aConstraint[]
** array, or false otherwise.
+**
+** Return SQLITE_OK if successful or an SQLite error code if an error
+** occurs within a geometry callback.
*/
-static int testRtreeCell(Rtree *pRtree, RtreeCursor *pCursor){
+static int testRtreeCell(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){
RtreeCell cell;
int ii;
int bRes = 0;
+ int rc = SQLITE_OK;
nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell);
for(ii=0; bRes==0 && ii<pCursor->nConstraint; ii++){
@@ -116744,31 +120185,51 @@ static int testRtreeCell(Rtree *pRtree, RtreeCursor *pCursor){
double cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]);
assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
- || p->op==RTREE_GT || p->op==RTREE_EQ
+ || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH
);
switch( p->op ){
- case RTREE_LE: case RTREE_LT: bRes = p->rValue<cell_min; break;
- case RTREE_GE: case RTREE_GT: bRes = p->rValue>cell_max; break;
- case RTREE_EQ:
+ case RTREE_LE: case RTREE_LT:
+ bRes = p->rValue<cell_min;
+ break;
+
+ case RTREE_GE: case RTREE_GT:
+ bRes = p->rValue>cell_max;
+ break;
+
+ case RTREE_EQ:
bRes = (p->rValue>cell_max || p->rValue<cell_min);
break;
+
+ default: {
+ assert( p->op==RTREE_MATCH );
+ rc = testRtreeGeom(pRtree, p, &cell, &bRes);
+ bRes = !bRes;
+ break;
+ }
}
}
- return bRes;
+ *pbEof = bRes;
+ return rc;
}
/*
-** Return true if the cell that cursor pCursor currently points to
+** Test if the cell that cursor pCursor currently points to
** would be filtered (excluded) by the constraints in the
-** pCursor->aConstraint[] array, or false otherwise.
+** pCursor->aConstraint[] array. If so, set *pbEof to true before
+** returning. If the cell is not filtered (excluded) by the constraints,
+** set pbEof to zero.
+**
+** Return SQLITE_OK if successful or an SQLite error code if an error
+** occurs within a geometry callback.
**
** This function assumes that the cell is part of a leaf node.
*/
-static int testRtreeEntry(Rtree *pRtree, RtreeCursor *pCursor){
+static int testRtreeEntry(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){
RtreeCell cell;
int ii;
+ *pbEof = 0;
nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell);
for(ii=0; ii<pCursor->nConstraint; ii++){
@@ -116776,7 +120237,7 @@ static int testRtreeEntry(Rtree *pRtree, RtreeCursor *pCursor){
double coord = DCOORD(cell.aCoord[p->iCoord]);
int res;
assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
- || p->op==RTREE_GT || p->op==RTREE_EQ
+ || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH
);
switch( p->op ){
case RTREE_LE: res = (coord<=p->rValue); break;
@@ -116784,12 +120245,24 @@ static int testRtreeEntry(Rtree *pRtree, RtreeCursor *pCursor){
case RTREE_GE: res = (coord>=p->rValue); break;
case RTREE_GT: res = (coord>p->rValue); break;
case RTREE_EQ: res = (coord==p->rValue); break;
+ default: {
+ int rc;
+ assert( p->op==RTREE_MATCH );
+ rc = testRtreeGeom(pRtree, p, &cell, &res);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ break;
+ }
}
- if( !res ) return 1;
+ if( !res ){
+ *pbEof = 1;
+ return SQLITE_OK;
+ }
}
- return 0;
+ return SQLITE_OK;
}
/*
@@ -116816,19 +120289,18 @@ static int descendToCell(
assert( iHeight>=0 );
if( iHeight==0 ){
- isEof = testRtreeEntry(pRtree, pCursor);
+ rc = testRtreeEntry(pRtree, pCursor, &isEof);
}else{
- isEof = testRtreeCell(pRtree, pCursor);
+ rc = testRtreeCell(pRtree, pCursor, &isEof);
}
- if( isEof || iHeight==0 ){
- *pEof = isEof;
- return SQLITE_OK;
+ if( rc!=SQLITE_OK || isEof || iHeight==0 ){
+ goto descend_to_cell_out;
}
iRowid = nodeGetRowid(pRtree, pCursor->pNode, pCursor->iCell);
rc = nodeAcquire(pRtree, iRowid, pCursor->pNode, &pChild);
if( rc!=SQLITE_OK ){
- return rc;
+ goto descend_to_cell_out;
}
nodeRelease(pRtree, pCursor->pNode);
@@ -116838,7 +120310,7 @@ static int descendToCell(
pCursor->iCell = ii;
rc = descendToCell(pRtree, pCursor, iHeight-1, &isEof);
if( rc!=SQLITE_OK ){
- return rc;
+ goto descend_to_cell_out;
}
}
@@ -116850,32 +120322,43 @@ static int descendToCell(
pCursor->iCell = iSavedCell;
}
+descend_to_cell_out:
*pEof = isEof;
- return SQLITE_OK;
+ return rc;
}
/*
** One of the cells in node pNode is guaranteed to have a 64-bit
** integer value equal to iRowid. Return the index of this cell.
*/
-static int nodeRowidIndex(Rtree *pRtree, RtreeNode *pNode, i64 iRowid){
+static int nodeRowidIndex(
+ Rtree *pRtree,
+ RtreeNode *pNode,
+ i64 iRowid,
+ int *piIndex
+){
int ii;
- for(ii=0; nodeGetRowid(pRtree, pNode, ii)!=iRowid; ii++){
- assert( ii<(NCELL(pNode)-1) );
+ int nCell = NCELL(pNode);
+ for(ii=0; ii<nCell; ii++){
+ if( nodeGetRowid(pRtree, pNode, ii)==iRowid ){
+ *piIndex = ii;
+ return SQLITE_OK;
+ }
}
- return ii;
+ return SQLITE_CORRUPT;
}
/*
** Return the index of the cell containing a pointer to node pNode
** in its parent. If pNode is the root node, return -1.
*/
-static int nodeParentIndex(Rtree *pRtree, RtreeNode *pNode){
+static int nodeParentIndex(Rtree *pRtree, RtreeNode *pNode, int *piIndex){
RtreeNode *pParent = pNode->pParent;
if( pParent ){
- return nodeRowidIndex(pRtree, pParent, pNode->iNode);
+ return nodeRowidIndex(pRtree, pParent, pNode->iNode, piIndex);
}
- return -1;
+ *piIndex = -1;
+ return SQLITE_OK;
}
/*
@@ -116886,13 +120369,17 @@ static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){
RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor;
int rc = SQLITE_OK;
+ /* RtreeCursor.pNode must not be NULL. If is is NULL, then this cursor is
+ ** already at EOF. It is against the rules to call the xNext() method of
+ ** a cursor that has already reached EOF.
+ */
+ assert( pCsr->pNode );
+
if( pCsr->iStrategy==1 ){
/* This "scan" is a direct lookup by rowid. There is no next entry. */
nodeRelease(pRtree, pCsr->pNode);
pCsr->pNode = 0;
- }
-
- else if( pCsr->pNode ){
+ }else{
/* Move to the next entry that matches the configured constraints. */
int iHeight = 0;
while( pCsr->pNode ){
@@ -116906,7 +120393,10 @@ static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){
}
}
pCsr->pNode = pNode->pParent;
- pCsr->iCell = nodeParentIndex(pRtree, pNode);
+ rc = nodeParentIndex(pRtree, pNode, &pCsr->iCell);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
nodeReference(pCsr->pNode);
nodeRelease(pRtree, pNode);
iHeight++;
@@ -116974,6 +120464,51 @@ static int findLeafNode(Rtree *pRtree, i64 iRowid, RtreeNode **ppLeaf){
return rc;
}
+/*
+** This function is called to configure the RtreeConstraint object passed
+** as the second argument for a MATCH constraint. The value passed as the
+** first argument to this function is the right-hand operand to the MATCH
+** operator.
+*/
+static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){
+ RtreeMatchArg *p;
+ sqlite3_rtree_geometry *pGeom;
+ int nBlob;
+
+ /* Check that value is actually a blob. */
+ if( !sqlite3_value_type(pValue)==SQLITE_BLOB ) return SQLITE_ERROR;
+
+ /* Check that the blob is roughly the right size. */
+ nBlob = sqlite3_value_bytes(pValue);
+ if( nBlob<(int)sizeof(RtreeMatchArg)
+ || ((nBlob-sizeof(RtreeMatchArg))%sizeof(double))!=0
+ ){
+ return SQLITE_ERROR;
+ }
+
+ pGeom = (sqlite3_rtree_geometry *)sqlite3_malloc(
+ sizeof(sqlite3_rtree_geometry) + nBlob
+ );
+ if( !pGeom ) return SQLITE_NOMEM;
+ memset(pGeom, 0, sizeof(sqlite3_rtree_geometry));
+ p = (RtreeMatchArg *)&pGeom[1];
+
+ memcpy(p, sqlite3_value_blob(pValue), nBlob);
+ if( p->magic!=RTREE_GEOMETRY_MAGIC
+ || nBlob!=(int)(sizeof(RtreeMatchArg) + (p->nParam-1)*sizeof(double))
+ ){
+ sqlite3_free(pGeom);
+ return SQLITE_ERROR;
+ }
+
+ pGeom->pContext = p->pContext;
+ pGeom->nParam = p->nParam;
+ pGeom->aParam = p->aParam;
+
+ pCons->xGeom = p->xGeom;
+ pCons->pGeom = pGeom;
+ return SQLITE_OK;
+}
/*
** Rtree virtual table module xFilter method.
@@ -116992,8 +120527,7 @@ static int rtreeFilter(
rtreeReference(pRtree);
- sqlite3_free(pCsr->aConstraint);
- pCsr->aConstraint = 0;
+ freeCursorConstraints(pCsr);
pCsr->iStrategy = idxNum;
if( idxNum==1 ){
@@ -117002,8 +120536,9 @@ static int rtreeFilter(
i64 iRowid = sqlite3_value_int64(argv[0]);
rc = findLeafNode(pRtree, iRowid, &pLeaf);
pCsr->pNode = pLeaf;
- if( pLeaf && rc==SQLITE_OK ){
- pCsr->iCell = nodeRowidIndex(pRtree, pLeaf, iRowid);
+ if( pLeaf ){
+ assert( rc==SQLITE_OK );
+ rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &pCsr->iCell);
}
}else{
/* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array
@@ -117015,12 +120550,24 @@ static int rtreeFilter(
if( !pCsr->aConstraint ){
rc = SQLITE_NOMEM;
}else{
+ memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*argc);
assert( (idxStr==0 && argc==0) || strlen(idxStr)==argc*2 );
for(ii=0; ii<argc; ii++){
RtreeConstraint *p = &pCsr->aConstraint[ii];
p->op = idxStr[ii*2];
p->iCoord = idxStr[ii*2+1]-'a';
- p->rValue = sqlite3_value_double(argv[ii]);
+ if( p->op==RTREE_MATCH ){
+ /* A MATCH operator. The right-hand-side must be a blob that
+ ** can be cast into an RtreeMatchArg object. One created using
+ ** an sqlite3_rtree_geometry_callback() SQL user function.
+ */
+ rc = deserializeGeometry(argv[ii], p);
+ if( rc!=SQLITE_OK ){
+ break;
+ }
+ }else{
+ p->rValue = sqlite3_value_double(argv[ii]);
+ }
}
}
}
@@ -117080,6 +120627,7 @@ static int rtreeFilter(
** < 0x43 ('C')
** >= 0x44 ('D')
** > 0x45 ('E')
+** MATCH 0x46 ('F')
** ----------------------
**
** The second of each pair of bytes identifies the coordinate column
@@ -117093,6 +120641,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
int iIdx = 0;
char zIdxStr[RTREE_MAX_DIMENSIONS*8+1];
memset(zIdxStr, 0, sizeof(zIdxStr));
+ UNUSED_PARAMETER(tab);
assert( pIdxInfo->idxStr==0 );
for(ii=0; ii<pIdxInfo->nConstraint; ii++){
@@ -117118,7 +120667,9 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
return SQLITE_OK;
}
- if( p->usable && p->iColumn>0 ){
+ if( p->usable && (p->iColumn>0 || p->op==SQLITE_INDEX_CONSTRAINT_MATCH) ){
+ int j, opmsk;
+ static const unsigned char compatible[] = { 0, 0, 1, 1, 2, 2 };
u8 op = 0;
switch( p->op ){
case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break;
@@ -117126,31 +120677,33 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break;
case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break;
case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break;
+ default:
+ assert( p->op==SQLITE_INDEX_CONSTRAINT_MATCH );
+ op = RTREE_MATCH;
+ break;
}
- if( op ){
- /* Make sure this particular constraint has not been used before.
- ** If it has been used before, ignore it.
- **
- ** A <= or < can be used if there is a prior >= or >.
- ** A >= or > can be used if there is a prior < or <=.
- ** A <= or < is disqualified if there is a prior <=, <, or ==.
- ** A >= or > is disqualified if there is a prior >=, >, or ==.
- ** A == is disqualifed if there is any prior constraint.
- */
- int j, opmsk;
- static const unsigned char compatible[] = { 0, 0, 1, 1, 2, 2 };
- assert( compatible[RTREE_EQ & 7]==0 );
- assert( compatible[RTREE_LT & 7]==1 );
- assert( compatible[RTREE_LE & 7]==1 );
- assert( compatible[RTREE_GT & 7]==2 );
- assert( compatible[RTREE_GE & 7]==2 );
- cCol = p->iColumn - 1 + 'a';
- opmsk = compatible[op & 7];
- for(j=0; j<iIdx; j+=2){
- if( zIdxStr[j+1]==cCol && (compatible[zIdxStr[j] & 7] & opmsk)!=0 ){
- op = 0;
- break;
- }
+ assert( op!=0 );
+
+ /* Make sure this particular constraint has not been used before.
+ ** If it has been used before, ignore it.
+ **
+ ** A <= or < can be used if there is a prior >= or >.
+ ** A >= or > can be used if there is a prior < or <=.
+ ** A <= or < is disqualified if there is a prior <=, <, or ==.
+ ** A >= or > is disqualified if there is a prior >=, >, or ==.
+ ** A == is disqualifed if there is any prior constraint.
+ */
+ assert( compatible[RTREE_EQ & 7]==0 );
+ assert( compatible[RTREE_LT & 7]==1 );
+ assert( compatible[RTREE_LE & 7]==1 );
+ assert( compatible[RTREE_GT & 7]==2 );
+ assert( compatible[RTREE_GE & 7]==2 );
+ cCol = p->iColumn - 1 + 'a';
+ opmsk = compatible[op & 7];
+ for(j=0; j<iIdx; j+=2){
+ if( zIdxStr[j+1]==cCol && (compatible[zIdxStr[j] & 7] & opmsk)!=0 ){
+ op = 0;
+ break;
}
}
if( op ){
@@ -117258,7 +120811,13 @@ static float cellOverlap(
int ii;
float overlap = 0.0;
for(ii=0; ii<nCell; ii++){
- if( ii!=iExclude ){
+#if VARIANT_RSTARTREE_CHOOSESUBTREE
+ if( ii!=iExclude )
+#else
+ assert( iExclude==-1 );
+ UNUSED_PARAMETER(iExclude);
+#endif
+ {
int jj;
float o = 1.0;
for(jj=0; jj<(pRtree->nDim*2); jj+=2){
@@ -117351,22 +120910,31 @@ static int ChooseLeaf(
** the smallest area.
*/
for(iCell=0; iCell<nCell; iCell++){
+ int bBest = 0;
float growth;
float area;
float overlap = 0.0;
nodeGetCell(pRtree, pNode, iCell, &cell);
growth = cellGrowth(pRtree, &cell, pCell);
area = cellArea(pRtree, &cell);
+
#if VARIANT_RSTARTREE_CHOOSESUBTREE
if( ii==(pRtree->iDepth-1) ){
overlap = cellOverlapEnlargement(pRtree,&cell,pCell,aCell,nCell,iCell);
}
-#endif
if( (iCell==0)
|| (overlap<fMinOverlap)
|| (overlap==fMinOverlap && growth<fMinGrowth)
|| (overlap==fMinOverlap && growth==fMinGrowth && area<fMinArea)
){
+ bBest = 1;
+ }
+#else
+ if( iCell==0||growth<fMinGrowth||(growth==fMinGrowth && area<fMinArea) ){
+ bBest = 1;
+ }
+#endif
+ if( bBest ){
fMinOverlap = overlap;
fMinGrowth = growth;
fMinArea = area;
@@ -117389,16 +120957,20 @@ static int ChooseLeaf(
** the node pNode. This function updates the bounding box cells in
** all ancestor elements.
*/
-static void AdjustTree(
+static int AdjustTree(
Rtree *pRtree, /* Rtree table */
RtreeNode *pNode, /* Adjust ancestry of this node. */
RtreeCell *pCell /* This cell was just inserted */
){
RtreeNode *p = pNode;
while( p->pParent ){
- RtreeCell cell;
RtreeNode *pParent = p->pParent;
- int iCell = nodeParentIndex(pRtree, p);
+ RtreeCell cell;
+ int iCell;
+
+ if( nodeParentIndex(pRtree, p, &iCell) ){
+ return SQLITE_CORRUPT;
+ }
nodeGetCell(pRtree, pParent, iCell, &cell);
if( !cellContains(pRtree, &cell, pCell) ){
@@ -117408,6 +120980,7 @@ static void AdjustTree(
p = pParent;
}
+ return SQLITE_OK;
}
/*
@@ -117936,14 +121509,14 @@ static int SplitNode(
nCell++;
if( pNode->iNode==1 ){
- pRight = nodeNew(pRtree, pNode, 1);
- pLeft = nodeNew(pRtree, pNode, 1);
+ pRight = nodeNew(pRtree, pNode);
+ pLeft = nodeNew(pRtree, pNode);
pRtree->iDepth++;
pNode->isDirty = 1;
writeInt16(pNode->zData, pRtree->iDepth);
}else{
pLeft = pNode;
- pRight = nodeNew(pRtree, pLeft->pParent, 1);
+ pRight = nodeNew(pRtree, pLeft->pParent);
nodeReference(pLeft);
}
@@ -117960,8 +121533,12 @@ static int SplitNode(
goto splitnode_out;
}
- /* Ensure both child nodes have node numbers assigned to them. */
- if( (0==pRight->iNode && SQLITE_OK!=(rc = nodeWrite(pRtree, pRight)))
+ /* Ensure both child nodes have node numbers assigned to them by calling
+ ** nodeWrite(). Node pRight always needs a node number, as it was created
+ ** by nodeNew() above. But node pLeft sometimes already has a node number.
+ ** In this case avoid the all to nodeWrite().
+ */
+ if( SQLITE_OK!=(rc = nodeWrite(pRtree, pRight))
|| (0==pLeft->iNode && SQLITE_OK!=(rc = nodeWrite(pRtree, pLeft)))
){
goto splitnode_out;
@@ -117977,9 +121554,15 @@ static int SplitNode(
}
}else{
RtreeNode *pParent = pLeft->pParent;
- int iCell = nodeParentIndex(pRtree, pLeft);
- nodeOverwriteCell(pRtree, pParent, &leftbbox, iCell);
- AdjustTree(pRtree, pParent, &leftbbox);
+ int iCell;
+ rc = nodeParentIndex(pRtree, pLeft, &iCell);
+ if( rc==SQLITE_OK ){
+ nodeOverwriteCell(pRtree, pParent, &leftbbox, iCell);
+ rc = AdjustTree(pRtree, pParent, &leftbbox);
+ }
+ if( rc!=SQLITE_OK ){
+ goto splitnode_out;
+ }
}
if( (rc = rtreeInsertCell(pRtree, pRight->pParent, &rightbbox, iHeight+1)) ){
goto splitnode_out;
@@ -118023,20 +121606,43 @@ splitnode_out:
return rc;
}
+/*
+** If node pLeaf is not the root of the r-tree and its pParent pointer is
+** still NULL, load all ancestor nodes of pLeaf into memory and populate
+** the pLeaf->pParent chain all the way up to the root node.
+**
+** This operation is required when a row is deleted (or updated - an update
+** is implemented as a delete followed by an insert). SQLite provides the
+** rowid of the row to delete, which can be used to find the leaf on which
+** the entry resides (argument pLeaf). Once the leaf is located, this
+** function is called to determine its ancestry.
+*/
static int fixLeafParent(Rtree *pRtree, RtreeNode *pLeaf){
int rc = SQLITE_OK;
- if( pLeaf->iNode!=1 && pLeaf->pParent==0 ){
- sqlite3_bind_int64(pRtree->pReadParent, 1, pLeaf->iNode);
- if( sqlite3_step(pRtree->pReadParent)==SQLITE_ROW ){
- i64 iNode = sqlite3_column_int64(pRtree->pReadParent, 0);
- rc = nodeAcquire(pRtree, iNode, 0, &pLeaf->pParent);
- }else{
- rc = SQLITE_ERROR;
- }
- sqlite3_reset(pRtree->pReadParent);
- if( rc==SQLITE_OK ){
- rc = fixLeafParent(pRtree, pLeaf->pParent);
+ RtreeNode *pChild = pLeaf;
+ while( rc==SQLITE_OK && pChild->iNode!=1 && pChild->pParent==0 ){
+ int rc2 = SQLITE_OK; /* sqlite3_reset() return code */
+ sqlite3_bind_int64(pRtree->pReadParent, 1, pChild->iNode);
+ rc = sqlite3_step(pRtree->pReadParent);
+ if( rc==SQLITE_ROW ){
+ RtreeNode *pTest; /* Used to test for reference loops */
+ i64 iNode; /* Node number of parent node */
+
+ /* Before setting pChild->pParent, test that we are not creating a
+ ** loop of references (as we would if, say, pChild==pParent). We don't
+ ** want to do this as it leads to a memory leak when trying to delete
+ ** the referenced counted node structures.
+ */
+ iNode = sqlite3_column_int64(pRtree->pReadParent, 0);
+ for(pTest=pLeaf; pTest && pTest->iNode!=iNode; pTest=pTest->pParent);
+ if( !pTest ){
+ rc2 = nodeAcquire(pRtree, iNode, 0, &pChild->pParent);
+ }
}
+ rc = sqlite3_reset(pRtree->pReadParent);
+ if( rc==SQLITE_OK ) rc = rc2;
+ if( rc==SQLITE_OK && !pChild->pParent ) rc = SQLITE_CORRUPT;
+ pChild = pChild->pParent;
}
return rc;
}
@@ -118045,18 +121651,24 @@ static int deleteCell(Rtree *, RtreeNode *, int, int);
static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){
int rc;
+ int rc2;
RtreeNode *pParent;
int iCell;
assert( pNode->nRef==1 );
/* Remove the entry in the parent cell. */
- iCell = nodeParentIndex(pRtree, pNode);
- pParent = pNode->pParent;
- pNode->pParent = 0;
- if( SQLITE_OK!=(rc = deleteCell(pRtree, pParent, iCell, iHeight+1))
- || SQLITE_OK!=(rc = nodeRelease(pRtree, pParent))
- ){
+ rc = nodeParentIndex(pRtree, pNode, &iCell);
+ if( rc==SQLITE_OK ){
+ pParent = pNode->pParent;
+ pNode->pParent = 0;
+ rc = deleteCell(pRtree, pParent, iCell, iHeight+1);
+ }
+ rc2 = nodeRelease(pRtree, pParent);
+ if( rc==SQLITE_OK ){
+ rc = rc2;
+ }
+ if( rc!=SQLITE_OK ){
return rc;
}
@@ -118086,8 +121698,9 @@ static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){
return SQLITE_OK;
}
-static void fixBoundingBox(Rtree *pRtree, RtreeNode *pNode){
+static int fixBoundingBox(Rtree *pRtree, RtreeNode *pNode){
RtreeNode *pParent = pNode->pParent;
+ int rc = SQLITE_OK;
if( pParent ){
int ii;
int nCell = NCELL(pNode);
@@ -118099,10 +121712,13 @@ static void fixBoundingBox(Rtree *pRtree, RtreeNode *pNode){
cellUnion(pRtree, &box, &cell);
}
box.iRowid = pNode->iNode;
- ii = nodeParentIndex(pRtree, pNode);
- nodeOverwriteCell(pRtree, pParent, &box, ii);
- fixBoundingBox(pRtree, pParent);
+ rc = nodeParentIndex(pRtree, pNode, &ii);
+ if( rc==SQLITE_OK ){
+ nodeOverwriteCell(pRtree, pParent, &box, ii);
+ rc = fixBoundingBox(pRtree, pParent);
+ }
}
+ return rc;
}
/*
@@ -118110,6 +121726,7 @@ static void fixBoundingBox(Rtree *pRtree, RtreeNode *pNode){
** cell, adjust the r-tree data structure if required.
*/
static int deleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell, int iHeight){
+ RtreeNode *pParent;
int rc;
if( SQLITE_OK!=(rc = fixLeafParent(pRtree, pNode)) ){
@@ -118126,14 +121743,13 @@ static int deleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell, int iHeight){
** cell in the parent node so that it tightly contains the updated
** node.
*/
- if( pNode->iNode!=1 ){
- RtreeNode *pParent = pNode->pParent;
- if( (pParent->iNode!=1 || NCELL(pParent)!=1)
- && (NCELL(pNode)<RTREE_MINCELLS(pRtree))
- ){
+ pParent = pNode->pParent;
+ assert( pParent || pNode->iNode==1 );
+ if( pParent ){
+ if( NCELL(pNode)<RTREE_MINCELLS(pRtree) ){
rc = removeNode(pRtree, pNode, iHeight);
}else{
- fixBoundingBox(pRtree, pNode);
+ rc = fixBoundingBox(pRtree, pNode);
}
}
@@ -118216,7 +121832,7 @@ static int Reinsert(
}
}
if( rc==SQLITE_OK ){
- fixBoundingBox(pRtree, pNode);
+ rc = fixBoundingBox(pRtree, pNode);
}
for(; rc==SQLITE_OK && ii<nCell; ii++){
/* Find a node to store this cell in. pNode->iNode currently contains
@@ -118270,11 +121886,13 @@ static int rtreeInsertCell(
rc = SplitNode(pRtree, pNode, pCell, iHeight);
#endif
}else{
- AdjustTree(pRtree, pNode, pCell);
- if( iHeight==0 ){
- rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode);
- }else{
- rc = parentWrite(pRtree, pCell->iRowid, pNode->iNode);
+ rc = AdjustTree(pRtree, pNode, pCell);
+ if( rc==SQLITE_OK ){
+ if( iHeight==0 ){
+ rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode);
+ }else{
+ rc = parentWrite(pRtree, pCell->iRowid, pNode->iNode);
+ }
}
}
return rc;
@@ -118319,16 +121937,6 @@ static int newRowid(Rtree *pRtree, i64 *piRowid){
return rc;
}
-#ifndef NDEBUG
-static int hashIsEmpty(Rtree *pRtree){
- int ii;
- for(ii=0; ii<HASHSIZE; ii++){
- assert( !pRtree->aHash[ii] );
- }
- return 1;
-}
-#endif
-
/*
** The xUpdate method for rtree module virtual tables.
*/
@@ -118344,7 +121952,6 @@ static int rtreeUpdate(
rtreeReference(pRtree);
assert(nData>=1);
- assert(hashIsEmpty(pRtree));
/* If azData[0] is not an SQL NULL value, it is the rowid of a
** record to delete from the r-tree table. The following block does
@@ -118370,8 +121977,10 @@ static int rtreeUpdate(
/* Delete the cell in question from the leaf node. */
if( rc==SQLITE_OK ){
int rc2;
- iCell = nodeRowidIndex(pRtree, pLeaf, iDelete);
- rc = deleteCell(pRtree, pLeaf, iCell, 0);
+ rc = nodeRowidIndex(pRtree, pLeaf, iDelete, &iCell);
+ if( rc==SQLITE_OK ){
+ rc = deleteCell(pRtree, pLeaf, iCell, 0);
+ }
rc2 = nodeRelease(pRtree, pLeaf);
if( rc==SQLITE_OK ){
rc = rc2;
@@ -118393,19 +122002,20 @@ static int rtreeUpdate(
** the root node (the operation that Gutman's paper says to perform
** in this scenario).
*/
- if( rc==SQLITE_OK && pRtree->iDepth>0 ){
- if( rc==SQLITE_OK && NCELL(pRoot)==1 ){
- RtreeNode *pChild;
- i64 iChild = nodeGetRowid(pRtree, pRoot, 0);
- rc = nodeAcquire(pRtree, iChild, pRoot, &pChild);
- if( rc==SQLITE_OK ){
- rc = removeNode(pRtree, pChild, pRtree->iDepth-1);
- }
- if( rc==SQLITE_OK ){
- pRtree->iDepth--;
- writeInt16(pRoot->zData, pRtree->iDepth);
- pRoot->isDirty = 1;
- }
+ if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){
+ int rc2;
+ RtreeNode *pChild;
+ i64 iChild = nodeGetRowid(pRtree, pRoot, 0);
+ rc = nodeAcquire(pRtree, iChild, pRoot, &pChild);
+ if( rc==SQLITE_OK ){
+ rc = removeNode(pRtree, pChild, pRtree->iDepth-1);
+ }
+ rc2 = nodeRelease(pRtree, pChild);
+ if( rc==SQLITE_OK ) rc = rc2;
+ if( rc==SQLITE_OK ){
+ pRtree->iDepth--;
+ writeInt16(pRoot->zData, pRtree->iDepth);
+ pRoot->isDirty = 1;
}
}
@@ -118695,7 +122305,7 @@ static int rtreeInit(
Rtree *pRtree;
int nDb; /* Length of string argv[1] */
int nName; /* Length of string argv[2] */
- int eCoordType = (int)pAux;
+ int eCoordType = (pAux ? RTREE_COORD_INT32 : RTREE_COORD_REAL32);
const char *aErrMsg[] = {
0, /* 0 */
@@ -118792,6 +122402,7 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
Rtree tree;
int ii;
+ UNUSED_PARAMETER(nArg);
memset(&node, 0, sizeof(RtreeNode));
memset(&tree, 0, sizeof(Rtree));
tree.nDim = sqlite3_value_int(apArg[0]);
@@ -118825,6 +122436,7 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
}
static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
+ UNUSED_PARAMETER(nArg);
if( sqlite3_value_type(apArg[0])!=SQLITE_BLOB
|| sqlite3_value_bytes(apArg[0])<2
){
@@ -118841,14 +122453,11 @@ static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
** function "rtreenode".
*/
SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db){
- int rc = SQLITE_OK;
+ const int utf8 = SQLITE_UTF8;
+ int rc;
+ rc = sqlite3_create_function(db, "rtreenode", 2, utf8, 0, rtreenode, 0, 0);
if( rc==SQLITE_OK ){
- int utf8 = SQLITE_UTF8;
- rc = sqlite3_create_function(db, "rtreenode", 2, utf8, 0, rtreenode, 0, 0);
- }
- if( rc==SQLITE_OK ){
- int utf8 = SQLITE_UTF8;
rc = sqlite3_create_function(db, "rtreedepth", 1, utf8, 0,rtreedepth, 0, 0);
}
if( rc==SQLITE_OK ){
@@ -118863,6 +122472,70 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db){
return rc;
}
+/*
+** A version of sqlite3_free() that can be used as a callback. This is used
+** in two places - as the destructor for the blob value returned by the
+** invocation of a geometry function, and as the destructor for the geometry
+** functions themselves.
+*/
+static void doSqlite3Free(void *p){
+ sqlite3_free(p);
+}
+
+/*
+** Each call to sqlite3_rtree_geometry_callback() creates an ordinary SQLite
+** scalar user function. This C function is the callback used for all such
+** registered SQL functions.
+**
+** The scalar user functions return a blob that is interpreted by r-tree
+** table MATCH operators.
+*/
+static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
+ RtreeGeomCallback *pGeomCtx = (RtreeGeomCallback *)sqlite3_user_data(ctx);
+ RtreeMatchArg *pBlob;
+ int nBlob;
+
+ nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(double);
+ pBlob = (RtreeMatchArg *)sqlite3_malloc(nBlob);
+ if( !pBlob ){
+ sqlite3_result_error_nomem(ctx);
+ }else{
+ int i;
+ pBlob->magic = RTREE_GEOMETRY_MAGIC;
+ pBlob->xGeom = pGeomCtx->xGeom;
+ pBlob->pContext = pGeomCtx->pContext;
+ pBlob->nParam = nArg;
+ for(i=0; i<nArg; i++){
+ pBlob->aParam[i] = sqlite3_value_double(aArg[i]);
+ }
+ sqlite3_result_blob(ctx, pBlob, nBlob, doSqlite3Free);
+ }
+}
+
+/*
+** Register a new geometry function for use with the r-tree MATCH operator.
+*/
+SQLITE_API int sqlite3_rtree_geometry_callback(
+ sqlite3 *db,
+ const char *zGeom,
+ int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *),
+ void *pContext
+){
+ RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */
+
+ /* Allocate and populate the context object. */
+ pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback));
+ if( !pGeomCtx ) return SQLITE_NOMEM;
+ pGeomCtx->xGeom = xGeom;
+ pGeomCtx->pContext = pContext;
+
+ /* Create the new user-function. Register a destructor function to delete
+ ** the context object when it is no longer required. */
+ return sqlite3_create_function_v2(db, zGeom, -1, SQLITE_ANY,
+ (void *)pGeomCtx, geomCallback, 0, 0, doSqlite3Free
+ );
+}
+
#if !SQLITE_CORE
SQLITE_API int sqlite3_extension_init(
sqlite3 *db,
diff --git a/sqlite-3.7.2/sqlite3.h b/sqlite-3.7.5/sqlite3.h
index ceca47a..75f96dd 100644
--- a/sqlite-3.7.2/sqlite3.h
+++ b/sqlite-3.7.5/sqlite3.h
@@ -107,9 +107,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.7.2"
-#define SQLITE_VERSION_NUMBER 3007002
-#define SQLITE_SOURCE_ID "2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3"
+#define SQLITE_VERSION "3.7.5"
+#define SQLITE_VERSION_NUMBER 3007005
+#define SQLITE_SOURCE_ID "2011-01-28 17:03:50 ed759d5a9edb3bba5f48f243df47be29e3fe8cd7"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -390,7 +390,7 @@ 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 /* Database lock protocol error */
@@ -542,6 +542,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
@@ -610,7 +622,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
@@ -703,6 +717,21 @@ struct sqlite3_io_methods {
** 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 specilized VFSes
+** that do require it.
*/
#define SQLITE_FCNTL_LOCKSTATE 1
#define SQLITE_GET_LOCKPROXYFILE 2
@@ -710,6 +739,9 @@ struct sqlite3_io_methods {
#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
+
/*
** CAPI3REF: Mutex Handle
@@ -757,15 +789,19 @@ 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
+** ^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].
**
@@ -776,7 +812,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
** 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:
**
** <ul>
@@ -787,7 +823,8 @@ typedef struct sqlite3_mutex sqlite3_mutex;
** <li> [SQLITE_OPEN_TRANSIENT_DB]
** <li> [SQLITE_OPEN_SUBJOURNAL]
** <li> [SQLITE_OPEN_MASTER_JOURNAL]
-** </ul>
+** <li> [SQLITE_OPEN_WAL]
+** </ul>)^
**
** The file I/O implementation can use the object type flags to
** change the way it deals with files. For example, an application
@@ -806,10 +843,11 @@ typedef struct sqlite3_mutex sqlite3_mutex;
** </ul>
**
** 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
@@ -818,7 +856,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
** It is <i>not</i> 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
@@ -828,13 +866,13 @@ 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]
+** ^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
@@ -848,10 +886,10 @@ typedef struct sqlite3_mutex sqlite3_mutex;
** 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()
+** 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
+** ^The xCurrentTimeInt64() method returns, as an integer, the Julian
** Day Number multipled by 86400000 (the number of milliseconds in
** a 24-hour day).
** ^SQLite will use the xCurrentTimeInt64() method to get the current
@@ -1248,7 +1286,7 @@ struct sqlite3_mem_methods {
** <ul>
** <li> [sqlite3_memory_used()]
** <li> [sqlite3_memory_highwater()]
-** <li> [sqlite3_soft_heap_limit()]
+** <li> [sqlite3_soft_heap_limit64()]
** <li> [sqlite3_status()]
** </ul>)^
** ^Memory allocation statistics are enabled by default unless SQLite is
@@ -1262,15 +1300,14 @@ struct sqlite3_mem_methods {
** aligned memory buffer from which the scrach 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.</dd>
**
** <dt>SQLITE_CONFIG_PAGECACHE</dt>
@@ -1290,8 +1327,7 @@ 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.</dd>
**
@@ -1420,8 +1456,14 @@ 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]</dd>
+** 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].)^</dd>
**
** </dl>
*/
@@ -1726,6 +1768,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 <b>result table</b> is memory data structure created by the
** [sqlite3_get_table()] interface. A result table records the
** complete query results from one or more queries.
@@ -1746,7 +1791,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:
**
** <blockquote><pre>
@@ -1770,7 +1815,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
** azResult&#91;5] = "28";
** azResult&#91;6] = "Cindy";
** azResult&#91;7] = "21";
-** </pre></blockquote>
+** </pre></blockquote>)^
**
** ^The sqlite3_get_table() function evaluates one or more
** semicolon-separated SQL statements in the zero-terminated UTF-8
@@ -1778,19 +1823,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 */
@@ -1815,7 +1860,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
@@ -1834,6 +1879,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
@@ -1897,6 +1944,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
@@ -1942,7 +1990,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
@@ -2200,17 +2250,28 @@ SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
/*
** 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.
@@ -2261,7 +2322,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** case the database must already exist, otherwise an error is returned.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt>
-** <dd>The database is opened for reading and writing, and is creates it if
+** <dd>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().</dd>)^
** </dl>
@@ -2269,7 +2330,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** 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,
+** [SQLITE_OPEN_SHAREDCACHE] and/or [SQLITE_OPEN_PRIVATECACHE] flags,
** then the behavior is undefined.
**
** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection
@@ -2394,17 +2455,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_<i>NAME</i> 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_<i>NAME</i>].
** (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
@@ -2433,7 +2499,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
**
** <dl>
** ^(<dt>SQLITE_LIMIT_LENGTH</dt>
-** <dd>The maximum size of any string or BLOB or table row.<dd>)^
+** <dd>The maximum size of any string or BLOB or table row, in bytes.<dd>)^
**
** ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt>
** <dd>The maximum length of an SQL statement, in bytes.</dd>)^
@@ -2451,7 +2517,9 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
**
** ^(<dt>SQLITE_LIMIT_VDBE_OP</dt>
** <dd>The maximum number of instructions in a virtual machine program
-** used to implement an SQL statement.</dd>)^
+** used to implement an SQL statement. This limit is not currently
+** enforced, though that might be added in some future release of
+** SQLite.</dd>)^
**
** ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt>
** <dd>The maximum number of arguments on a function.</dd>)^
@@ -2464,8 +2532,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** [GLOB] operators.</dd>)^
**
** ^(<dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt>
-** <dd>The maximum number of variables in an SQL statement that can
-** be bound.</dd>)^
+** <dd>The maximum index number of any [parameter] in an SQL statement.)^
**
** ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt>
** <dd>The maximum depth of recursion for triggers.</dd>)^
@@ -2537,12 +2604,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** <li>
** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it
** always used to do, [sqlite3_step()] will automatically recompile the SQL
-** statement and try to run it again. ^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.
** </li>
**
** <li>
@@ -2555,11 +2617,16 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** </li>
**
** <li>
-** ^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
** </li>
** </ol>
*/
@@ -2602,6 +2669,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:
+**
+** <blockquote><pre>
+** SELECT eval('DELETE FROM t1') FROM t2;
+** </pre></blockquote>
+**
+** 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}
**
@@ -2626,7 +2724,7 @@ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
** 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
@@ -2700,7 +2798,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
@@ -2821,6 +2922,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);
@@ -2986,13 +3089,17 @@ 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, it was required
-** after sqlite3_step() returned anything other than [SQLITE_ROW] that
-** [sqlite3_reset()] be called before any subsequent invocation of
-** sqlite3_step(). Failure to invoke [sqlite3_reset()] in this way 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].
+** 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.
**
** <b>Goofy Interface Alert:</b> In the legacy interface, the sqlite3_step()
** API always returns a generic error code, [SQLITE_ERROR], following any
@@ -3011,8 +3118,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);
@@ -3092,18 +3205,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
@@ -3148,10 +3269,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:
**
** <ul>
@@ -3164,22 +3285,22 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** <li> 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.</li>
-** </ul>)^
+** </ul>
**
** ^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:
**
** <ul>
** <li>sqlite3_column_text() followed by sqlite3_column_bytes()</li>
** <li>sqlite3_column_blob() followed by sqlite3_column_bytes()</li>
** <li>sqlite3_column_text16() followed by sqlite3_column_bytes16()</li>
-** </ul>)^
+** </ul>
**
** In other words, you should call sqlite3_column_text(),
** sqlite3_column_blob(), or sqlite3_column_text16() first to force the result
@@ -3217,17 +3338,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.
-**
-** ^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].
+** ^If the most recent evaluation of the statement encountered no errors or
+** 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].
+**
+** ^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);
@@ -3263,23 +3393,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 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
@@ -3289,10 +3421,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.
@@ -3304,13 +3436,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 poiners 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
@@ -3326,11 +3469,6 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** 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
@@ -3357,6 +3495,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
@@ -3400,7 +3549,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.
@@ -3703,46 +3852,79 @@ 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.
-**
-** ^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.
-**
-** 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 any more).
-** ^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 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).
+** 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 (eTextRep) must be one of the constants:
+** <ul>
+** <li> [SQLITE_UTF8],
+** <li> [SQLITE_UTF16LE],
+** <li> [SQLITE_UTF16BE],
+** <li> [SQLITE_UTF16], or
+** <li> [SQLITE_UTF16_ALIGNED].
+** </ul>)^
+** ^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.
+**
+** ^The fourth argument, pArg, is a application data pointer that is passed
+** through as the first argument to the collating function callback.
+**
+** ^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 alway 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:
+**
+** <ol>
+** <li> If A==B then B==A.
+** <li> If A==B and B==C then A==C.
+** <li> If A&lt;B THEN B&gt;A.
+** <li> If A&lt;B and B&lt;C then A&lt;C.
+** </ol>
+**
+** 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 <u>not</u> 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()].
*/
@@ -3750,14 +3932,14 @@ SQLITE_API int sqlite3_create_collation(
sqlite3*,
const char *zName,
int eTextRep,
- void*,
+ 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*,
+ void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*),
void(*xDestroy)(void*)
);
@@ -3765,7 +3947,7 @@ SQLITE_API int sqlite3_create_collation16(
sqlite3*,
const void *zName,
int eTextRep,
- void*,
+ void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*)
);
@@ -3854,16 +4036,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);
@@ -4085,40 +4270,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.
+** <ul>
+** <li> The soft heap limit is set to zero.
+** <li> 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.
+** <li> An alternative page cache implementation is specifed using
+** [sqlite3_config]([SQLITE_CONFIG_PCACHE],...).
+** <li> The page cache allocates from its own memory pool supplied
+** by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than
+** from the heap.
+** </ul>)^
+**
+** 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
@@ -4242,34 +4460,47 @@ 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 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.
+**
+** ^(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:
+**
+** <blockquote><pre>
+** &nbsp; int xEntryPoint(
+** &nbsp; sqlite3 *db,
+** &nbsp; const char **pzErrMsg,
+** &nbsp; const struct sqlite3_api_routines *pThunk
+** &nbsp; );
+** </pre></blockquote>)^
**
-** ^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].
+** 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.
**
-** ^(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()].)^
+** ^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.
**
-** ^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.
+** 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);
@@ -4449,7 +4680,9 @@ 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.
*/
@@ -4633,6 +4866,30 @@ SQLITE_API int sqlite3_blob_open(
);
/*
+** 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
**
** ^Closes an open [BLOB handle].
@@ -4908,7 +5165,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
@@ -5020,7 +5277,8 @@ 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
@@ -5039,7 +5297,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
@@ -5049,6 +5307,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()]
@@ -5105,7 +5369,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16
#define SQLITE_TESTCTRL_PGHDRSZ 17
-#define SQLITE_TESTCTRL_LAST 17
+#define SQLITE_TESTCTRL_SCRATCHMALLOC 18
+#define SQLITE_TESTCTRL_LAST 18
/*
** CAPI3REF: SQLite Runtime Status
@@ -5124,7 +5389,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
@@ -5164,7 +5429,8 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
** The value written into the *pCurrent parameter is undefined.</dd>)^
**
** ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt>
-** <dd>This parameter records the number of separate memory allocations.</dd>)^
+** <dd>This parameter records the number of separate memory allocations
+** currently checked out.</dd>)^
**
** ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt>
** <dd>This parameter returns the number of pages used out of the
@@ -5174,7 +5440,7 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
**
** ^(<dt>SQLITE_STATUS_PAGECACHE_OVERFLOW</dt>
** <dd>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
@@ -5197,7 +5463,7 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
**
** ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
** <dd>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
@@ -5246,6 +5512,9 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
** 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 int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
@@ -5267,6 +5536,28 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** <dd>This parameter returns the number of lookaside memory slots currently
** checked out.</dd>)^
**
+** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
+** <dd>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.
+** checked out.</dd>)^
+**
+** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt>
+** <dd>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.
+** checked out.</dd>)^
+**
+** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt>
+** <dd>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.
+** checked out.</dd>)^
+**
** ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
** <dd>This parameter returns the approximate number of of bytes of heap
** memory used by all pager caches associated with the database connection.)^
@@ -5289,11 +5580,14 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** </dd>
** </dl>
*/
-#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_MAX 3 /* Largest defined DBSTATUS */
+#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 */
/*
@@ -5372,32 +5666,42 @@ typedef struct sqlite3_pcache sqlite3_pcache;
**
** ^(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
+** 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() 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
+** 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() 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.
@@ -5405,47 +5709,52 @@ 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,
+** ^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() 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 xPagecount() method must return the number of pages currently
+** stored in the cache, both pinned and unpinned.
**
-** ^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 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
+** mimimum 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:
**
** <table border=1 width=85% align=center>
** <tr><th> createFlag <th> Behaviour when page is not already in cache
@@ -5454,36 +5763,35 @@ typedef struct sqlite3_pcache sqlite3_pcache;
** Otherwise return NULL.
** <tr><td> 2 <td> Make every effort to allocate a new page. Only return
** NULL if allocating a new page is effectively impossible.
-** </table>)^
+** </table>
**
-** 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.
**
** ^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
+** 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().)^
+** 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() 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.
**
@@ -5529,11 +5837,12 @@ typedef struct sqlite3_backup sqlite3_backup;
**
** 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:
@@ -5560,11 +5869,11 @@ typedef struct sqlite3_backup sqlite3_backup;
** 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
@@ -5581,7 +5890,7 @@ typedef struct sqlite3_backup sqlite3_backup;
** the source and destination databases specified by [sqlite3_backup] object B.
** ^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),
@@ -5595,7 +5904,7 @@ typedef struct sqlite3_backup sqlite3_backup;
** <li> the destination database was opened read-only, or
** <li> the destination database is using write-ahead-log journaling
** and the destination and source page sizes differ, or
-** <li> The destination database is an in-memory database and the
+** <li> the destination database is an in-memory database and the
** destination and source page sizes differ.
** </ol>)^
**
@@ -5926,7 +6235,8 @@ SQLITE_API void *sqlite3_wal_hook(
** from SQL.
**
** ^Every new [database connection] defaults to having the auto-checkpoint
-** enabled with a threshold of 1000 pages. The use of this interface
+** 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.
*/
@@ -5961,3 +6271,59 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
#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_
+
+
+#ifdef __cplusplus
+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 <rtree> WHERE <rtree col> 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 */
+};
+
+
+#ifdef __cplusplus
+} /* end of the 'extern "C"' block */
+#endif
+
+#endif /* ifndef _SQLITE3RTREE_H_ */
+
diff --git a/sqlite-3.7.2/sqlite3ext.h b/sqlite-3.7.5/sqlite3ext.h
index 0d37bbe..e45e691 100644
--- a/sqlite-3.7.2/sqlite3ext.h
+++ b/sqlite-3.7.5/sqlite3ext.h
@@ -191,6 +191,27 @@ struct sqlite3_api_routines {
sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
const char *(*sql)(sqlite3_stmt*);
int (*status)(int,int*,int*,int);
+ int (*backup_finish)(sqlite3_backup*);
+ sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
+ int (*backup_pagecount)(sqlite3_backup*);
+ int (*backup_remaining)(sqlite3_backup*);
+ int (*backup_step)(sqlite3_backup*,int);
+ const char *(*compileoption_get)(int);
+ int (*compileoption_used)(const char*);
+ int (*create_function_v2)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*),void(*xDestroy)(void*));
+ int (*db_config)(sqlite3*,int,...);
+ sqlite3_mutex *(*db_mutex)(sqlite3*);
+ int (*db_status)(sqlite3*,int,int*,int*,int);
+ int (*extended_errcode)(sqlite3*);
+ void (*log)(int,const char*,...);
+ sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
+ const char *(*sourceid)(void);
+ int (*stmt_status)(sqlite3_stmt*,int,int);
+ int (*strnicmp)(const char*,const char*,int);
+ int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
+ int (*wal_autocheckpoint)(sqlite3*,int);
+ int (*wal_checkpoint)(sqlite3*,const char*);
+ void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
};
/*
@@ -370,6 +391,27 @@ struct sqlite3_api_routines {
#define sqlite3_next_stmt sqlite3_api->next_stmt
#define sqlite3_sql sqlite3_api->sql
#define sqlite3_status sqlite3_api->status
+#define sqlite3_backup_finish sqlite3_api->backup_finish
+#define sqlite3_backup_init sqlite3_api->backup_init
+#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount
+#define sqlite3_backup_remaining sqlite3_api->backup_remaining
+#define sqlite3_backup_step sqlite3_api->backup_step
+#define sqlite3_compileoption_get sqlite3_api->compileoption_get
+#define sqlite3_compileoption_used sqlite3_api->compileoption_used
+#define sqlite3_create_function_v2 sqlite3_api->create_function_v2
+#define sqlite3_db_config sqlite3_api->db_config
+#define sqlite3_db_mutex sqlite3_api->db_mutex
+#define sqlite3_db_status sqlite3_api->db_status
+#define sqlite3_extended_errcode sqlite3_api->extended_errcode
+#define sqlite3_log sqlite3_api->log
+#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64
+#define sqlite3_sourceid sqlite3_api->sourceid
+#define sqlite3_stmt_status sqlite3_api->stmt_status
+#define sqlite3_strnicmp sqlite3_api->strnicmp
+#define sqlite3_unlock_notify sqlite3_api->unlock_notify
+#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
+#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
+#define sqlite3_wal_hook sqlite3_api->wal_hook
#endif /* SQLITE_CORE */
#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0;