summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnatol Belski <ab@php.net>2016-09-13 15:03:04 +0200
committerAnatol Belski <ab@php.net>2016-09-13 15:03:04 +0200
commit8773a2e820ce4f27e1c598749d15e739fcb22478 (patch)
tree2dddc012a22fc5093b823b11642b0a0481549af4
parent18b6f6ee016d558aafb9e7653696ada0f7dff280 (diff)
downloadphp-git-8773a2e820ce4f27e1c598749d15e739fcb22478.tar.gz
Revert "Update to SQLite3 3.13.0"
This reverts commit 81c25abd251014e32452da30c3d18afa73dc64af.
-rw-r--r--ext/sqlite3/libsqlite/sqlite3.c66128
-rw-r--r--ext/sqlite3/libsqlite/sqlite3.h2513
-rw-r--r--ext/sqlite3/libsqlite/sqlite3ext.h35
3 files changed, 12657 insertions, 56019 deletions
diff --git a/ext/sqlite3/libsqlite/sqlite3.c b/ext/sqlite3/libsqlite/sqlite3.c
index e198678908..dff4538dd3 100644
--- a/ext/sqlite3/libsqlite/sqlite3.c
+++ b/ext/sqlite3/libsqlite/sqlite3.c
@@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.13.0. By combining all the individual C code files into this
+** version 3.8.10.2. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@@ -40,41 +40,6 @@
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
-/* Special Comments:
-**
-** Some comments have special meaning to the tools that measure test
-** coverage:
-**
-** NO_TEST - The branches on this line are not
-** measured by branch coverage. This is
-** used on lines of code that actually
-** implement parts of coverage testing.
-**
-** OPTIMIZATION-IF-TRUE - This branch is allowed to alway be false
-** and the correct answer is still obtained,
-** though perhaps more slowly.
-**
-** OPTIMIZATION-IF-FALSE - This branch is allowed to alway be true
-** and the correct answer is still obtained,
-** though perhaps more slowly.
-**
-** PREVENTS-HARMLESS-OVERREAD - This branch prevents a buffer overread
-** that would be harmless and undetectable
-** if it did occur.
-**
-** In all cases, the special comment must be enclosed in the usual
-** slash-asterisk...asterisk-slash comment marks, with no spaces between the
-** asterisks and the comment text.
-*/
-
-/*
-** Make sure that rand_s() is available on Windows systems with MSVC 2005
-** or higher.
-*/
-#if defined(_MSC_VER) && _MSC_VER>=1400
-# define _CRT_RAND_S
-#endif
-
/*
** Include the header file used to customize the compiler options for MSVC.
** This should be done first so that it can successfully prevent spurious
@@ -156,9 +121,6 @@
#else
/* This is not VxWorks. */
#define OS_VXWORKS 0
-#define HAVE_FCHOWN 1
-#define HAVE_READLINK 1
-#define HAVE_LSTAT 1
#endif /* defined(_WRS_KERNEL) */
/************** End of vxworks.h *********************************************/
@@ -196,13 +158,6 @@
# define _LARGEFILE_SOURCE 1
#endif
-/* What version of GCC is being used. 0 means GCC is not being used */
-#ifdef __GNUC__
-# define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__)
-#else
-# define GCC_VERSION 0
-#endif
-
/* Needed for various definitions... */
#if defined(__GNUC__) && !defined(_GNU_SOURCE)
# define _GNU_SOURCE
@@ -275,7 +230,7 @@
**
** The official C-language API documentation for SQLite is derived
** from comments in this file. This file is the authoritative source
-** on how SQLite interfaces are supposed to operate.
+** on how SQLite interfaces are suppose to operate.
**
** The name of this file under configuration management is "sqlite.h.in".
** The makefile makes some minor changes to this file (such as inserting
@@ -363,9 +318,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.13.0"
-#define SQLITE_VERSION_NUMBER 3013000
-#define SQLITE_SOURCE_ID "2016-05-18 10:57:30 fc49f556e48970561d7ab6a2f24fdd7d9eb81ff2"
+#define SQLITE_VERSION "3.8.10.2"
+#define SQLITE_VERSION_NUMBER 3008010
+#define SQLITE_SOURCE_ID "2015-05-20 18:17:19 2ef4f3a5b1d1d0c4338f8243d40a2452cc1f7fe4"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -376,7 +331,7 @@ extern "C" {
** but are associated with the library instead of the header file. ^(Cautious
** programmers might include assert() statements in their application to
** verify that values returned by these interfaces match the macros in
-** the header, and thus ensure that the application is
+** the header, and thus insure that the application is
** compiled with matching library and header files.
**
** <blockquote><pre>
@@ -599,7 +554,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** from [sqlite3_malloc()] and passed back through the 5th parameter.
** To avoid memory leaks, the application should invoke [sqlite3_free()]
** on error message strings returned through the 5th parameter of
-** sqlite3_exec() after the error message string is no longer needed.
+** of sqlite3_exec() after the error message string is no longer needed.
** ^If the 5th parameter to sqlite3_exec() is not NULL and no errors
** occur, then sqlite3_exec() sets the pointer in its 5th parameter to
** NULL before returning.
@@ -626,7 +581,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** Restrictions:
**
** <ul>
-** <li> The application must ensure that the 1st parameter to sqlite3_exec()
+** <li> The application must insure that the 1st parameter to sqlite3_exec()
** is a valid and open [database connection].
** <li> The application must not close the [database connection] specified by
** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
@@ -729,8 +684,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8))
#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25<<8))
#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8))
-#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8))
-#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
@@ -1046,13 +999,8 @@ struct sqlite3_io_methods {
** <li>[[SQLITE_FCNTL_FILE_POINTER]]
** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer
** to the [sqlite3_file] object associated with a particular database
-** connection. See also [SQLITE_FCNTL_JOURNAL_POINTER].
-**
-** <li>[[SQLITE_FCNTL_JOURNAL_POINTER]]
-** The [SQLITE_FCNTL_JOURNAL_POINTER] opcode is used to obtain a pointer
-** to the [sqlite3_file] object associated with the journal file (either
-** the [rollback journal] or the [write-ahead log]) for a particular database
-** connection. See also [SQLITE_FCNTL_FILE_POINTER].
+** connection. See the [sqlite3_file_control()] documentation for
+** additional information.
**
** <li>[[SQLITE_FCNTL_SYNC_OMITTED]]
** No longer in use.
@@ -1139,15 +1087,6 @@ struct sqlite3_io_methods {
** pointer in case this file-control is not implemented. This file-control
** is intended for diagnostic use only.
**
-** <li>[[SQLITE_FCNTL_VFS_POINTER]]
-** ^The [SQLITE_FCNTL_VFS_POINTER] opcode finds a pointer to the top-level
-** [VFSes] currently in use. ^(The argument X in
-** sqlite3_file_control(db,SQLITE_FCNTL_VFS_POINTER,X) must be
-** of type "[sqlite3_vfs] **". This opcodes will set *X
-** to a pointer to the top-level VFS.)^
-** ^When there are multiple VFS shims in the stack, this opcode finds the
-** upper-most shim only.
-**
** <li>[[SQLITE_FCNTL_PRAGMA]]
** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA]
** file control is sent to the open [sqlite3_file] object corresponding
@@ -1231,14 +1170,6 @@ struct sqlite3_io_methods {
** circumstances in order to fix a problem with priority inversion.
** Applications should <em>not</em> use this file-control.
**
-** <li>[[SQLITE_FCNTL_ZIPVFS]]
-** The [SQLITE_FCNTL_ZIPVFS] opcode is implemented by zipvfs only. All other
-** VFS should return SQLITE_NOTFOUND for this opcode.
-**
-** <li>[[SQLITE_FCNTL_RBU]]
-** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by
-** the RBU extension only. All other VFS should return SQLITE_NOTFOUND for
-** this opcode.
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@@ -1264,10 +1195,6 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_COMMIT_PHASETWO 22
#define SQLITE_FCNTL_WIN32_SET_HANDLE 23
#define SQLITE_FCNTL_WAL_BLOCK 24
-#define SQLITE_FCNTL_ZIPVFS 25
-#define SQLITE_FCNTL_RBU 26
-#define SQLITE_FCNTL_VFS_POINTER 27
-#define SQLITE_FCNTL_JOURNAL_POINTER 28
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -1480,7 +1407,7 @@ struct sqlite3_vfs {
const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName);
/*
** The methods above are in versions 1 through 3 of the sqlite_vfs object.
- ** New fields may be appended in future versions. The iVersion
+ ** New fields may be appended in figure versions. The iVersion
** value will increment whenever this happens.
*/
};
@@ -1636,11 +1563,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
** applications and so this routine is usually not necessary. It is
** provided to support rare applications with unusual needs.
**
-** <b>The sqlite3_config() interface is not threadsafe. The application
-** must ensure that no other SQLite interfaces are invoked by other
-** threads while sqlite3_config() is running.</b>
-**
-** The sqlite3_config() interface
+** The sqlite3_config() interface is not threadsafe. The application
+** must insure that no other SQLite interfaces are invoked by other
+** threads while sqlite3_config() is running. Furthermore, sqlite3_config()
** may only be invoked prior to library initialization using
** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()].
** ^If sqlite3_config() is called after [sqlite3_initialize()] and before
@@ -1867,34 +1792,29 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
-** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool
+** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a static memory buffer
** that SQLite can use for the database page cache with the default page
** cache implementation.
-** This configuration option is a no-op if an application-define page
-** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2].
+** This configuration should not be used if an application-define page
+** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]
+** configuration option.
** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
-** 8-byte aligned memory (pMem), the size of each page cache line (sz),
-** and the number of cache lines (N).
+** 8-byte aligned
+** memory, the size of each page buffer (sz), and the number of pages (N).
** The sz argument should be the size of the largest database page
** (a power of two between 512 and 65536) plus some extra bytes for each
** page header. ^The number of extra bytes needed by the page header
-** can be determined using [SQLITE_CONFIG_PCACHE_HDRSZ].
+** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option
+** to [sqlite3_config()].
** ^It is harmless, apart from the wasted memory,
-** for the sz parameter to be larger than necessary. The pMem
-** argument must be either a NULL pointer or a pointer to an 8-byte
-** aligned block of memory of at least sz*N bytes, otherwise
-** subsequent behavior is undefined.
-** ^When pMem is not NULL, SQLite will strive to use the memory provided
-** to satisfy page cache needs, falling back to [sqlite3_malloc()] if
-** a page cache line is larger than sz bytes or if all of the pMem buffer
-** is exhausted.
-** ^If pMem is NULL and N is non-zero, then each database connection
-** does an initial bulk allocation for page cache memory
-** from [sqlite3_malloc()] sufficient for N cache lines if N is positive or
-** of -1024*N bytes if N is negative, . ^If additional
-** page cache memory is needed beyond what is provided by the initial
-** allocation, then SQLite goes to [sqlite3_malloc()] separately for each
-** additional cache line. </dd>
+** for the sz parameter to be larger than necessary. The first
+** argument should pointer to an 8-byte aligned block of memory that
+** is at least sz*N bytes of memory, otherwise subsequent behavior is
+** undefined.
+** ^SQLite will use the memory provided by the first argument to satisfy its
+** memory needs for the first N pages that it adds to cache. ^If additional
+** page cache memory is needed beyond what is provided by this option, then
+** SQLite goes to [sqlite3_malloc()] for the additional storage space.</dd>
**
** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer
@@ -2072,20 +1992,6 @@ struct sqlite3_mem_methods {
** is enabled (using the [PRAGMA threads] command) and the amount of content
** to be sorted exceeds the page size times the minimum of the
** [PRAGMA cache_size] setting and this value.
-**
-** [[SQLITE_CONFIG_STMTJRNL_SPILL]]
-** <dt>SQLITE_CONFIG_STMTJRNL_SPILL
-** <dd>^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which
-** becomes the [statement journal] spill-to-disk threshold.
-** [Statement journals] are held in memory until their size (in bytes)
-** exceeds this threshold, at which point they are written to disk.
-** Or if the threshold is -1, statement journals are always held
-** exclusively in memory.
-** Since many statement journals never become large, setting the spill
-** threshold to a value such as 64KiB can greatly reduce the amount of
-** I/O required to support statement rollback.
-** The default value for this setting is controlled by the
-** [SQLITE_STMTJRNL_SPILL] compile-time option.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -2113,7 +2019,6 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
-#define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -2171,43 +2076,11 @@ struct sqlite3_mem_methods {
** following this call. The second parameter may be a NULL pointer, in
** which case the trigger setting is not reported back. </dd>
**
-** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
-** <dd> ^This option is used to enable or disable the two-argument
-** version of the [fts3_tokenizer()] function which is part of the
-** [FTS3] full-text search engine extension.
-** There should be two additional arguments.
-** The first argument is an integer which is 0 to disable fts3_tokenizer() or
-** positive to enable fts3_tokenizer() or negative to leave the setting
-** unchanged.
-** The second parameter is a pointer to an integer into which
-** is written 0 or 1 to indicate whether fts3_tokenizer is disabled or enabled
-** following this call. The second parameter may be a NULL pointer, in
-** which case the new setting is not reported back. </dd>
-**
-** <dt>SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION</dt>
-** <dd> ^This option is used to enable or disable the [sqlite3_load_extension()]
-** interface independently of the [load_extension()] SQL function.
-** The [sqlite3_enable_load_extension()] API enables or disables both the
-** C-API [sqlite3_load_extension()] and the SQL function [load_extension()].
-** There should be two additional arguments.
-** When the first argument to this interface is 1, then only the C-API is
-** enabled and the SQL function remains disabled. If the first argment to
-** this interface is 0, then both the C-API and the SQL function are disabled.
-** If the first argument is -1, then no changes are made to state of either the
-** C-API or the SQL function.
-** The second parameter is a pointer to an integer into which
-** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface
-** is disabled or enabled following this call. The second parameter may
-** be a NULL pointer, in which case the new setting is not reported back.
-** </dd>
-**
** </dl>
*/
-#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
-#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
-#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
-#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */
-#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */
+#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
+#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
/*
@@ -3697,8 +3570,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
**
** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the
** [prepared statement] S has been stepped at least once using
-** [sqlite3_step(S)] but has neither run to completion (returned
-** [SQLITE_DONE] from [sqlite3_step(S)]) nor
+** [sqlite3_step(S)] but has not run to completion and/or has not
** been reset using [sqlite3_reset(S)]. ^The sqlite3_stmt_busy(S)
** interface returns false if S is a NULL pointer. If S is not a
** NULL pointer and is not a pointer to a valid [prepared statement]
@@ -3725,9 +3597,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*);
** Some interfaces require a protected sqlite3_value. Other interfaces
** will accept either a protected or an unprotected sqlite3_value.
** Every interface that accepts sqlite3_value arguments specifies
-** whether or not it requires a protected sqlite3_value. The
-** [sqlite3_value_dup()] interface can be used to construct a new
-** protected sqlite3_value from an unprotected sqlite3_value.
+** whether or not it requires a protected sqlite3_value.
**
** The terms "protected" and "unprotected" refer to whether or not
** a mutex is held. An internal mutex is held for a protected
@@ -3887,7 +3757,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(sqlite3_stmt*, int, const char
void(*)(void*), unsigned char encoding);
SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64);
/*
** CAPI3REF: Number Of SQL Parameters
@@ -3951,7 +3820,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*,
**
** See also: [sqlite3_bind_blob|sqlite3_bind()],
** [sqlite3_bind_parameter_count()], and
-** [sqlite3_bind_parameter_name()].
+** [sqlite3_bind_parameter_index()].
*/
SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
@@ -4231,6 +4100,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
** KEYWORDS: {column access functions}
** METHOD: sqlite3_stmt
**
+** These routines form the "result set" interface.
+**
** ^These routines return information about a single column of the current
** result row of a query. ^In every case the first argument is a pointer
** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*]
@@ -4290,14 +4161,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
** even empty strings, are always zero-terminated. ^The return
** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
**
-** <b>Warning:</b> ^The object returned by [sqlite3_column_value()] is an
-** [unprotected sqlite3_value] object. In a multithreaded environment,
-** an unprotected sqlite3_value object may only be used safely with
-** [sqlite3_bind_value()] and [sqlite3_result_value()].
+** ^The object returned by [sqlite3_column_value()] is an
+** [unprotected sqlite3_value] object. An unprotected sqlite3_value object
+** may only be used with [sqlite3_bind_value()] and [sqlite3_result_value()].
** If the [unprotected sqlite3_value] object returned by
** [sqlite3_column_value()] is used in any other way, including calls
** to routines like [sqlite3_value_int()], [sqlite3_value_text()],
-** or [sqlite3_value_bytes()], the behavior is not threadsafe.
+** or [sqlite3_value_bytes()], then the behavior is undefined.
**
** These routines attempt to convert the value where appropriate. ^For
** example, if the internal representation is FLOAT and a text result
@@ -4328,6 +4198,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
** </table>
** </blockquote>)^
**
+** The table above makes reference to standard C library functions atoi()
+** and atof(). SQLite does not really use these functions. It has its
+** own equivalent internal routines. The atoi() and atof() names are
+** 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
** calls to sqlite3_column_blob(), sqlite3_column_text(), and/or
** sqlite3_column_text16() may be invalidated.
@@ -4352,7 +4228,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
** 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 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>
@@ -4372,7 +4248,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
** ^The pointers returned are valid until a type conversion occurs as
** described above, or until [sqlite3_step()] or [sqlite3_reset()] or
** [sqlite3_finalize()] is called. ^The memory space used to hold strings
-** and BLOBs is freed automatically. Do <em>not</em> pass the pointers returned
+** and BLOBs is freed automatically. Do <b>not</b> pass the pointers returned
** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
** [sqlite3_free()].
**
@@ -4622,12 +4498,12 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
#endif
/*
-** CAPI3REF: Obtaining SQL Values
+** CAPI3REF: Obtaining SQL Function Parameter Values
** METHOD: sqlite3_value
**
** The C-language implementation of SQL functions and aggregates uses
** this set of interface routines to access the parameter values on
-** the function or aggregate.
+** the function or aggregate.
**
** The xFunc (for scalar functions) or xStep (for aggregates) parameters
** to [sqlite3_create_function()] and [sqlite3_create_function16()]
@@ -4681,39 +4557,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value*);
SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
/*
-** CAPI3REF: Finding The Subtype Of SQL Values
-** METHOD: sqlite3_value
-**
-** The sqlite3_value_subtype(V) function returns the subtype for
-** an [application-defined SQL function] argument V. The subtype
-** information can be used to pass a limited amount of context from
-** one SQL function to another. Use the [sqlite3_result_subtype()]
-** routine to set the subtype for the return value of an SQL function.
-**
-** SQLite makes no use of subtype itself. It merely passes the subtype
-** from the result of one [application-defined SQL function] into the
-** input of another.
-*/
-SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*);
-
-/*
-** CAPI3REF: Copy And Free SQL Values
-** METHOD: sqlite3_value
-**
-** ^The sqlite3_value_dup(V) interface makes a copy of the [sqlite3_value]
-** object D and returns a pointer to that copy. ^The [sqlite3_value] returned
-** is a [protected sqlite3_value] object even if the input is not.
-** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a
-** memory allocation fails.
-**
-** ^The sqlite3_value_free(V) interface frees an [sqlite3_value] object
-** previously obtained from [sqlite3_value_dup()]. ^If V is a NULL pointer
-** then sqlite3_value_free(V) is a harmless no-op.
-*/
-SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value*);
-SQLITE_API void SQLITE_STDCALL sqlite3_value_free(sqlite3_value*);
-
-/*
** CAPI3REF: Obtain Aggregate Function Context
** METHOD: sqlite3_context
**
@@ -4876,9 +4719,9 @@ typedef void (*sqlite3_destructor_type)(void*);
** to by the second parameter and which is N bytes long where N is the
** third parameter.
**
-** ^The sqlite3_result_zeroblob(C,N) and sqlite3_result_zeroblob64(C,N)
-** interfaces set the result of the application-defined function to be
-** a BLOB containing all zero bytes and N bytes in size.
+** ^The sqlite3_result_zeroblob() interfaces set the result of
+** the application-defined function to be a BLOB containing all zero
+** bytes and N bytes in size, where N is the value of the 2nd parameter.
**
** ^The sqlite3_result_double() interface sets the result from
** an application-defined function to be a floating point value specified
@@ -4960,7 +4803,7 @@ typedef void (*sqlite3_destructor_type)(void*);
** from [sqlite3_malloc()] before it returns.
**
** ^The sqlite3_result_value() interface sets the result of
-** the application-defined function to be a copy of the
+** the application-defined function to be a copy the
** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The
** sqlite3_result_value() interface makes a copy of the [sqlite3_value]
** so that the [sqlite3_value] specified in the parameter may change or
@@ -4993,22 +4836,6 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(sqlite3_context*, const v
SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context*, sqlite3_value*);
SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context*, int n);
-SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
-
-
-/*
-** CAPI3REF: Setting The Subtype Of An SQL Function
-** METHOD: sqlite3_context
-**
-** The sqlite3_result_subtype(C,T) function causes the subtype of
-** the result from the [application-defined SQL function] with
-** [sqlite3_context] C to be the value T. Only the lower 8 bits
-** of the subtype T are preserved in current versions of SQLite;
-** higher order bits are discarded.
-** The number of subtype bytes preserved by SQLite might increase
-** in future releases of SQLite.
-*/
-SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned int);
/*
** CAPI3REF: Define New Collating Sequences
@@ -5457,7 +5284,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
** ^The sqlite3_update_hook() interface registers a callback function
** with the [database connection] identified by the first argument
** to be invoked whenever a row is updated, inserted or deleted in
-** a [rowid table].
+** a rowid table.
** ^Any callback set by a previous call to this function
** for the same database connection is overridden.
**
@@ -5496,8 +5323,8 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
** on the same [database connection] D, or NULL for
** the first call on D.
**
-** See also the [sqlite3_commit_hook()], [sqlite3_rollback_hook()],
-** and [sqlite3_preupdate_hook()] interfaces.
+** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()]
+** interfaces.
*/
SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
sqlite3*,
@@ -5744,18 +5571,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
** should free this memory by calling [sqlite3_free()].
**
** ^Extension loading must be enabled using
-** [sqlite3_enable_load_extension()] or
-** [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],1,NULL)
-** prior to calling this API,
+** [sqlite3_enable_load_extension()] prior to calling this API,
** otherwise an error will be returned.
**
-** <b>Security warning:</b> It is recommended that the
-** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this
-** interface. The use of the [sqlite3_enable_load_extension()] interface
-** should be avoided. This will keep the SQL function [load_extension()]
-** disabled and prevent SQL injections from giving attackers
-** access to extension loading capabilities.
-**
** See also the [load_extension() SQL function].
*/
SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
@@ -5778,17 +5596,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
** ^Call the sqlite3_enable_load_extension() routine with onoff==1
** to turn extension loading on and call it with onoff==0 to turn
** it back off again.
-**
-** ^This interface enables or disables both the C-API
-** [sqlite3_load_extension()] and the SQL function [load_extension()].
-** Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..)
-** to enable or disable only the C-API.
-**
-** <b>Security warning:</b> It is recommended that extension loading
-** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method
-** rather than this interface, so the [load_extension()] SQL function
-** remains disabled. This will prevent SQL injections from giving attackers
-** access to extension loading capabilities.
*/
SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff);
@@ -5950,17 +5757,6 @@ struct sqlite3_module {
** ^Information about the ORDER BY clause is stored in aOrderBy[].
** ^Each term of aOrderBy records a column of the ORDER BY clause.
**
-** The colUsed field indicates which columns of the virtual table may be
-** required by the current scan. Virtual table columns are numbered from
-** zero in the order in which they appear within the CREATE TABLE statement
-** passed to sqlite3_declare_vtab(). For the first 63 columns (columns 0-62),
-** the corresponding bit is set within the colUsed mask if the column may be
-** required by SQLite. If the table has at least 64 columns and any column
-** to the right of the first 63 is required, then bit 63 of colUsed is also
-** set. In other words, column iCol may be required if the expression
-** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to
-** non-zero.
-**
** The [xBestIndex] method must fill aConstraintUsage[] with information
** about what parameters to pass to xFilter. ^If argvIndex>0 then
** the right-hand side of the corresponding aConstraint[] is evaluated
@@ -5986,37 +5782,19 @@ struct sqlite3_module {
** ^The estimatedRows value is an estimate of the number of rows that
** will be returned by the strategy.
**
-** The xBestIndex method may optionally populate the idxFlags field with a
-** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag -
-** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite
-** assumes that the strategy may visit at most one row.
-**
-** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
-** SQLite also assumes that if a call to the xUpdate() method is made as
-** part of the same statement to delete or update a virtual table row and the
-** implementation returns SQLITE_CONSTRAINT, then there is no need to rollback
-** any database changes. In other words, if the xUpdate() returns
-** SQLITE_CONSTRAINT, the database contents must be exactly as they were
-** before xUpdate was called. By contrast, if SQLITE_INDEX_SCAN_UNIQUE is not
-** set and xUpdate returns SQLITE_CONSTRAINT, any database changes made by
-** the xUpdate method are automatically rolled back by SQLite.
-**
** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
** structure for SQLite version 3.8.2. If a virtual table extension is
** used with an SQLite version earlier than 3.8.2, the results of attempting
** to read or write the estimatedRows field are undefined (but are likely
** to included crashing the application). The estimatedRows field should
** therefore only be used if [sqlite3_libversion_number()] returns a
-** value greater than or equal to 3008002. Similarly, the idxFlags field
-** was added for version 3.9.0. It may therefore only be used if
-** sqlite3_libversion_number() returns a value greater than or equal to
-** 3009000.
+** value greater than or equal to 3008002.
*/
struct sqlite3_index_info {
/* Inputs */
int nConstraint; /* Number of entries in aConstraint */
struct sqlite3_index_constraint {
- int iColumn; /* Column constrained. -1 for ROWID */
+ int iColumn; /* Column on left-hand side of constraint */
unsigned char op; /* Constraint operator */
unsigned char usable; /* True if this constraint is usable */
int iTermOffset; /* Used internally - xBestIndex should ignore */
@@ -6038,18 +5816,9 @@ struct sqlite3_index_info {
double estimatedCost; /* Estimated cost of using this index */
/* Fields below are only available in SQLite 3.8.2 and later */
sqlite3_int64 estimatedRows; /* Estimated number of rows returned */
- /* Fields below are only available in SQLite 3.9.0 and later */
- int idxFlags; /* Mask of SQLITE_INDEX_SCAN_* flags */
- /* Fields below are only available in SQLite 3.10.0 and later */
- sqlite3_uint64 colUsed; /* Input: Mask of columns used by statement */
};
/*
-** CAPI3REF: Virtual Table Scan Flags
-*/
-#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */
-
-/*
** CAPI3REF: Virtual Table Constraint Operator Codes
**
** These macros defined the allowed values for the
@@ -6057,15 +5826,12 @@ struct sqlite3_index_info {
** an operator that is part of a constraint term in the wHERE clause of
** a query that uses a [virtual table].
*/
-#define SQLITE_INDEX_CONSTRAINT_EQ 2
-#define SQLITE_INDEX_CONSTRAINT_GT 4
-#define SQLITE_INDEX_CONSTRAINT_LE 8
-#define SQLITE_INDEX_CONSTRAINT_LT 16
-#define SQLITE_INDEX_CONSTRAINT_GE 32
-#define SQLITE_INDEX_CONSTRAINT_MATCH 64
-#define SQLITE_INDEX_CONSTRAINT_LIKE 65
-#define SQLITE_INDEX_CONSTRAINT_GLOB 66
-#define SQLITE_INDEX_CONSTRAINT_REGEXP 67
+#define SQLITE_INDEX_CONSTRAINT_EQ 2
+#define SQLITE_INDEX_CONSTRAINT_GT 4
+#define SQLITE_INDEX_CONSTRAINT_LE 8
+#define SQLITE_INDEX_CONSTRAINT_LT 16
+#define SQLITE_INDEX_CONSTRAINT_GE 32
+#define SQLITE_INDEX_CONSTRAINT_MATCH 64
/*
** CAPI3REF: Register A Virtual Table Implementation
@@ -6313,7 +6079,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
**
** ^This function sets the database handle error code and message.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
+SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
/*
** CAPI3REF: Close A BLOB Handle
@@ -6509,9 +6275,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
** <li> SQLITE_MUTEX_STATIC_APP1
** <li> SQLITE_MUTEX_STATIC_APP2
** <li> SQLITE_MUTEX_STATIC_APP3
-** <li> SQLITE_MUTEX_STATIC_VFS1
-** <li> SQLITE_MUTEX_STATIC_VFS2
-** <li> SQLITE_MUTEX_STATIC_VFS3
** </ul>
**
** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
@@ -6713,9 +6476,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */
#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */
#define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */
-#define SQLITE_MUTEX_STATIC_VFS1 11 /* For use by built-in VFS */
-#define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */
-#define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */
/*
** CAPI3REF: Retrieve the mutex for a database connection
@@ -6929,8 +6689,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
** The value written into the *pCurrent parameter is undefined.</dd>)^
**
** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
-** <dd>The *pHighwater parameter records the deepest parser stack.
-** The *pCurrent value is undefined. The *pHighwater value is only
+** <dd>This parameter records the deepest parser stack. It is only
** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^
** </dl>
**
@@ -7427,7 +7186,7 @@ typedef struct sqlite3_backup sqlite3_backup;
** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
** an error.
**
-** ^A call to sqlite3_backup_init() will fail, returning NULL, if
+** ^A call to sqlite3_backup_init() will fail, returning SQLITE_ERROR, if
** there is already a read or read-write transaction open on the
** destination database.
**
@@ -7716,44 +7475,19 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *, const char *, int);
/*
** CAPI3REF: String Globbing
*
-** ^The [sqlite3_strglob(P,X)] interface returns zero if and only if
-** string X matches the [GLOB] pattern P.
-** ^The definition of [GLOB] pattern matching used in
+** ^The [sqlite3_strglob(P,X)] interface returns zero if string X matches
+** the glob pattern P, and it returns non-zero if string X does not match
+** the glob pattern P. ^The definition of glob pattern matching used in
** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the
-** SQL dialect understood by SQLite. ^The [sqlite3_strglob(P,X)] function
-** is case sensitive.
+** SQL dialect used by SQLite. ^The sqlite3_strglob(P,X) function is case
+** sensitive.
**
** Note that this routine returns zero on a match and non-zero if the strings
** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
-**
-** See also: [sqlite3_strlike()].
*/
SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zStr);
/*
-** CAPI3REF: String LIKE Matching
-*
-** ^The [sqlite3_strlike(P,X,E)] interface returns zero if and only if
-** string X matches the [LIKE] pattern P with escape character E.
-** ^The definition of [LIKE] pattern matching used in
-** [sqlite3_strlike(P,X,E)] is the same as for the "X LIKE P ESCAPE E"
-** operator in the SQL dialect understood by SQLite. ^For "X LIKE P" without
-** the ESCAPE clause, set the E parameter of [sqlite3_strlike(P,X,E)] to 0.
-** ^As with the LIKE operator, the [sqlite3_strlike(P,X,E)] function is case
-** insensitive - equivalent upper and lower case ASCII characters match
-** one another.
-**
-** ^The [sqlite3_strlike(P,X,E)] function matches Unicode characters, though
-** only ASCII characters are case folded.
-**
-** Note that this routine returns zero on a match and non-zero if the strings
-** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
-**
-** See also: [sqlite3_strglob()].
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc);
-
-/*
** CAPI3REF: Error Logging Interface
**
** ^The [sqlite3_log()] interface writes a message into the [error log]
@@ -7808,7 +7542,7 @@ SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...)
** previously registered write-ahead log callback. ^Note that the
** [sqlite3_wal_autocheckpoint()] interface and the
** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
-** overwrite any prior [sqlite3_wal_hook()] settings.
+** those overwrite any prior [sqlite3_wal_hook()] settings.
*/
SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
sqlite3*,
@@ -8155,7 +7889,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *);
**
** See also: [sqlite3_stmt_scanstatus_reset()]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
+SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_stmt_scanstatus(
sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
int idx, /* Index of loop to report on */
int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
@@ -8171,279 +7905,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
** This API is only available if the library is built with pre-processor
** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
-
-/*
-** CAPI3REF: Flush caches to disk mid-transaction
-**
-** ^If a write-transaction is open on [database connection] D when the
-** [sqlite3_db_cacheflush(D)] interface invoked, any dirty
-** pages in the pager-cache that are not currently in use are written out
-** to disk. A dirty page may be in use if a database cursor created by an
-** active SQL statement is reading from it, or if it is page 1 of a database
-** file (page 1 is always "in use"). ^The [sqlite3_db_cacheflush(D)]
-** interface flushes caches for all schemas - "main", "temp", and
-** any [attached] databases.
-**
-** ^If this function needs to obtain extra database locks before dirty pages
-** can be flushed to disk, it does so. ^If those locks cannot be obtained
-** immediately and there is a busy-handler callback configured, it is invoked
-** in the usual manner. ^If the required lock still cannot be obtained, then
-** the database is skipped and an attempt made to flush any dirty pages
-** belonging to the next (if any) database. ^If any databases are skipped
-** because locks cannot be obtained, but no other error occurs, this
-** function returns SQLITE_BUSY.
-**
-** ^If any other error occurs while flushing dirty pages to disk (for
-** example an IO error or out-of-memory condition), then processing is
-** abandoned and an SQLite [error code] is returned to the caller immediately.
-**
-** ^Otherwise, if no error occurs, [sqlite3_db_cacheflush()] returns SQLITE_OK.
-**
-** ^This function does not set the database handle error code or message
-** returned by the [sqlite3_errcode()] and [sqlite3_errmsg()] functions.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3_db_cacheflush(sqlite3*);
-
-/*
-** CAPI3REF: The pre-update hook.
-**
-** ^These interfaces are only available if SQLite is compiled using the
-** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option.
-**
-** ^The [sqlite3_preupdate_hook()] interface registers a callback function
-** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation
-** on a [rowid table].
-** ^At most one preupdate hook may be registered at a time on a single
-** [database connection]; each call to [sqlite3_preupdate_hook()] overrides
-** the previous setting.
-** ^The preupdate hook is disabled by invoking [sqlite3_preupdate_hook()]
-** with a NULL pointer as the second parameter.
-** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as
-** the first parameter to callbacks.
-**
-** ^The preupdate hook only fires for changes to [rowid tables]; the preupdate
-** hook is not invoked for changes to [virtual tables] or [WITHOUT ROWID]
-** tables.
-**
-** ^The second parameter to the preupdate callback is a pointer to
-** the [database connection] that registered the preupdate hook.
-** ^The third parameter to the preupdate callback is one of the constants
-** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to indentify the
-** kind of update operation that is about to occur.
-** ^(The fourth parameter to the preupdate callback is the name of the
-** database within the database connection that is being modified. This
-** will be "main" for the main database or "temp" for TEMP tables or
-** the name given after the AS keyword in the [ATTACH] statement for attached
-** databases.)^
-** ^The fifth parameter to the preupdate callback is the name of the
-** table that is being modified.
-** ^The sixth parameter to the preupdate callback is the initial [rowid] of the
-** row being changes for SQLITE_UPDATE and SQLITE_DELETE changes and is
-** undefined for SQLITE_INSERT changes.
-** ^The seventh parameter to the preupdate callback is the final [rowid] of
-** the row being changed for SQLITE_UPDATE and SQLITE_INSERT changes and is
-** undefined for SQLITE_DELETE changes.
-**
-** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
-** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
-** provide additional information about a preupdate event. These routines
-** may only be called from within a preupdate callback. Invoking any of
-** these routines from outside of a preupdate callback or with a
-** [database connection] pointer that is different from the one supplied
-** to the preupdate callback results in undefined and probably undesirable
-** behavior.
-**
-** ^The [sqlite3_preupdate_count(D)] interface returns the number of columns
-** in the row that is being inserted, updated, or deleted.
-**
-** ^The [sqlite3_preupdate_old(D,N,P)] interface writes into P a pointer to
-** a [protected sqlite3_value] that contains the value of the Nth column of
-** the table row before it is updated. The N parameter must be between 0
-** and one less than the number of columns or the behavior will be
-** undefined. This must only be used within SQLITE_UPDATE and SQLITE_DELETE
-** preupdate callbacks; if it is used by an SQLITE_INSERT callback then the
-** behavior is undefined. The [sqlite3_value] that P points to
-** will be destroyed when the preupdate callback returns.
-**
-** ^The [sqlite3_preupdate_new(D,N,P)] interface writes into P a pointer to
-** a [protected sqlite3_value] that contains the value of the Nth column of
-** the table row after it is updated. The N parameter must be between 0
-** and one less than the number of columns or the behavior will be
-** undefined. This must only be used within SQLITE_INSERT and SQLITE_UPDATE
-** preupdate callbacks; if it is used by an SQLITE_DELETE callback then the
-** behavior is undefined. The [sqlite3_value] that P points to
-** will be destroyed when the preupdate callback returns.
-**
-** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate
-** callback was invoked as a result of a direct insert, update, or delete
-** operation; or 1 for inserts, updates, or deletes invoked by top-level
-** triggers; or 2 for changes resulting from triggers called by top-level
-** triggers; and so forth.
-**
-** See also: [sqlite3_update_hook()]
-*/
-SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_preupdate_hook(
- sqlite3 *db,
- void(*xPreUpdate)(
- void *pCtx, /* Copy of third arg to preupdate_hook() */
- sqlite3 *db, /* Database handle */
- int op, /* SQLITE_UPDATE, DELETE or INSERT */
- char const *zDb, /* Database name */
- char const *zName, /* Table name */
- sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */
- sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */
- ),
- void*
-);
-SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
-SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_preupdate_count(sqlite3 *);
-SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_preupdate_depth(sqlite3 *);
-SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
-
-/*
-** CAPI3REF: Low-level system error code
-**
-** ^Attempt to return the underlying operating system error code or error
-** number that caused the most recent I/O error or failure to open a file.
-** The return value is OS-dependent. For example, on unix systems, after
-** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be
-** called to get back the underlying "errno" that caused the problem, such
-** as ENOSPC, EAUTH, EISDIR, and so forth.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3_system_errno(sqlite3*);
-
-/*
-** CAPI3REF: Database Snapshot
-** KEYWORDS: {snapshot}
-** EXPERIMENTAL
-**
-** An instance of the snapshot object records the state of a [WAL mode]
-** database for some specific point in history.
-**
-** In [WAL mode], multiple [database connections] that are open on the
-** same database file can each be reading a different historical version
-** of the database file. When a [database connection] begins a read
-** transaction, that connection sees an unchanging copy of the database
-** as it existed for the point in time when the transaction first started.
-** Subsequent changes to the database from other connections are not seen
-** by the reader until a new read transaction is started.
-**
-** The sqlite3_snapshot object records state information about an historical
-** version of the database file so that it is possible to later open a new read
-** transaction that sees that historical version of the database rather than
-** the most recent version.
-**
-** The constructor for this object is [sqlite3_snapshot_get()]. The
-** [sqlite3_snapshot_open()] method causes a fresh read transaction to refer
-** to an historical snapshot (if possible). The destructor for
-** sqlite3_snapshot objects is [sqlite3_snapshot_free()].
-*/
-typedef struct sqlite3_snapshot sqlite3_snapshot;
-
-/*
-** CAPI3REF: Record A Database Snapshot
-** EXPERIMENTAL
-**
-** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a
-** new [sqlite3_snapshot] object that records the current state of
-** schema S in database connection D. ^On success, the
-** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
-** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
-** ^If schema S of [database connection] D is not a [WAL mode] database
-** that is in a read transaction, then [sqlite3_snapshot_get(D,S,P)]
-** leaves the *P value unchanged and returns an appropriate [error code].
-**
-** The [sqlite3_snapshot] object returned from a successful call to
-** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()]
-** to avoid a memory leak.
-**
-** The [sqlite3_snapshot_get()] interface is only available when the
-** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
-*/
-SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_get(
- sqlite3 *db,
- const char *zSchema,
- sqlite3_snapshot **ppSnapshot
-);
+SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
-/*
-** CAPI3REF: Start a read transaction on an historical snapshot
-** EXPERIMENTAL
-**
-** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a
-** read transaction for schema S of
-** [database connection] D such that the read transaction
-** refers to historical [snapshot] P, rather than the most
-** recent change to the database.
-** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success
-** or an appropriate [error code] if it fails.
-**
-** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be
-** the first operation following the [BEGIN] that takes the schema S
-** out of [autocommit mode].
-** ^In other words, schema S must not currently be in
-** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the
-** database connection D must be out of [autocommit mode].
-** ^A [snapshot] will fail to open if it has been overwritten by a
-** [checkpoint].
-** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the
-** database connection D does not know that the database file for
-** schema S is in [WAL mode]. A database connection might not know
-** that the database file is in [WAL mode] if there has been no prior
-** I/O on that database connection, or if the database entered [WAL mode]
-** after the most recent I/O on the database connection.)^
-** (Hint: Run "[PRAGMA application_id]" against a newly opened
-** database connection in order to make it ready to use snapshots.)
-**
-** The [sqlite3_snapshot_open()] interface is only available when the
-** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
-*/
-SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_open(
- sqlite3 *db,
- const char *zSchema,
- sqlite3_snapshot *pSnapshot
-);
-
-/*
-** CAPI3REF: Destroy a snapshot
-** EXPERIMENTAL
-**
-** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P.
-** The application must eventually free every [sqlite3_snapshot] object
-** using this routine to avoid a memory leak.
-**
-** The [sqlite3_snapshot_free()] interface is only available when the
-** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
-*/
-SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_snapshot_free(sqlite3_snapshot*);
-
-/*
-** CAPI3REF: Compare the ages of two snapshot handles.
-** EXPERIMENTAL
-**
-** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages
-** of two valid snapshot handles.
-**
-** If the two snapshot handles are not associated with the same database
-** file, the result of the comparison is undefined.
-**
-** Additionally, the result of the comparison is only valid if both of the
-** snapshot handles were obtained by calling sqlite3_snapshot_get() since the
-** last time the wal file was deleted. The wal file is deleted when the
-** database is changed back to rollback mode or when the number of database
-** clients drops to zero. If either snapshot handle was obtained before the
-** wal file was last deleted, the value returned by this function
-** is undefined.
-**
-** Otherwise, this API returns a negative value if P1 refers to an older
-** snapshot than P2, zero if the two handles refer to the same database
-** snapshot, and a positive value if P1 is a newer snapshot than P2.
-*/
-SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_cmp(
- sqlite3_snapshot *p1,
- sqlite3_snapshot *p2
-);
/*
** Undo the hack that converts floating point types to integer for
@@ -8458,7 +7921,6 @@ SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_cmp(
#endif
#endif /* _SQLITE3_H_ */
-/******** Begin file sqlite3rtree.h *********/
/*
** 2010 August 30
**
@@ -8558,8 +8020,6 @@ struct sqlite3_rtree_query_info {
int eParentWithin; /* Visibility of parent node */
int eWithin; /* OUT: Visiblity */
sqlite3_rtree_dbl rScore; /* OUT: Write the score here */
- /* The following fields are only available in 3.8.11 and later */
- sqlite3_value **apSqlParam; /* Original SQL values of parameters */
};
/*
@@ -8576,1868 +8036,6 @@ struct sqlite3_rtree_query_info {
#endif /* ifndef _SQLITE3RTREE_H_ */
-/******** End of sqlite3rtree.h *********/
-/******** Begin file sqlite3session.h *********/
-
-#if !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION)
-#define __SQLITESESSION_H_ 1
-
-/*
-** Make sure we can call this stuff from C++.
-*/
-#if 0
-extern "C" {
-#endif
-
-
-/*
-** CAPI3REF: Session Object Handle
-*/
-typedef struct sqlite3_session sqlite3_session;
-
-/*
-** CAPI3REF: Changeset Iterator Handle
-*/
-typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
-
-/*
-** CAPI3REF: Create A New Session Object
-**
-** Create a new session object attached to database handle db. If successful,
-** a pointer to the new object is written to *ppSession and SQLITE_OK is
-** returned. If an error occurs, *ppSession is set to NULL and an SQLite
-** error code (e.g. SQLITE_NOMEM) is returned.
-**
-** It is possible to create multiple session objects attached to a single
-** database handle.
-**
-** Session objects created using this function should be deleted using the
-** [sqlite3session_delete()] function before the database handle that they
-** are attached to is itself closed. If the database handle is closed before
-** the session object is deleted, then the results of calling any session
-** module function, including [sqlite3session_delete()] on the session object
-** are undefined.
-**
-** Because the session module uses the [sqlite3_preupdate_hook()] API, it
-** is not possible for an application to register a pre-update hook on a
-** database handle that has one or more session objects attached. Nor is
-** it possible to create a session object attached to a database handle for
-** which a pre-update hook is already defined. The results of attempting
-** either of these things are undefined.
-**
-** The session object will be used to create changesets for tables in
-** database zDb, where zDb is either "main", or "temp", or the name of an
-** attached database. It is not an error if database zDb is not attached
-** to the database when the session object is created.
-*/
-int sqlite3session_create(
- sqlite3 *db, /* Database handle */
- const char *zDb, /* Name of db (e.g. "main") */
- sqlite3_session **ppSession /* OUT: New session object */
-);
-
-/*
-** CAPI3REF: Delete A Session Object
-**
-** Delete a session object previously allocated using
-** [sqlite3session_create()]. Once a session object has been deleted, the
-** results of attempting to use pSession with any other session module
-** function are undefined.
-**
-** Session objects must be deleted before the database handle to which they
-** are attached is closed. Refer to the documentation for
-** [sqlite3session_create()] for details.
-*/
-void sqlite3session_delete(sqlite3_session *pSession);
-
-
-/*
-** CAPI3REF: Enable Or Disable A Session Object
-**
-** Enable or disable the recording of changes by a session object. When
-** enabled, a session object records changes made to the database. When
-** disabled - it does not. A newly created session object is enabled.
-** Refer to the documentation for [sqlite3session_changeset()] for further
-** details regarding how enabling and disabling a session object affects
-** the eventual changesets.
-**
-** Passing zero to this function disables the session. Passing a value
-** greater than zero enables it. Passing a value less than zero is a
-** no-op, and may be used to query the current state of the session.
-**
-** The return value indicates the final state of the session object: 0 if
-** the session is disabled, or 1 if it is enabled.
-*/
-int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
-
-/*
-** CAPI3REF: Set Or Clear the Indirect Change Flag
-**
-** Each change recorded by a session object is marked as either direct or
-** indirect. A change is marked as indirect if either:
-**
-** <ul>
-** <li> The session object "indirect" flag is set when the change is
-** made, or
-** <li> The change is made by an SQL trigger or foreign key action
-** instead of directly as a result of a users SQL statement.
-** </ul>
-**
-** If a single row is affected by more than one operation within a session,
-** then the change is considered indirect if all operations meet the criteria
-** for an indirect change above, or direct otherwise.
-**
-** This function is used to set, clear or query the session object indirect
-** flag. If the second argument passed to this function is zero, then the
-** indirect flag is cleared. If it is greater than zero, the indirect flag
-** is set. Passing a value less than zero does not modify the current value
-** of the indirect flag, and may be used to query the current state of the
-** indirect flag for the specified session object.
-**
-** The return value indicates the final state of the indirect flag: 0 if
-** it is clear, or 1 if it is set.
-*/
-int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect);
-
-/*
-** CAPI3REF: Attach A Table To A Session Object
-**
-** If argument zTab is not NULL, then it is the name of a table to attach
-** to the session object passed as the first argument. All subsequent changes
-** made to the table while the session object is enabled will be recorded. See
-** documentation for [sqlite3session_changeset()] for further details.
-**
-** Or, if argument zTab is NULL, then changes are recorded for all tables
-** in the database. If additional tables are added to the database (by
-** executing "CREATE TABLE" statements) after this call is made, changes for
-** the new tables are also recorded.
-**
-** Changes can only be recorded for tables that have a PRIMARY KEY explicitly
-** defined as part of their CREATE TABLE statement. It does not matter if the
-** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY
-** KEY may consist of a single column, or may be a composite key.
-**
-** It is not an error if the named table does not exist in the database. Nor
-** is it an error if the named table does not have a PRIMARY KEY. However,
-** no changes will be recorded in either of these scenarios.
-**
-** Changes are not recorded for individual rows that have NULL values stored
-** in one or more of their PRIMARY KEY columns.
-**
-** SQLITE_OK is returned if the call completes without error. Or, if an error
-** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
-*/
-int sqlite3session_attach(
- sqlite3_session *pSession, /* Session object */
- const char *zTab /* Table name */
-);
-
-/*
-** CAPI3REF: Set a table filter on a Session Object.
-**
-** The second argument (xFilter) is the "filter callback". For changes to rows
-** in tables that are not attached to the Session oject, the filter is called
-** to determine whether changes to the table's rows should be tracked or not.
-** If xFilter returns 0, changes is not tracked. Note that once a table is
-** attached, xFilter will not be called again.
-*/
-void sqlite3session_table_filter(
- sqlite3_session *pSession, /* Session object */
- int(*xFilter)(
- void *pCtx, /* Copy of third arg to _filter_table() */
- const char *zTab /* Table name */
- ),
- void *pCtx /* First argument passed to xFilter */
-);
-
-/*
-** CAPI3REF: Generate A Changeset From A Session Object
-**
-** Obtain a changeset containing changes to the tables attached to the
-** session object passed as the first argument. If successful,
-** set *ppChangeset to point to a buffer containing the changeset
-** and *pnChangeset to the size of the changeset in bytes before returning
-** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to
-** zero and return an SQLite error code.
-**
-** A changeset consists of zero or more INSERT, UPDATE and/or DELETE changes,
-** each representing a change to a single row of an attached table. An INSERT
-** change contains the values of each field of a new database row. A DELETE
-** contains the original values of each field of a deleted database row. An
-** UPDATE change contains the original values of each field of an updated
-** database row along with the updated values for each updated non-primary-key
-** column. It is not possible for an UPDATE change to represent a change that
-** modifies the values of primary key columns. If such a change is made, it
-** is represented in a changeset as a DELETE followed by an INSERT.
-**
-** Changes are not recorded for rows that have NULL values stored in one or
-** more of their PRIMARY KEY columns. If such a row is inserted or deleted,
-** no corresponding change is present in the changesets returned by this
-** function. If an existing row with one or more NULL values stored in
-** PRIMARY KEY columns is updated so that all PRIMARY KEY columns are non-NULL,
-** only an INSERT is appears in the changeset. Similarly, if an existing row
-** with non-NULL PRIMARY KEY values is updated so that one or more of its
-** PRIMARY KEY columns are set to NULL, the resulting changeset contains a
-** DELETE change only.
-**
-** The contents of a changeset may be traversed using an iterator created
-** using the [sqlite3changeset_start()] API. A changeset may be applied to
-** a database with a compatible schema using the [sqlite3changeset_apply()]
-** API.
-**
-** Within a changeset generated by this function, all changes related to a
-** single table are grouped together. In other words, when iterating through
-** a changeset or when applying a changeset to a database, all changes related
-** to a single table are processed before moving on to the next table. Tables
-** are sorted in the same order in which they were attached (or auto-attached)
-** to the sqlite3_session object. The order in which the changes related to
-** a single table are stored is undefined.
-**
-** Following a successful call to this function, it is the responsibility of
-** the caller to eventually free the buffer that *ppChangeset points to using
-** [sqlite3_free()].
-**
-** <h3>Changeset Generation</h3>
-**
-** Once a table has been attached to a session object, the session object
-** records the primary key values of all new rows inserted into the table.
-** It also records the original primary key and other column values of any
-** deleted or updated rows. For each unique primary key value, data is only
-** recorded once - the first time a row with said primary key is inserted,
-** updated or deleted in the lifetime of the session.
-**
-** There is one exception to the previous paragraph: when a row is inserted,
-** updated or deleted, if one or more of its primary key columns contain a
-** NULL value, no record of the change is made.
-**
-** The session object therefore accumulates two types of records - those
-** that consist of primary key values only (created when the user inserts
-** a new record) and those that consist of the primary key values and the
-** original values of other table columns (created when the users deletes
-** or updates a record).
-**
-** When this function is called, the requested changeset is created using
-** both the accumulated records and the current contents of the database
-** file. Specifically:
-**
-** <ul>
-** <li> For each record generated by an insert, the database is queried
-** for a row with a matching primary key. If one is found, an INSERT
-** change is added to the changeset. If no such row is found, no change
-** is added to the changeset.
-**
-** <li> For each record generated by an update or delete, the database is
-** queried for a row with a matching primary key. If such a row is
-** found and one or more of the non-primary key fields have been
-** modified from their original values, an UPDATE change is added to
-** the changeset. Or, if no such row is found in the table, a DELETE
-** change is added to the changeset. If there is a row with a matching
-** primary key in the database, but all fields contain their original
-** values, no change is added to the changeset.
-** </ul>
-**
-** This means, amongst other things, that if a row is inserted and then later
-** deleted while a session object is active, neither the insert nor the delete
-** will be present in the changeset. Or if a row is deleted and then later a
-** row with the same primary key values inserted while a session object is
-** active, the resulting changeset will contain an UPDATE change instead of
-** a DELETE and an INSERT.
-**
-** When a session object is disabled (see the [sqlite3session_enable()] API),
-** it does not accumulate records when rows are inserted, updated or deleted.
-** This may appear to have some counter-intuitive effects if a single row
-** is written to more than once during a session. For example, if a row
-** is inserted while a session object is enabled, then later deleted while
-** the same session object is disabled, no INSERT record will appear in the
-** changeset, even though the delete took place while the session was disabled.
-** Or, if one field of a row is updated while a session is disabled, and
-** another field of the same row is updated while the session is enabled, the
-** resulting changeset will contain an UPDATE change that updates both fields.
-*/
-int sqlite3session_changeset(
- sqlite3_session *pSession, /* Session object */
- int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */
- void **ppChangeset /* OUT: Buffer containing changeset */
-);
-
-/*
-** CAPI3REF: Load The Difference Between Tables Into A Session
-**
-** If it is not already attached to the session object passed as the first
-** argument, this function attaches table zTbl in the same manner as the
-** [sqlite3session_attach()] function. If zTbl does not exist, or if it
-** does not have a primary key, this function is a no-op (but does not return
-** an error).
-**
-** Argument zFromDb must be the name of a database ("main", "temp" etc.)
-** attached to the same database handle as the session object that contains
-** a table compatible with the table attached to the session by this function.
-** A table is considered compatible if it:
-**
-** <ul>
-** <li> Has the same name,
-** <li> Has the same set of columns declared in the same order, and
-** <li> Has the same PRIMARY KEY definition.
-** </ul>
-**
-** If the tables are not compatible, SQLITE_SCHEMA is returned. If the tables
-** are compatible but do not have any PRIMARY KEY columns, it is not an error
-** but no changes are added to the session object. As with other session
-** APIs, tables without PRIMARY KEYs are simply ignored.
-**
-** This function adds a set of changes to the session object that could be
-** used to update the table in database zFrom (call this the "from-table")
-** so that its content is the same as the table attached to the session
-** object (call this the "to-table"). Specifically:
-**
-** <ul>
-** <li> For each row (primary key) that exists in the to-table but not in
-** the from-table, an INSERT record is added to the session object.
-**
-** <li> For each row (primary key) that exists in the to-table but not in
-** the from-table, a DELETE record is added to the session object.
-**
-** <li> For each row (primary key) that exists in both tables, but features
-** different in each, an UPDATE record is added to the session.
-** </ul>
-**
-** To clarify, if this function is called and then a changeset constructed
-** using [sqlite3session_changeset()], then after applying that changeset to
-** database zFrom the contents of the two compatible tables would be
-** identical.
-**
-** It an error if database zFrom does not exist or does not contain the
-** required compatible table.
-**
-** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite
-** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
-** may be set to point to a buffer containing an English language error
-** message. It is the responsibility of the caller to free this buffer using
-** sqlite3_free().
-*/
-int sqlite3session_diff(
- sqlite3_session *pSession,
- const char *zFromDb,
- const char *zTbl,
- char **pzErrMsg
-);
-
-
-/*
-** CAPI3REF: Generate A Patchset From A Session Object
-**
-** The differences between a patchset and a changeset are that:
-**
-** <ul>
-** <li> DELETE records consist of the primary key fields only. The
-** original values of other fields are omitted.
-** <li> The original values of any modified fields are omitted from
-** UPDATE records.
-** </ul>
-**
-** A patchset blob may be used with up to date versions of all
-** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(),
-** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly,
-** attempting to use a patchset blob with old versions of the
-** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error.
-**
-** Because the non-primary key "old.*" fields are omitted, no
-** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset
-** is passed to the sqlite3changeset_apply() API. Other conflict types work
-** in the same way as for changesets.
-**
-** Changes within a patchset are ordered in the same way as for changesets
-** generated by the sqlite3session_changeset() function (i.e. all changes for
-** a single table are grouped together, tables appear in the order in which
-** they were attached to the session object).
-*/
-int sqlite3session_patchset(
- sqlite3_session *pSession, /* Session object */
- int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */
- void **ppPatchset /* OUT: Buffer containing changeset */
-);
-
-/*
-** CAPI3REF: Test if a changeset has recorded any changes.
-**
-** Return non-zero if no changes to attached tables have been recorded by
-** the session object passed as the first argument. Otherwise, if one or
-** more changes have been recorded, return zero.
-**
-** Even if this function returns zero, it is possible that calling
-** [sqlite3session_changeset()] on the session handle may still return a
-** changeset that contains no changes. This can happen when a row in
-** an attached table is modified and then later on the original values
-** are restored. However, if this function returns non-zero, then it is
-** guaranteed that a call to sqlite3session_changeset() will return a
-** changeset containing zero changes.
-*/
-int sqlite3session_isempty(sqlite3_session *pSession);
-
-/*
-** CAPI3REF: Create An Iterator To Traverse A Changeset
-**
-** Create an iterator used to iterate through the contents of a changeset.
-** If successful, *pp is set to point to the iterator handle and SQLITE_OK
-** is returned. Otherwise, if an error occurs, *pp is set to zero and an
-** SQLite error code is returned.
-**
-** The following functions can be used to advance and query a changeset
-** iterator created by this function:
-**
-** <ul>
-** <li> [sqlite3changeset_next()]
-** <li> [sqlite3changeset_op()]
-** <li> [sqlite3changeset_new()]
-** <li> [sqlite3changeset_old()]
-** </ul>
-**
-** It is the responsibility of the caller to eventually destroy the iterator
-** by passing it to [sqlite3changeset_finalize()]. The buffer containing the
-** changeset (pChangeset) must remain valid until after the iterator is
-** destroyed.
-**
-** Assuming the changeset blob was created by one of the
-** [sqlite3session_changeset()], [sqlite3changeset_concat()] or
-** [sqlite3changeset_invert()] functions, all changes within the changeset
-** that apply to a single table are grouped together. This means that when
-** an application iterates through a changeset using an iterator created by
-** this function, all changes that relate to a single table are visted
-** consecutively. There is no chance that the iterator will visit a change
-** the applies to table X, then one for table Y, and then later on visit
-** another change for table X.
-*/
-int sqlite3changeset_start(
- sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */
- int nChangeset, /* Size of changeset blob in bytes */
- void *pChangeset /* Pointer to blob containing changeset */
-);
-
-
-/*
-** CAPI3REF: Advance A Changeset Iterator
-**
-** This function may only be used with iterators created by function
-** [sqlite3changeset_start()]. If it is called on an iterator passed to
-** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE
-** is returned and the call has no effect.
-**
-** Immediately after an iterator is created by sqlite3changeset_start(), it
-** does not point to any change in the changeset. Assuming the changeset
-** is not empty, the first call to this function advances the iterator to
-** point to the first change in the changeset. Each subsequent call advances
-** the iterator to point to the next change in the changeset (if any). If
-** no error occurs and the iterator points to a valid change after a call
-** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned.
-** Otherwise, if all changes in the changeset have already been visited,
-** SQLITE_DONE is returned.
-**
-** If an error occurs, an SQLite error code is returned. Possible error
-** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or
-** SQLITE_NOMEM.
-*/
-int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
-
-/*
-** CAPI3REF: Obtain The Current Operation From A Changeset Iterator
-**
-** The pIter argument passed to this function may either be an iterator
-** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
-** created by [sqlite3changeset_start()]. In the latter case, the most recent
-** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this
-** is not the case, this function returns [SQLITE_MISUSE].
-**
-** If argument pzTab is not NULL, then *pzTab is set to point to a
-** nul-terminated utf-8 encoded string containing the name of the table
-** affected by the current change. The buffer remains valid until either
-** sqlite3changeset_next() is called on the iterator or until the
-** conflict-handler function returns. If pnCol is not NULL, then *pnCol is
-** set to the number of columns in the table affected by the change. If
-** pbIncorrect is not NULL, then *pbIndirect is set to true (1) if the change
-** is an indirect change, or false (0) otherwise. See the documentation for
-** [sqlite3session_indirect()] for a description of direct and indirect
-** changes. Finally, if pOp is not NULL, then *pOp is set to one of
-** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the
-** type of change that the iterator currently points to.
-**
-** If no error occurs, SQLITE_OK is returned. If an error does occur, an
-** SQLite error code is returned. The values of the output variables may not
-** be trusted in this case.
-*/
-int sqlite3changeset_op(
- sqlite3_changeset_iter *pIter, /* Iterator object */
- const char **pzTab, /* OUT: Pointer to table name */
- int *pnCol, /* OUT: Number of columns in table */
- int *pOp, /* OUT: SQLITE_INSERT, DELETE or UPDATE */
- int *pbIndirect /* OUT: True for an 'indirect' change */
-);
-
-/*
-** CAPI3REF: Obtain The Primary Key Definition Of A Table
-**
-** For each modified table, a changeset includes the following:
-**
-** <ul>
-** <li> The number of columns in the table, and
-** <li> Which of those columns make up the tables PRIMARY KEY.
-** </ul>
-**
-** This function is used to find which columns comprise the PRIMARY KEY of
-** the table modified by the change that iterator pIter currently points to.
-** If successful, *pabPK is set to point to an array of nCol entries, where
-** nCol is the number of columns in the table. Elements of *pabPK are set to
-** 0x01 if the corresponding column is part of the tables primary key, or
-** 0x00 if it is not.
-**
-** If argumet pnCol is not NULL, then *pnCol is set to the number of columns
-** in the table.
-**
-** If this function is called when the iterator does not point to a valid
-** entry, SQLITE_MISUSE is returned and the output variables zeroed. Otherwise,
-** SQLITE_OK is returned and the output variables populated as described
-** above.
-*/
-int sqlite3changeset_pk(
- sqlite3_changeset_iter *pIter, /* Iterator object */
- unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */
- int *pnCol /* OUT: Number of entries in output array */
-);
-
-/*
-** CAPI3REF: Obtain old.* Values From A Changeset Iterator
-**
-** The pIter argument passed to this function may either be an iterator
-** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
-** created by [sqlite3changeset_start()]. In the latter case, the most recent
-** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
-** Furthermore, it may only be called if the type of change that the iterator
-** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise,
-** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
-**
-** Argument iVal must be greater than or equal to 0, and less than the number
-** of columns in the table affected by the current change. Otherwise,
-** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
-**
-** If successful, this function sets *ppValue to point to a protected
-** sqlite3_value object containing the iVal'th value from the vector of
-** original row values stored as part of the UPDATE or DELETE change and
-** returns SQLITE_OK. The name of the function comes from the fact that this
-** is similar to the "old.*" columns available to update or delete triggers.
-**
-** If some other error occurs (e.g. an OOM condition), an SQLite error code
-** is returned and *ppValue is set to NULL.
-*/
-int sqlite3changeset_old(
- sqlite3_changeset_iter *pIter, /* Changeset iterator */
- int iVal, /* Column number */
- sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */
-);
-
-/*
-** CAPI3REF: Obtain new.* Values From A Changeset Iterator
-**
-** The pIter argument passed to this function may either be an iterator
-** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
-** created by [sqlite3changeset_start()]. In the latter case, the most recent
-** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
-** Furthermore, it may only be called if the type of change that the iterator
-** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise,
-** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
-**
-** Argument iVal must be greater than or equal to 0, and less than the number
-** of columns in the table affected by the current change. Otherwise,
-** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
-**
-** If successful, this function sets *ppValue to point to a protected
-** sqlite3_value object containing the iVal'th value from the vector of
-** new row values stored as part of the UPDATE or INSERT change and
-** returns SQLITE_OK. If the change is an UPDATE and does not include
-** a new value for the requested column, *ppValue is set to NULL and
-** SQLITE_OK returned. The name of the function comes from the fact that
-** this is similar to the "new.*" columns available to update or delete
-** triggers.
-**
-** If some other error occurs (e.g. an OOM condition), an SQLite error code
-** is returned and *ppValue is set to NULL.
-*/
-int sqlite3changeset_new(
- sqlite3_changeset_iter *pIter, /* Changeset iterator */
- int iVal, /* Column number */
- sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */
-);
-
-/*
-** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator
-**
-** This function should only be used with iterator objects passed to a
-** conflict-handler callback by [sqlite3changeset_apply()] with either
-** [SQLITE_CHANGESET_DATA] or [SQLITE_CHANGESET_CONFLICT]. If this function
-** is called on any other iterator, [SQLITE_MISUSE] is returned and *ppValue
-** is set to NULL.
-**
-** Argument iVal must be greater than or equal to 0, and less than the number
-** of columns in the table affected by the current change. Otherwise,
-** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
-**
-** If successful, this function sets *ppValue to point to a protected
-** sqlite3_value object containing the iVal'th value from the
-** "conflicting row" associated with the current conflict-handler callback
-** and returns SQLITE_OK.
-**
-** If some other error occurs (e.g. an OOM condition), an SQLite error code
-** is returned and *ppValue is set to NULL.
-*/
-int sqlite3changeset_conflict(
- sqlite3_changeset_iter *pIter, /* Changeset iterator */
- int iVal, /* Column number */
- sqlite3_value **ppValue /* OUT: Value from conflicting row */
-);
-
-/*
-** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations
-**
-** This function may only be called with an iterator passed to an
-** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case
-** it sets the output variable to the total number of known foreign key
-** violations in the destination database and returns SQLITE_OK.
-**
-** In all other cases this function returns SQLITE_MISUSE.
-*/
-int sqlite3changeset_fk_conflicts(
- sqlite3_changeset_iter *pIter, /* Changeset iterator */
- int *pnOut /* OUT: Number of FK violations */
-);
-
-
-/*
-** CAPI3REF: Finalize A Changeset Iterator
-**
-** This function is used to finalize an iterator allocated with
-** [sqlite3changeset_start()].
-**
-** This function should only be called on iterators created using the
-** [sqlite3changeset_start()] function. If an application calls this
-** function with an iterator passed to a conflict-handler by
-** [sqlite3changeset_apply()], [SQLITE_MISUSE] is immediately returned and the
-** call has no effect.
-**
-** If an error was encountered within a call to an sqlite3changeset_xxx()
-** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an
-** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding
-** to that error is returned by this function. Otherwise, SQLITE_OK is
-** returned. This is to allow the following pattern (pseudo-code):
-**
-** sqlite3changeset_start();
-** while( SQLITE_ROW==sqlite3changeset_next() ){
-** // Do something with change.
-** }
-** rc = sqlite3changeset_finalize();
-** if( rc!=SQLITE_OK ){
-** // An error has occurred
-** }
-*/
-int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
-
-/*
-** CAPI3REF: Invert A Changeset
-**
-** This function is used to "invert" a changeset object. Applying an inverted
-** changeset to a database reverses the effects of applying the uninverted
-** changeset. Specifically:
-**
-** <ul>
-** <li> Each DELETE change is changed to an INSERT, and
-** <li> Each INSERT change is changed to a DELETE, and
-** <li> For each UPDATE change, the old.* and new.* values are exchanged.
-** </ul>
-**
-** This function does not change the order in which changes appear within
-** the changeset. It merely reverses the sense of each individual change.
-**
-** If successful, a pointer to a buffer containing the inverted changeset
-** is stored in *ppOut, the size of the same buffer is stored in *pnOut, and
-** SQLITE_OK is returned. If an error occurs, both *pnOut and *ppOut are
-** zeroed and an SQLite error code returned.
-**
-** It is the responsibility of the caller to eventually call sqlite3_free()
-** on the *ppOut pointer to free the buffer allocation following a successful
-** call to this function.
-**
-** WARNING/TODO: This function currently assumes that the input is a valid
-** changeset. If it is not, the results are undefined.
-*/
-int sqlite3changeset_invert(
- int nIn, const void *pIn, /* Input changeset */
- int *pnOut, void **ppOut /* OUT: Inverse of input */
-);
-
-/*
-** CAPI3REF: Concatenate Two Changeset Objects
-**
-** This function is used to concatenate two changesets, A and B, into a
-** single changeset. The result is a changeset equivalent to applying
-** changeset A followed by changeset B.
-**
-** This function combines the two input changesets using an
-** sqlite3_changegroup object. Calling it produces similar results as the
-** following code fragment:
-**
-** sqlite3_changegroup *pGrp;
-** rc = sqlite3_changegroup_new(&pGrp);
-** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA);
-** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nB, pB);
-** if( rc==SQLITE_OK ){
-** rc = sqlite3changegroup_output(pGrp, pnOut, ppOut);
-** }else{
-** *ppOut = 0;
-** *pnOut = 0;
-** }
-**
-** Refer to the sqlite3_changegroup documentation below for details.
-*/
-int sqlite3changeset_concat(
- int nA, /* Number of bytes in buffer pA */
- void *pA, /* Pointer to buffer containing changeset A */
- int nB, /* Number of bytes in buffer pB */
- void *pB, /* Pointer to buffer containing changeset B */
- int *pnOut, /* OUT: Number of bytes in output changeset */
- void **ppOut /* OUT: Buffer containing output changeset */
-);
-
-
-/*
-** Changegroup handle.
-*/
-typedef struct sqlite3_changegroup sqlite3_changegroup;
-
-/*
-** CAPI3REF: Combine two or more changesets into a single changeset.
-**
-** An sqlite3_changegroup object is used to combine two or more changesets
-** (or patchsets) into a single changeset (or patchset). A single changegroup
-** object may combine changesets or patchsets, but not both. The output is
-** always in the same format as the input.
-**
-** If successful, this function returns SQLITE_OK and populates (*pp) with
-** a pointer to a new sqlite3_changegroup object before returning. The caller
-** should eventually free the returned object using a call to
-** sqlite3changegroup_delete(). If an error occurs, an SQLite error code
-** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL.
-**
-** The usual usage pattern for an sqlite3_changegroup object is as follows:
-**
-** <ul>
-** <li> It is created using a call to sqlite3changegroup_new().
-**
-** <li> Zero or more changesets (or patchsets) are added to the object
-** by calling sqlite3changegroup_add().
-**
-** <li> The result of combining all input changesets together is obtained
-** by the application via a call to sqlite3changegroup_output().
-**
-** <li> The object is deleted using a call to sqlite3changegroup_delete().
-** </ul>
-**
-** Any number of calls to add() and output() may be made between the calls to
-** new() and delete(), and in any order.
-**
-** As well as the regular sqlite3changegroup_add() and
-** sqlite3changegroup_output() functions, also available are the streaming
-** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm().
-*/
-int sqlite3changegroup_new(sqlite3_changegroup **pp);
-
-/*
-** Add all changes within the changeset (or patchset) in buffer pData (size
-** nData bytes) to the changegroup.
-**
-** If the buffer contains a patchset, then all prior calls to this function
-** on the same changegroup object must also have specified patchsets. Or, if
-** the buffer contains a changeset, so must have the earlier calls to this
-** function. Otherwise, SQLITE_ERROR is returned and no changes are added
-** to the changegroup.
-**
-** Rows within the changeset and changegroup are identified by the values in
-** their PRIMARY KEY columns. A change in the changeset is considered to
-** apply to the same row as a change already present in the changegroup if
-** the two rows have the same primary key.
-**
-** Changes to rows that that do not already appear in the changegroup are
-** simply copied into it. Or, if both the new changeset and the changegroup
-** contain changes that apply to a single row, the final contents of the
-** changegroup depends on the type of each change, as follows:
-**
-** <table border=1 style="margin-left:8ex;margin-right:8ex">
-** <tr><th style="white-space:pre">Existing Change </th>
-** <th style="white-space:pre">New Change </th>
-** <th>Output Change
-** <tr><td>INSERT <td>INSERT <td>
-** The new change is ignored. This case does not occur if the new
-** changeset was recorded immediately after the changesets already
-** added to the changegroup.
-** <tr><td>INSERT <td>UPDATE <td>
-** The INSERT change remains in the changegroup. The values in the
-** INSERT change are modified as if the row was inserted by the
-** existing change and then updated according to the new change.
-** <tr><td>INSERT <td>DELETE <td>
-** The existing INSERT is removed from the changegroup. The DELETE is
-** not added.
-** <tr><td>UPDATE <td>INSERT <td>
-** The new change is ignored. This case does not occur if the new
-** changeset was recorded immediately after the changesets already
-** added to the changegroup.
-** <tr><td>UPDATE <td>UPDATE <td>
-** The existing UPDATE remains within the changegroup. It is amended
-** so that the accompanying values are as if the row was updated once
-** by the existing change and then again by the new change.
-** <tr><td>UPDATE <td>DELETE <td>
-** The existing UPDATE is replaced by the new DELETE within the
-** changegroup.
-** <tr><td>DELETE <td>INSERT <td>
-** If one or more of the column values in the row inserted by the
-** new change differ from those in the row deleted by the existing
-** change, the existing DELETE is replaced by an UPDATE within the
-** changegroup. Otherwise, if the inserted row is exactly the same
-** as the deleted row, the existing DELETE is simply discarded.
-** <tr><td>DELETE <td>UPDATE <td>
-** The new change is ignored. This case does not occur if the new
-** changeset was recorded immediately after the changesets already
-** added to the changegroup.
-** <tr><td>DELETE <td>DELETE <td>
-** The new change is ignored. This case does not occur if the new
-** changeset was recorded immediately after the changesets already
-** added to the changegroup.
-** </table>
-**
-** If the new changeset contains changes to a table that is already present
-** in the changegroup, then the number of columns and the position of the
-** primary key columns for the table must be consistent. If this is not the
-** case, this function fails with SQLITE_SCHEMA. If the input changeset
-** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
-** returned. Or, if an out-of-memory condition occurs during processing, this
-** function returns SQLITE_NOMEM. In all cases, if an error occurs the
-** final contents of the changegroup is undefined.
-**
-** If no error occurs, SQLITE_OK is returned.
-*/
-int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
-
-/*
-** Obtain a buffer containing a changeset (or patchset) representing the
-** current contents of the changegroup. If the inputs to the changegroup
-** were themselves changesets, the output is a changeset. Or, if the
-** inputs were patchsets, the output is also a patchset.
-**
-** As with the output of the sqlite3session_changeset() and
-** sqlite3session_patchset() functions, all changes related to a single
-** table are grouped together in the output of this function. Tables appear
-** in the same order as for the very first changeset added to the changegroup.
-** If the second or subsequent changesets added to the changegroup contain
-** changes for tables that do not appear in the first changeset, they are
-** appended onto the end of the output changeset, again in the order in
-** which they are first encountered.
-**
-** If an error occurs, an SQLite error code is returned and the output
-** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK
-** is returned and the output variables are set to the size of and a
-** pointer to the output buffer, respectively. In this case it is the
-** responsibility of the caller to eventually free the buffer using a
-** call to sqlite3_free().
-*/
-int sqlite3changegroup_output(
- sqlite3_changegroup*,
- int *pnData, /* OUT: Size of output buffer in bytes */
- void **ppData /* OUT: Pointer to output buffer */
-);
-
-/*
-** Delete a changegroup object.
-*/
-void sqlite3changegroup_delete(sqlite3_changegroup*);
-
-/*
-** CAPI3REF: Apply A Changeset To A Database
-**
-** Apply a changeset to a database. This function attempts to update the
-** "main" database attached to handle db with the changes found in the
-** changeset passed via the second and third arguments.
-**
-** The fourth argument (xFilter) passed to this function is the "filter
-** callback". If it is not NULL, then for each table affected by at least one
-** change in the changeset, the filter callback is invoked with
-** the table name as the second argument, and a copy of the context pointer
-** passed as the sixth argument to this function as the first. If the "filter
-** callback" returns zero, then no attempt is made to apply any changes to
-** the table. Otherwise, if the return value is non-zero or the xFilter
-** argument to this function is NULL, all changes related to the table are
-** attempted.
-**
-** For each table that is not excluded by the filter callback, this function
-** tests that the target database contains a compatible table. A table is
-** considered compatible if all of the following are true:
-**
-** <ul>
-** <li> The table has the same name as the name recorded in the
-** changeset, and
-** <li> The table has the same number of columns as recorded in the
-** changeset, and
-** <li> The table has primary key columns in the same position as
-** recorded in the changeset.
-** </ul>
-**
-** If there is no compatible table, it is not an error, but none of the
-** changes associated with the table are applied. A warning message is issued
-** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most
-** one such warning is issued for each table in the changeset.
-**
-** For each change for which there is a compatible table, an attempt is made
-** to modify the table contents according to the UPDATE, INSERT or DELETE
-** change. If a change cannot be applied cleanly, the conflict handler
-** function passed as the fifth argument to sqlite3changeset_apply() may be
-** invoked. A description of exactly when the conflict handler is invoked for
-** each type of change is below.
-**
-** Unlike the xFilter argument, xConflict may not be passed NULL. The results
-** of passing anything other than a valid function pointer as the xConflict
-** argument are undefined.
-**
-** Each time the conflict handler function is invoked, it must return one
-** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or
-** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned
-** if the second argument passed to the conflict handler is either
-** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler
-** returns an illegal value, any changes already made are rolled back and
-** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different
-** actions are taken by sqlite3changeset_apply() depending on the value
-** returned by each invocation of the conflict-handler function. Refer to
-** the documentation for the three
-** [SQLITE_CHANGESET_OMIT|available return values] for details.
-**
-** <dl>
-** <dt>DELETE Changes<dd>
-** For each DELETE change, this function checks if the target database
-** contains a row with the same primary key value (or values) as the
-** original row values stored in the changeset. If it does, and the values
-** stored in all non-primary key columns also match the values stored in
-** the changeset the row is deleted from the target database.
-**
-** If a row with matching primary key values is found, but one or more of
-** the non-primary key fields contains a value different from the original
-** row value stored in the changeset, the conflict-handler function is
-** invoked with [SQLITE_CHANGESET_DATA] as the second argument.
-**
-** If no row with matching primary key values is found in the database,
-** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
-** passed as the second argument.
-**
-** If the DELETE operation is attempted, but SQLite returns SQLITE_CONSTRAINT
-** (which can only happen if a foreign key constraint is violated), the
-** conflict-handler function is invoked with [SQLITE_CHANGESET_CONSTRAINT]
-** passed as the second argument. This includes the case where the DELETE
-** operation is attempted because an earlier call to the conflict handler
-** function returned [SQLITE_CHANGESET_REPLACE].
-**
-** <dt>INSERT Changes<dd>
-** For each INSERT change, an attempt is made to insert the new row into
-** the database.
-**
-** If the attempt to insert the row fails because the database already
-** contains a row with the same primary key values, the conflict handler
-** function is invoked with the second argument set to
-** [SQLITE_CHANGESET_CONFLICT].
-**
-** If the attempt to insert the row fails because of some other constraint
-** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is
-** invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT].
-** This includes the case where the INSERT operation is re-attempted because
-** an earlier call to the conflict handler function returned
-** [SQLITE_CHANGESET_REPLACE].
-**
-** <dt>UPDATE Changes<dd>
-** For each UPDATE change, this function checks if the target database
-** contains a row with the same primary key value (or values) as the
-** original row values stored in the changeset. If it does, and the values
-** stored in all non-primary key columns also match the values stored in
-** the changeset the row is updated within the target database.
-**
-** If a row with matching primary key values is found, but one or more of
-** the non-primary key fields contains a value different from an original
-** row value stored in the changeset, the conflict-handler function is
-** invoked with [SQLITE_CHANGESET_DATA] as the second argument. Since
-** UPDATE changes only contain values for non-primary key fields that are
-** to be modified, only those fields need to match the original values to
-** avoid the SQLITE_CHANGESET_DATA conflict-handler callback.
-**
-** If no row with matching primary key values is found in the database,
-** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
-** passed as the second argument.
-**
-** If the UPDATE operation is attempted, but SQLite returns
-** SQLITE_CONSTRAINT, the conflict-handler function is invoked with
-** [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument.
-** This includes the case where the UPDATE operation is attempted after
-** an earlier call to the conflict handler function returned
-** [SQLITE_CHANGESET_REPLACE].
-** </dl>
-**
-** It is safe to execute SQL statements, including those that write to the
-** table that the callback related to, from within the xConflict callback.
-** This can be used to further customize the applications conflict
-** resolution strategy.
-**
-** All changes made by this function are enclosed in a savepoint transaction.
-** If any other error (aside from a constraint failure when attempting to
-** write to the target database) occurs, then the savepoint transaction is
-** rolled back, restoring the target database to its original state, and an
-** SQLite error code returned.
-*/
-int sqlite3changeset_apply(
- sqlite3 *db, /* Apply change to "main" db of this handle */
- int nChangeset, /* Size of changeset in bytes */
- void *pChangeset, /* Changeset blob */
- int(*xFilter)(
- void *pCtx, /* Copy of sixth arg to _apply() */
- const char *zTab /* Table name */
- ),
- int(*xConflict)(
- void *pCtx, /* Copy of sixth arg to _apply() */
- int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
- sqlite3_changeset_iter *p /* Handle describing change and conflict */
- ),
- void *pCtx /* First argument passed to xConflict */
-);
-
-/*
-** CAPI3REF: Constants Passed To The Conflict Handler
-**
-** Values that may be passed as the second argument to a conflict-handler.
-**
-** <dl>
-** <dt>SQLITE_CHANGESET_DATA<dd>
-** The conflict handler is invoked with CHANGESET_DATA as the second argument
-** when processing a DELETE or UPDATE change if a row with the required
-** PRIMARY KEY fields is present in the database, but one or more other
-** (non primary-key) fields modified by the update do not contain the
-** expected "before" values.
-**
-** The conflicting row, in this case, is the database row with the matching
-** primary key.
-**
-** <dt>SQLITE_CHANGESET_NOTFOUND<dd>
-** The conflict handler is invoked with CHANGESET_NOTFOUND as the second
-** argument when processing a DELETE or UPDATE change if a row with the
-** required PRIMARY KEY fields is not present in the database.
-**
-** There is no conflicting row in this case. The results of invoking the
-** sqlite3changeset_conflict() API are undefined.
-**
-** <dt>SQLITE_CHANGESET_CONFLICT<dd>
-** CHANGESET_CONFLICT is passed as the second argument to the conflict
-** handler while processing an INSERT change if the operation would result
-** in duplicate primary key values.
-**
-** The conflicting row in this case is the database row with the matching
-** primary key.
-**
-** <dt>SQLITE_CHANGESET_FOREIGN_KEY<dd>
-** If foreign key handling is enabled, and applying a changeset leaves the
-** database in a state containing foreign key violations, the conflict
-** handler is invoked with CHANGESET_FOREIGN_KEY as the second argument
-** exactly once before the changeset is committed. If the conflict handler
-** returns CHANGESET_OMIT, the changes, including those that caused the
-** foreign key constraint violation, are committed. Or, if it returns
-** CHANGESET_ABORT, the changeset is rolled back.
-**
-** No current or conflicting row information is provided. The only function
-** it is possible to call on the supplied sqlite3_changeset_iter handle
-** is sqlite3changeset_fk_conflicts().
-**
-** <dt>SQLITE_CHANGESET_CONSTRAINT<dd>
-** If any other constraint violation occurs while applying a change (i.e.
-** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is
-** invoked with CHANGESET_CONSTRAINT as the second argument.
-**
-** There is no conflicting row in this case. The results of invoking the
-** sqlite3changeset_conflict() API are undefined.
-**
-** </dl>
-*/
-#define SQLITE_CHANGESET_DATA 1
-#define SQLITE_CHANGESET_NOTFOUND 2
-#define SQLITE_CHANGESET_CONFLICT 3
-#define SQLITE_CHANGESET_CONSTRAINT 4
-#define SQLITE_CHANGESET_FOREIGN_KEY 5
-
-/*
-** CAPI3REF: Constants Returned By The Conflict Handler
-**
-** A conflict handler callback must return one of the following three values.
-**
-** <dl>
-** <dt>SQLITE_CHANGESET_OMIT<dd>
-** If a conflict handler returns this value no special action is taken. The
-** change that caused the conflict is not applied. The session module
-** continues to the next change in the changeset.
-**
-** <dt>SQLITE_CHANGESET_REPLACE<dd>
-** This value may only be returned if the second argument to the conflict
-** handler was SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If this
-** is not the case, any changes applied so far are rolled back and the
-** call to sqlite3changeset_apply() returns SQLITE_MISUSE.
-**
-** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_DATA conflict
-** handler, then the conflicting row is either updated or deleted, depending
-** on the type of change.
-**
-** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_CONFLICT conflict
-** handler, then the conflicting row is removed from the database and a
-** second attempt to apply the change is made. If this second attempt fails,
-** the original row is restored to the database before continuing.
-**
-** <dt>SQLITE_CHANGESET_ABORT<dd>
-** If this value is returned, any changes applied so far are rolled back
-** and the call to sqlite3changeset_apply() returns SQLITE_ABORT.
-** </dl>
-*/
-#define SQLITE_CHANGESET_OMIT 0
-#define SQLITE_CHANGESET_REPLACE 1
-#define SQLITE_CHANGESET_ABORT 2
-
-/*
-** CAPI3REF: Streaming Versions of API functions.
-**
-** The six streaming API xxx_strm() functions serve similar purposes to the
-** corresponding non-streaming API functions:
-**
-** <table border=1 style="margin-left:8ex;margin-right:8ex">
-** <tr><th>Streaming function<th>Non-streaming equivalent</th>
-** <tr><td>sqlite3changeset_apply_str<td>[sqlite3changeset_apply]
-** <tr><td>sqlite3changeset_concat_str<td>[sqlite3changeset_concat]
-** <tr><td>sqlite3changeset_invert_str<td>[sqlite3changeset_invert]
-** <tr><td>sqlite3changeset_start_str<td>[sqlite3changeset_start]
-** <tr><td>sqlite3session_changeset_str<td>[sqlite3session_changeset]
-** <tr><td>sqlite3session_patchset_str<td>[sqlite3session_patchset]
-** </table>
-**
-** Non-streaming functions that accept changesets (or patchsets) as input
-** require that the entire changeset be stored in a single buffer in memory.
-** Similarly, those that return a changeset or patchset do so by returning
-** a pointer to a single large buffer allocated using sqlite3_malloc().
-** Normally this is convenient. However, if an application running in a
-** low-memory environment is required to handle very large changesets, the
-** large contiguous memory allocations required can become onerous.
-**
-** In order to avoid this problem, instead of a single large buffer, input
-** is passed to a streaming API functions by way of a callback function that
-** the sessions module invokes to incrementally request input data as it is
-** required. In all cases, a pair of API function parameters such as
-**
-** <pre>
-** &nbsp; int nChangeset,
-** &nbsp; void *pChangeset,
-** </pre>
-**
-** Is replaced by:
-**
-** <pre>
-** &nbsp; int (*xInput)(void *pIn, void *pData, int *pnData),
-** &nbsp; void *pIn,
-** </pre>
-**
-** Each time the xInput callback is invoked by the sessions module, the first
-** argument passed is a copy of the supplied pIn context pointer. The second
-** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no
-** error occurs the xInput method should copy up to (*pnData) bytes of data
-** into the buffer and set (*pnData) to the actual number of bytes copied
-** before returning SQLITE_OK. If the input is completely exhausted, (*pnData)
-** should be set to zero to indicate this. Or, if an error occurs, an SQLite
-** error code should be returned. In all cases, if an xInput callback returns
-** an error, all processing is abandoned and the streaming API function
-** returns a copy of the error code to the caller.
-**
-** In the case of sqlite3changeset_start_strm(), the xInput callback may be
-** invoked by the sessions module at any point during the lifetime of the
-** iterator. If such an xInput callback returns an error, the iterator enters
-** an error state, whereby all subsequent calls to iterator functions
-** immediately fail with the same error code as returned by xInput.
-**
-** Similarly, streaming API functions that return changesets (or patchsets)
-** return them in chunks by way of a callback function instead of via a
-** pointer to a single large buffer. In this case, a pair of parameters such
-** as:
-**
-** <pre>
-** &nbsp; int *pnChangeset,
-** &nbsp; void **ppChangeset,
-** </pre>
-**
-** Is replaced by:
-**
-** <pre>
-** &nbsp; int (*xOutput)(void *pOut, const void *pData, int nData),
-** &nbsp; void *pOut
-** </pre>
-**
-** The xOutput callback is invoked zero or more times to return data to
-** the application. The first parameter passed to each call is a copy of the
-** pOut pointer supplied by the application. The second parameter, pData,
-** points to a buffer nData bytes in size containing the chunk of output
-** data being returned. If the xOutput callback successfully processes the
-** supplied data, it should return SQLITE_OK to indicate success. Otherwise,
-** it should return some other SQLite error code. In this case processing
-** is immediately abandoned and the streaming API function returns a copy
-** of the xOutput error code to the application.
-**
-** The sessions module never invokes an xOutput callback with the third
-** parameter set to a value less than or equal to zero. Other than this,
-** no guarantees are made as to the size of the chunks of data returned.
-*/
-int sqlite3changeset_apply_strm(
- sqlite3 *db, /* Apply change to "main" db of this handle */
- int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
- void *pIn, /* First arg for xInput */
- int(*xFilter)(
- void *pCtx, /* Copy of sixth arg to _apply() */
- const char *zTab /* Table name */
- ),
- int(*xConflict)(
- void *pCtx, /* Copy of sixth arg to _apply() */
- int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
- sqlite3_changeset_iter *p /* Handle describing change and conflict */
- ),
- void *pCtx /* First argument passed to xConflict */
-);
-int sqlite3changeset_concat_strm(
- int (*xInputA)(void *pIn, void *pData, int *pnData),
- void *pInA,
- int (*xInputB)(void *pIn, void *pData, int *pnData),
- void *pInB,
- int (*xOutput)(void *pOut, const void *pData, int nData),
- void *pOut
-);
-int sqlite3changeset_invert_strm(
- int (*xInput)(void *pIn, void *pData, int *pnData),
- void *pIn,
- int (*xOutput)(void *pOut, const void *pData, int nData),
- void *pOut
-);
-int sqlite3changeset_start_strm(
- sqlite3_changeset_iter **pp,
- int (*xInput)(void *pIn, void *pData, int *pnData),
- void *pIn
-);
-int sqlite3session_changeset_strm(
- sqlite3_session *pSession,
- int (*xOutput)(void *pOut, const void *pData, int nData),
- void *pOut
-);
-int sqlite3session_patchset_strm(
- sqlite3_session *pSession,
- int (*xOutput)(void *pOut, const void *pData, int nData),
- void *pOut
-);
-int sqlite3changegroup_add_strm(sqlite3_changegroup*,
- int (*xInput)(void *pIn, void *pData, int *pnData),
- void *pIn
-);
-int sqlite3changegroup_output_strm(sqlite3_changegroup*,
- int (*xOutput)(void *pOut, const void *pData, int nData),
- void *pOut
-);
-
-
-/*
-** Make sure we can call this stuff from C++.
-*/
-#if 0
-}
-#endif
-
-#endif /* !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) */
-
-/******** End of sqlite3session.h *********/
-/******** Begin file fts5.h *********/
-/*
-** 2014 May 31
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** Interfaces to extend FTS5. Using the interfaces defined in this file,
-** FTS5 may be extended with:
-**
-** * custom tokenizers, and
-** * custom auxiliary functions.
-*/
-
-
-#ifndef _FTS5_H
-#define _FTS5_H
-
-
-#if 0
-extern "C" {
-#endif
-
-/*************************************************************************
-** CUSTOM AUXILIARY FUNCTIONS
-**
-** Virtual table implementations may overload SQL functions by implementing
-** the sqlite3_module.xFindFunction() method.
-*/
-
-typedef struct Fts5ExtensionApi Fts5ExtensionApi;
-typedef struct Fts5Context Fts5Context;
-typedef struct Fts5PhraseIter Fts5PhraseIter;
-
-typedef void (*fts5_extension_function)(
- const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
- Fts5Context *pFts, /* First arg to pass to pApi functions */
- sqlite3_context *pCtx, /* Context for returning result/error */
- int nVal, /* Number of values in apVal[] array */
- sqlite3_value **apVal /* Array of trailing arguments */
-);
-
-struct Fts5PhraseIter {
- const unsigned char *a;
- const unsigned char *b;
-};
-
-/*
-** EXTENSION API FUNCTIONS
-**
-** xUserData(pFts):
-** Return a copy of the context pointer the extension function was
-** registered with.
-**
-** xColumnTotalSize(pFts, iCol, pnToken):
-** If parameter iCol is less than zero, set output variable *pnToken
-** to the total number of tokens in the FTS5 table. Or, if iCol is
-** non-negative but less than the number of columns in the table, return
-** the total number of tokens in column iCol, considering all rows in
-** the FTS5 table.
-**
-** If parameter iCol is greater than or equal to the number of columns
-** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
-** an OOM condition or IO error), an appropriate SQLite error code is
-** returned.
-**
-** xColumnCount(pFts):
-** Return the number of columns in the table.
-**
-** xColumnSize(pFts, iCol, pnToken):
-** If parameter iCol is less than zero, set output variable *pnToken
-** to the total number of tokens in the current row. Or, if iCol is
-** non-negative but less than the number of columns in the table, set
-** *pnToken to the number of tokens in column iCol of the current row.
-**
-** If parameter iCol is greater than or equal to the number of columns
-** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
-** an OOM condition or IO error), an appropriate SQLite error code is
-** returned.
-**
-** This function may be quite inefficient if used with an FTS5 table
-** created with the "columnsize=0" option.
-**
-** xColumnText:
-** This function attempts to retrieve the text of column iCol of the
-** current document. If successful, (*pz) is set to point to a buffer
-** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
-** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
-** if an error occurs, an SQLite error code is returned and the final values
-** of (*pz) and (*pn) are undefined.
-**
-** xPhraseCount:
-** Returns the number of phrases in the current query expression.
-**
-** xPhraseSize:
-** Returns the number of tokens in phrase iPhrase of the query. Phrases
-** are numbered starting from zero.
-**
-** xInstCount:
-** Set *pnInst to the total number of occurrences of all phrases within
-** the query within the current row. Return SQLITE_OK if successful, or
-** an error code (i.e. SQLITE_NOMEM) if an error occurs.
-**
-** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" or "detail=column" option. If the FTS5 table is created
-** with either "detail=none" or "detail=column" and "content=" option
-** (i.e. if it is a contentless table), then this API always returns 0.
-**
-** xInst:
-** Query for the details of phrase match iIdx within the current row.
-** Phrase matches are numbered starting from zero, so the iIdx argument
-** should be greater than or equal to zero and smaller than the value
-** output by xInstCount().
-**
-** Usually, output parameter *piPhrase is set to the phrase number, *piCol
-** to the column in which it occurs and *piOff the token offset of the
-** first token of the phrase. The exception is if the table was created
-** with the offsets=0 option specified. In this case *piOff is always
-** set to -1.
-**
-** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
-** if an error occurs.
-**
-** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" or "detail=column" option.
-**
-** xRowid:
-** Returns the rowid of the current row.
-**
-** xTokenize:
-** Tokenize text using the tokenizer belonging to the FTS5 table.
-**
-** xQueryPhrase(pFts5, iPhrase, pUserData, xCallback):
-** This API function is used to query the FTS table for phrase iPhrase
-** of the current query. Specifically, a query equivalent to:
-**
-** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid
-**
-** with $p set to a phrase equivalent to the phrase iPhrase of the
-** current query is executed. Any column filter that applies to
-** phrase iPhrase of the current query is included in $p. For each
-** row visited, the callback function passed as the fourth argument
-** is invoked. The context and API objects passed to the callback
-** function may be used to access the properties of each matched row.
-** Invoking Api.xUserData() returns a copy of the pointer passed as
-** the third argument to pUserData.
-**
-** If the callback function returns any value other than SQLITE_OK, the
-** query is abandoned and the xQueryPhrase function returns immediately.
-** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
-** Otherwise, the error code is propagated upwards.
-**
-** If the query runs to completion without incident, SQLITE_OK is returned.
-** Or, if some error occurs before the query completes or is aborted by
-** the callback, an SQLite error code is returned.
-**
-**
-** xSetAuxdata(pFts5, pAux, xDelete)
-**
-** Save the pointer passed as the second argument as the extension functions
-** "auxiliary data". The pointer may then be retrieved by the current or any
-** future invocation of the same fts5 extension function made as part of
-** of the same MATCH query using the xGetAuxdata() API.
-**
-** Each extension function is allocated a single auxiliary data slot for
-** each FTS query (MATCH expression). If the extension function is invoked
-** more than once for a single FTS query, then all invocations share a
-** single auxiliary data context.
-**
-** If there is already an auxiliary data pointer when this function is
-** invoked, then it is replaced by the new pointer. If an xDelete callback
-** was specified along with the original pointer, it is invoked at this
-** point.
-**
-** The xDelete callback, if one is specified, is also invoked on the
-** auxiliary data pointer after the FTS5 query has finished.
-**
-** If an error (e.g. an OOM condition) occurs within this function, an
-** the auxiliary data is set to NULL and an error code returned. If the
-** xDelete parameter was not NULL, it is invoked on the auxiliary data
-** pointer before returning.
-**
-**
-** xGetAuxdata(pFts5, bClear)
-**
-** Returns the current auxiliary data pointer for the fts5 extension
-** function. See the xSetAuxdata() method for details.
-**
-** If the bClear argument is non-zero, then the auxiliary data is cleared
-** (set to NULL) before this function returns. In this case the xDelete,
-** if any, is not invoked.
-**
-**
-** xRowCount(pFts5, pnRow)
-**
-** This function is used to retrieve the total number of rows in the table.
-** In other words, the same value that would be returned by:
-**
-** SELECT count(*) FROM ftstable;
-**
-** xPhraseFirst()
-** This function is used, along with type Fts5PhraseIter and the xPhraseNext
-** method, to iterate through all instances of a single query phrase within
-** the current row. This is the same information as is accessible via the
-** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient
-** to use, this API may be faster under some circumstances. To iterate
-** through instances of phrase iPhrase, use the following code:
-**
-** Fts5PhraseIter iter;
-** int iCol, iOff;
-** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
-** iCol>=0;
-** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
-** ){
-** // An instance of phrase iPhrase at offset iOff of column iCol
-** }
-**
-** The Fts5PhraseIter structure is defined above. Applications should not
-** modify this structure directly - it should only be used as shown above
-** with the xPhraseFirst() and xPhraseNext() API methods (and by
-** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
-**
-** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" or "detail=column" option. If the FTS5 table is created
-** with either "detail=none" or "detail=column" and "content=" option
-** (i.e. if it is a contentless table), then this API always iterates
-** through an empty set (all calls to xPhraseFirst() set iCol to -1).
-**
-** xPhraseNext()
-** See xPhraseFirst above.
-**
-** xPhraseFirstColumn()
-** This function and xPhraseNextColumn() are similar to the xPhraseFirst()
-** and xPhraseNext() APIs described above. The difference is that instead
-** of iterating through all instances of a phrase in the current row, these
-** APIs are used to iterate through the set of columns in the current row
-** that contain one or more instances of a specified phrase. For example:
-**
-** Fts5PhraseIter iter;
-** int iCol;
-** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol);
-** iCol>=0;
-** pApi->xPhraseNextColumn(pFts, &iter, &iCol)
-** ){
-** // Column iCol contains at least one instance of phrase iPhrase
-** }
-**
-** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" option. If the FTS5 table is created with either
-** "detail=none" "content=" option (i.e. if it is a contentless table),
-** then this API always iterates through an empty set (all calls to
-** xPhraseFirstColumn() set iCol to -1).
-**
-** The information accessed using this API and its companion
-** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
-** (or xInst/xInstCount). The chief advantage of this API is that it is
-** significantly more efficient than those alternatives when used with
-** "detail=column" tables.
-**
-** xPhraseNextColumn()
-** See xPhraseFirstColumn above.
-*/
-struct Fts5ExtensionApi {
- int iVersion; /* Currently always set to 3 */
-
- void *(*xUserData)(Fts5Context*);
-
- int (*xColumnCount)(Fts5Context*);
- int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
- int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken);
-
- int (*xTokenize)(Fts5Context*,
- const char *pText, int nText, /* Text to tokenize */
- void *pCtx, /* Context passed to xToken() */
- int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
- );
-
- int (*xPhraseCount)(Fts5Context*);
- int (*xPhraseSize)(Fts5Context*, int iPhrase);
-
- int (*xInstCount)(Fts5Context*, int *pnInst);
- int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff);
-
- sqlite3_int64 (*xRowid)(Fts5Context*);
- int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn);
- int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken);
-
- int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData,
- int(*)(const Fts5ExtensionApi*,Fts5Context*,void*)
- );
- int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
- void *(*xGetAuxdata)(Fts5Context*, int bClear);
-
- int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
- void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
-
- int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
- void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
-};
-
-/*
-** CUSTOM AUXILIARY FUNCTIONS
-*************************************************************************/
-
-/*************************************************************************
-** CUSTOM TOKENIZERS
-**
-** Applications may also register custom tokenizer types. A tokenizer
-** is registered by providing fts5 with a populated instance of the
-** following structure. All structure methods must be defined, setting
-** any member of the fts5_tokenizer struct to NULL leads to undefined
-** behaviour. The structure methods are expected to function as follows:
-**
-** xCreate:
-** This function is used to allocate and inititalize a tokenizer instance.
-** A tokenizer instance is required to actually tokenize text.
-**
-** The first argument passed to this function is a copy of the (void*)
-** pointer provided by the application when the fts5_tokenizer object
-** was registered with FTS5 (the third argument to xCreateTokenizer()).
-** The second and third arguments are an array of nul-terminated strings
-** containing the tokenizer arguments, if any, specified following the
-** tokenizer name as part of the CREATE VIRTUAL TABLE statement used
-** to create the FTS5 table.
-**
-** The final argument is an output variable. If successful, (*ppOut)
-** should be set to point to the new tokenizer handle and SQLITE_OK
-** returned. If an error occurs, some value other than SQLITE_OK should
-** be returned. In this case, fts5 assumes that the final value of *ppOut
-** is undefined.
-**
-** xDelete:
-** This function is invoked to delete a tokenizer handle previously
-** allocated using xCreate(). Fts5 guarantees that this function will
-** be invoked exactly once for each successful call to xCreate().
-**
-** xTokenize:
-** This function is expected to tokenize the nText byte string indicated
-** by argument pText. pText may or may not be nul-terminated. The first
-** argument passed to this function is a pointer to an Fts5Tokenizer object
-** returned by an earlier call to xCreate().
-**
-** The second argument indicates the reason that FTS5 is requesting
-** tokenization of the supplied text. This is always one of the following
-** four values:
-**
-** <ul><li> <b>FTS5_TOKENIZE_DOCUMENT</b> - A document is being inserted into
-** or removed from the FTS table. The tokenizer is being invoked to
-** determine the set of tokens to add to (or delete from) the
-** FTS index.
-**
-** <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed
-** against the FTS index. The tokenizer is being called to tokenize
-** a bareword or quoted string specified as part of the query.
-**
-** <li> <b>(FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX)</b> - Same as
-** FTS5_TOKENIZE_QUERY, except that the bareword or quoted string is
-** followed by a "*" character, indicating that the last token
-** returned by the tokenizer will be treated as a token prefix.
-**
-** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
-** satisfy an fts5_api.xTokenize() request made by an auxiliary
-** function. Or an fts5_api.xColumnSize() request made by the same
-** on a columnsize=0 database.
-** </ul>
-**
-** For each token in the input string, the supplied callback xToken() must
-** be invoked. The first argument to it should be a copy of the pointer
-** passed as the second argument to xTokenize(). The third and fourth
-** arguments are a pointer to a buffer containing the token text, and the
-** size of the token in bytes. The 4th and 5th arguments are the byte offsets
-** of the first byte of and first byte immediately following the text from
-** which the token is derived within the input.
-**
-** The second argument passed to the xToken() callback ("tflags") should
-** normally be set to 0. The exception is if the tokenizer supports
-** synonyms. In this case see the discussion below for details.
-**
-** FTS5 assumes the xToken() callback is invoked for each token in the
-** order that they occur within the input text.
-**
-** If an xToken() callback returns any value other than SQLITE_OK, then
-** the tokenization should be abandoned and the xTokenize() method should
-** immediately return a copy of the xToken() return value. Or, if the
-** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally,
-** if an error occurs with the xTokenize() implementation itself, it
-** may abandon the tokenization and return any error code other than
-** SQLITE_OK or SQLITE_DONE.
-**
-** SYNONYM SUPPORT
-**
-** Custom tokenizers may also support synonyms. Consider a case in which a
-** user wishes to query for a phrase such as "first place". Using the
-** built-in tokenizers, the FTS5 query 'first + place' will match instances
-** of "first place" within the document set, but not alternative forms
-** such as "1st place". In some applications, it would be better to match
-** all instances of "first place" or "1st place" regardless of which form
-** the user specified in the MATCH query text.
-**
-** There are several ways to approach this in FTS5:
-**
-** <ol><li> By mapping all synonyms to a single token. In this case, the
-** In the above example, this means that the tokenizer returns the
-** same token for inputs "first" and "1st". Say that token is in
-** fact "first", so that when the user inserts the document "I won
-** 1st place" entries are added to the index for tokens "i", "won",
-** "first" and "place". If the user then queries for '1st + place',
-** the tokenizer substitutes "first" for "1st" and the query works
-** as expected.
-**
-** <li> By adding multiple synonyms for a single term to the FTS index.
-** In this case, when tokenizing query text, the tokenizer may
-** provide multiple synonyms for a single term within the document.
-** FTS5 then queries the index for each synonym individually. For
-** example, faced with the query:
-**
-** <codeblock>
-** ... MATCH 'first place'</codeblock>
-**
-** the tokenizer offers both "1st" and "first" as synonyms for the
-** first token in the MATCH query and FTS5 effectively runs a query
-** similar to:
-**
-** <codeblock>
-** ... MATCH '(first OR 1st) place'</codeblock>
-**
-** except that, for the purposes of auxiliary functions, the query
-** still appears to contain just two phrases - "(first OR 1st)"
-** being treated as a single phrase.
-**
-** <li> By adding multiple synonyms for a single term to the FTS index.
-** Using this method, when tokenizing document text, the tokenizer
-** provides multiple synonyms for each token. So that when a
-** document such as "I won first place" is tokenized, entries are
-** added to the FTS index for "i", "won", "first", "1st" and
-** "place".
-**
-** This way, even if the tokenizer does not provide synonyms
-** when tokenizing query text (it should not - to do would be
-** inefficient), it doesn't matter if the user queries for
-** 'first + place' or '1st + place', as there are entires in the
-** FTS index corresponding to both forms of the first token.
-** </ol>
-**
-** Whether it is parsing document or query text, any call to xToken that
-** specifies a <i>tflags</i> argument with the FTS5_TOKEN_COLOCATED bit
-** is considered to supply a synonym for the previous token. For example,
-** when parsing the document "I won first place", a tokenizer that supports
-** synonyms would call xToken() 5 times, as follows:
-**
-** <codeblock>
-** xToken(pCtx, 0, "i", 1, 0, 1);
-** xToken(pCtx, 0, "won", 3, 2, 5);
-** xToken(pCtx, 0, "first", 5, 6, 11);
-** xToken(pCtx, FTS5_TOKEN_COLOCATED, "1st", 3, 6, 11);
-** xToken(pCtx, 0, "place", 5, 12, 17);
-**</codeblock>
-**
-** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time
-** xToken() is called. Multiple synonyms may be specified for a single token
-** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence.
-** There is no limit to the number of synonyms that may be provided for a
-** single token.
-**
-** In many cases, method (1) above is the best approach. It does not add
-** extra data to the FTS index or require FTS5 to query for multiple terms,
-** so it is efficient in terms of disk space and query speed. However, it
-** does not support prefix queries very well. If, as suggested above, the
-** token "first" is subsituted for "1st" by the tokenizer, then the query:
-**
-** <codeblock>
-** ... MATCH '1s*'</codeblock>
-**
-** will not match documents that contain the token "1st" (as the tokenizer
-** will probably not map "1s" to any prefix of "first").
-**
-** For full prefix support, method (3) may be preferred. In this case,
-** because the index contains entries for both "first" and "1st", prefix
-** queries such as 'fi*' or '1s*' will match correctly. However, because
-** extra entries are added to the FTS index, this method uses more space
-** within the database.
-**
-** Method (2) offers a midpoint between (1) and (3). Using this method,
-** a query such as '1s*' will match documents that contain the literal
-** token "1st", but not "first" (assuming the tokenizer is not able to
-** provide synonyms for prefixes). However, a non-prefix query like '1st'
-** will match against "1st" and "first". This method does not require
-** extra disk space, as no extra entries are added to the FTS index.
-** On the other hand, it may require more CPU cycles to run MATCH queries,
-** as separate queries of the FTS index are required for each synonym.
-**
-** When using methods (2) or (3), it is important that the tokenizer only
-** provide synonyms when tokenizing document text (method (2)) or query
-** text (method (3)), not both. Doing so will not cause any errors, but is
-** inefficient.
-*/
-typedef struct Fts5Tokenizer Fts5Tokenizer;
-typedef struct fts5_tokenizer fts5_tokenizer;
-struct fts5_tokenizer {
- int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
- void (*xDelete)(Fts5Tokenizer*);
- int (*xTokenize)(Fts5Tokenizer*,
- void *pCtx,
- int flags, /* Mask of FTS5_TOKENIZE_* flags */
- const char *pText, int nText,
- int (*xToken)(
- void *pCtx, /* Copy of 2nd argument to xTokenize() */
- int tflags, /* Mask of FTS5_TOKEN_* flags */
- const char *pToken, /* Pointer to buffer containing token */
- int nToken, /* Size of token in bytes */
- int iStart, /* Byte offset of token within input text */
- int iEnd /* Byte offset of end of token within input text */
- )
- );
-};
-
-/* Flags that may be passed as the third argument to xTokenize() */
-#define FTS5_TOKENIZE_QUERY 0x0001
-#define FTS5_TOKENIZE_PREFIX 0x0002
-#define FTS5_TOKENIZE_DOCUMENT 0x0004
-#define FTS5_TOKENIZE_AUX 0x0008
-
-/* Flags that may be passed by the tokenizer implementation back to FTS5
-** as the third argument to the supplied xToken callback. */
-#define FTS5_TOKEN_COLOCATED 0x0001 /* Same position as prev. token */
-
-/*
-** END OF CUSTOM TOKENIZERS
-*************************************************************************/
-
-/*************************************************************************
-** FTS5 EXTENSION REGISTRATION API
-*/
-typedef struct fts5_api fts5_api;
-struct fts5_api {
- int iVersion; /* Currently always set to 2 */
-
- /* Create a new tokenizer */
- int (*xCreateTokenizer)(
- fts5_api *pApi,
- const char *zName,
- void *pContext,
- fts5_tokenizer *pTokenizer,
- void (*xDestroy)(void*)
- );
-
- /* Find an existing tokenizer */
- int (*xFindTokenizer)(
- fts5_api *pApi,
- const char *zName,
- void **ppContext,
- fts5_tokenizer *pTokenizer
- );
-
- /* Create a new auxiliary function */
- int (*xCreateFunction)(
- fts5_api *pApi,
- const char *zName,
- void *pContext,
- fts5_extension_function xFunction,
- void (*xDestroy)(void*)
- );
-};
-
-/*
-** END OF REGISTRATION API
-*************************************************************************/
-
-#if 0
-} /* end of the 'extern "C"' block */
-#endif
-
-#endif /* _FTS5_H */
-
-
-/******** End of fts5.h *********/
/************** End of sqlite3.h *********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
@@ -10555,13 +8153,13 @@ struct fts5_api {
** The suggested maximum number of in-memory pages to use for
** the main database table and for temporary tables.
**
-** IMPLEMENTATION-OF: R-30185-15359 The default suggested cache size is -2000,
-** which means the cache size is limited to 2048000 bytes of memory.
+** IMPLEMENTATION-OF: R-31093-59126 The default suggested cache size
+** is 2000 pages.
** IMPLEMENTATION-OF: R-48205-43578 The default suggested cache size can be
** altered using the SQLITE_DEFAULT_CACHE_SIZE compile-time options.
*/
#ifndef SQLITE_DEFAULT_CACHE_SIZE
-# define SQLITE_DEFAULT_CACHE_SIZE -2000
+# define SQLITE_DEFAULT_CACHE_SIZE 2000
#endif
/*
@@ -10574,9 +8172,8 @@ struct fts5_api {
/*
** The maximum number of attached databases. This must be between 0
-** and 125. The upper bound of 125 is because the attached databases are
-** counted using a signed 8-bit integer which has a maximum value of 127
-** and we have to allow 2 extra counts for the "main" and "temp" databases.
+** and 62. The upper bound on 62 is because a 64-bit integer bitmap
+** is used internally to track attached databases.
*/
#ifndef SQLITE_MAX_ATTACHED
# define SQLITE_MAX_ATTACHED 10
@@ -10611,7 +8208,7 @@ struct fts5_api {
** The default size of a database page.
*/
#ifndef SQLITE_DEFAULT_PAGE_SIZE
-# define SQLITE_DEFAULT_PAGE_SIZE 4096
+# define SQLITE_DEFAULT_PAGE_SIZE 1024
#endif
#if SQLITE_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
# undef SQLITE_DEFAULT_PAGE_SIZE
@@ -10692,7 +8289,7 @@ struct fts5_api {
** to the next, so we have developed the following set of #if statements
** to generate appropriate macros for a wide range of compilers.
**
-** The correct "ANSI" way to do this is to use the intptr_t type.
+** The correct "ANSI" way to do this is to use the intptr_t type.
** Unfortunately, that typedef is not available on all compilers, or
** if it is available, it requires an #include of specific headers
** that vary from one machine to the next.
@@ -10729,24 +8326,6 @@ struct fts5_api {
#endif
/*
-** Make sure that the compiler intrinsics we desire are enabled when
-** compiling with an appropriate version of MSVC unless prevented by
-** the SQLITE_DISABLE_INTRINSIC define.
-*/
-#if !defined(SQLITE_DISABLE_INTRINSIC)
-# if defined(_MSC_VER) && _MSC_VER>=1300
-# if !defined(_WIN32_WCE)
-# include <intrin.h>
-# pragma intrinsic(_byteswap_ushort)
-# pragma intrinsic(_byteswap_ulong)
-# pragma intrinsic(_ReadWriteBarrier)
-# else
-# include <cmnintrin.h>
-# endif
-# endif
-#endif
-
-/*
** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2.
** 0 means mutexes are permanently disable and the library is never
** threadsafe. 1 means the library is serialized which is the highest
@@ -10844,7 +8423,7 @@ struct fts5_api {
** is set. Thus NDEBUG becomes an opt-in rather than an opt-out
** feature.
*/
-#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
+#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
# define NDEBUG 1
#endif
#if defined(NDEBUG) && defined(SQLITE_DEBUG)
@@ -10859,7 +8438,7 @@ struct fts5_api {
#endif
/*
-** The testcase() macro is used to aid in coverage testing. When
+** The testcase() macro is used to aid in coverage testing. When
** doing coverage testing, the condition inside the argument to
** testcase() must be evaluated both true and false in order to
** get full branch coverage. The testcase() macro is inserted
@@ -10905,7 +8484,7 @@ SQLITE_PRIVATE void sqlite3Coverage(int);
#endif
/*
-** The ALWAYS and NEVER macros surround boolean expressions which
+** The ALWAYS and NEVER macros surround boolean expressions which
** are intended to always be true or false, respectively. Such
** expressions could be omitted from the code completely. But they
** are included in a few cases in order to enhance the resilience
@@ -10919,7 +8498,7 @@ SQLITE_PRIVATE void sqlite3Coverage(int);
** be true and false so that the unreachable code they specify will
** not be counted as untested code.
*/
-#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
+#if defined(SQLITE_COVERAGE_TEST)
# define ALWAYS(X) (1)
# define NEVER(X) (0)
#elif !defined(NDEBUG)
@@ -10931,21 +8510,6 @@ SQLITE_PRIVATE void sqlite3Coverage(int);
#endif
/*
-** Some malloc failures are only possible if SQLITE_TEST_REALLOC_STRESS is
-** defined. We need to defend against those failures when testing with
-** SQLITE_TEST_REALLOC_STRESS, but we don't want the unreachable branches
-** during a normal build. The following macro can be used to disable tests
-** that are always false except when SQLITE_TEST_REALLOC_STRESS is set.
-*/
-#if defined(SQLITE_TEST_REALLOC_STRESS)
-# define ONLY_IF_REALLOC_STRESS(X) (X)
-#elif !defined(NDEBUG)
-# define ONLY_IF_REALLOC_STRESS(X) ((X)?(assert(0),1):0)
-#else
-# define ONLY_IF_REALLOC_STRESS(X) (0)
-#endif
-
-/*
** Declarations used for tracing the operating system interfaces.
*/
#if defined(SQLITE_FORCE_OS_TRACE) || defined(SQLITE_TEST) || \
@@ -10972,13 +8536,6 @@ SQLITE_PRIVATE void sqlite3Coverage(int);
#endif
/*
-** SQLITE_ENABLE_EXPLAIN_COMMENTS is incompatible with SQLITE_OMIT_EXPLAIN
-*/
-#ifdef SQLITE_OMIT_EXPLAIN
-# undef SQLITE_ENABLE_EXPLAIN_COMMENTS
-#endif
-
-/*
** Return true (non-zero) if the input is an integer that is too large
** to fit in 32-bits. This macro is used inside of various testcase()
** macros to verify that we have tested SQLite for large-file support.
@@ -11124,76 +8681,76 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
#define TK_AS 24
#define TK_WITHOUT 25
#define TK_COMMA 26
-#define TK_OR 27
-#define TK_AND 28
-#define TK_IS 29
-#define TK_MATCH 30
-#define TK_LIKE_KW 31
-#define TK_BETWEEN 32
-#define TK_IN 33
-#define TK_ISNULL 34
-#define TK_NOTNULL 35
-#define TK_NE 36
-#define TK_EQ 37
-#define TK_GT 38
-#define TK_LE 39
-#define TK_LT 40
-#define TK_GE 41
-#define TK_ESCAPE 42
-#define TK_BITAND 43
-#define TK_BITOR 44
-#define TK_LSHIFT 45
-#define TK_RSHIFT 46
-#define TK_PLUS 47
-#define TK_MINUS 48
-#define TK_STAR 49
-#define TK_SLASH 50
-#define TK_REM 51
-#define TK_CONCAT 52
-#define TK_COLLATE 53
-#define TK_BITNOT 54
-#define TK_ID 55
-#define TK_INDEXED 56
-#define TK_ABORT 57
-#define TK_ACTION 58
-#define TK_AFTER 59
-#define TK_ANALYZE 60
-#define TK_ASC 61
-#define TK_ATTACH 62
-#define TK_BEFORE 63
-#define TK_BY 64
-#define TK_CASCADE 65
-#define TK_CAST 66
-#define TK_COLUMNKW 67
-#define TK_CONFLICT 68
-#define TK_DATABASE 69
-#define TK_DESC 70
-#define TK_DETACH 71
-#define TK_EACH 72
-#define TK_FAIL 73
-#define TK_FOR 74
-#define TK_IGNORE 75
-#define TK_INITIALLY 76
-#define TK_INSTEAD 77
-#define TK_NO 78
-#define TK_KEY 79
-#define TK_OF 80
-#define TK_OFFSET 81
-#define TK_PRAGMA 82
-#define TK_RAISE 83
-#define TK_RECURSIVE 84
-#define TK_REPLACE 85
-#define TK_RESTRICT 86
-#define TK_ROW 87
-#define TK_TRIGGER 88
-#define TK_VACUUM 89
-#define TK_VIEW 90
-#define TK_VIRTUAL 91
-#define TK_WITH 92
-#define TK_REINDEX 93
-#define TK_RENAME 94
-#define TK_CTIME_KW 95
-#define TK_ANY 96
+#define TK_ID 27
+#define TK_INDEXED 28
+#define TK_ABORT 29
+#define TK_ACTION 30
+#define TK_AFTER 31
+#define TK_ANALYZE 32
+#define TK_ASC 33
+#define TK_ATTACH 34
+#define TK_BEFORE 35
+#define TK_BY 36
+#define TK_CASCADE 37
+#define TK_CAST 38
+#define TK_COLUMNKW 39
+#define TK_CONFLICT 40
+#define TK_DATABASE 41
+#define TK_DESC 42
+#define TK_DETACH 43
+#define TK_EACH 44
+#define TK_FAIL 45
+#define TK_FOR 46
+#define TK_IGNORE 47
+#define TK_INITIALLY 48
+#define TK_INSTEAD 49
+#define TK_LIKE_KW 50
+#define TK_MATCH 51
+#define TK_NO 52
+#define TK_KEY 53
+#define TK_OF 54
+#define TK_OFFSET 55
+#define TK_PRAGMA 56
+#define TK_RAISE 57
+#define TK_RECURSIVE 58
+#define TK_REPLACE 59
+#define TK_RESTRICT 60
+#define TK_ROW 61
+#define TK_TRIGGER 62
+#define TK_VACUUM 63
+#define TK_VIEW 64
+#define TK_VIRTUAL 65
+#define TK_WITH 66
+#define TK_REINDEX 67
+#define TK_RENAME 68
+#define TK_CTIME_KW 69
+#define TK_ANY 70
+#define TK_OR 71
+#define TK_AND 72
+#define TK_IS 73
+#define TK_BETWEEN 74
+#define TK_IN 75
+#define TK_ISNULL 76
+#define TK_NOTNULL 77
+#define TK_NE 78
+#define TK_EQ 79
+#define TK_GT 80
+#define TK_LE 81
+#define TK_LT 82
+#define TK_GE 83
+#define TK_ESCAPE 84
+#define TK_BITAND 85
+#define TK_BITOR 86
+#define TK_LSHIFT 87
+#define TK_RSHIFT 88
+#define TK_PLUS 89
+#define TK_MINUS 90
+#define TK_STAR 91
+#define TK_SLASH 92
+#define TK_REM 93
+#define TK_CONCAT 94
+#define TK_COLLATE 95
+#define TK_BITNOT 96
#define TK_STRING 97
#define TK_JOIN_KW 98
#define TK_CONSTRAINT 99
@@ -11247,25 +8804,16 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
#define TK_TO_REAL 147
#define TK_ISNOT 148
#define TK_END_OF_FILE 149
-#define TK_UNCLOSED_STRING 150
-#define TK_FUNCTION 151
-#define TK_COLUMN 152
-#define TK_AGG_FUNCTION 153
-#define TK_AGG_COLUMN 154
-#define TK_UMINUS 155
-#define TK_UPLUS 156
-#define TK_REGISTER 157
-#define TK_ASTERISK 158
-#define TK_SPAN 159
-#define TK_SPACE 160
-#define TK_ILLEGAL 161
-
-/* The token codes above must all fit in 8 bits */
-#define TKFLG_MASK 0xff
-
-/* Flags that can be added to a token code when it is not
-** being stored in a u8: */
-#define TKFLG_DONTFOLD 0x100 /* Omit constant folding optimizations */
+#define TK_ILLEGAL 150
+#define TK_SPACE 151
+#define TK_UNCLOSED_STRING 152
+#define TK_FUNCTION 153
+#define TK_COLUMN 154
+#define TK_AGG_FUNCTION 155
+#define TK_AGG_COLUMN 156
+#define TK_UMINUS 157
+#define TK_UPLUS 158
+#define TK_REGISTER 159
/************** End of parse.h ***********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
@@ -11297,7 +8845,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
/*
** OMIT_TEMPDB is set to 1 if SQLITE_OMIT_TEMPDB is defined, or 0
-** afterward. Having this macro allows us to cause the C compiler
+** afterward. Having this macro allows us to cause the C compiler
** to omit code used by TEMP tables without messy #ifndef statements.
*/
#ifdef SQLITE_OMIT_TEMPDB
@@ -11336,7 +8884,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
/*
** If no value has been provided for SQLITE_MAX_WORKER_THREADS, or if
-** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it
+** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it
** to zero.
*/
#if SQLITE_TEMP_STORE==3 || SQLITE_THREADSAFE==0
@@ -11354,15 +8902,6 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
# define SQLITE_MAX_WORKER_THREADS SQLITE_DEFAULT_WORKER_THREADS
#endif
-/*
-** The default initial allocation for the pagecache when using separate
-** pagecaches for each database connection. A positive number is the
-** number of pages. A negative number N translations means that a buffer
-** of -1024*N bytes is allocated and used for as many pages as it will hold.
-*/
-#ifndef SQLITE_DEFAULT_PCACHE_INITSZ
-# define SQLITE_DEFAULT_PCACHE_INITSZ 100
-#endif
/*
** GCC does not define the offsetof() macro so we'll have to do it
@@ -11375,12 +8914,8 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
/*
** Macros to compute minimum and maximum of two numbers.
*/
-#ifndef MIN
-# define MIN(A,B) ((A)<(B)?(A):(B))
-#endif
-#ifndef MAX
-# define MAX(A,B) ((A)>(B)?(A):(B))
-#endif
+#define MIN(A,B) ((A)<(B)?(A):(B))
+#define MAX(A,B) ((A)>(B)?(A):(B))
/*
** Swap two objects of type TYPE.
@@ -11488,7 +9023,7 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */
** 4 -> 20 1000 -> 99 1048576 -> 200
** 10 -> 33 1024 -> 100 4294967296 -> 320
**
-** The LogEst can be negative to indicate fractional values.
+** The LogEst can be negative to indicate fractional values.
** Examples:
**
** 0.5 -> -10 0.1 -> -33 0.0625 -> -40
@@ -11509,27 +9044,6 @@ typedef INT16_TYPE LogEst;
# endif
#endif
-/* The uptr type is an unsigned integer large enough to hold a pointer
-*/
-#if defined(HAVE_STDINT_H)
- typedef uintptr_t uptr;
-#elif SQLITE_PTRSIZE==4
- typedef u32 uptr;
-#else
- typedef u64 uptr;
-#endif
-
-/*
-** The SQLITE_WITHIN(P,S,E) macro checks to see if pointer P points to
-** something between S (inclusive) and E (exclusive).
-**
-** In other words, S is a buffer and E is a pointer to the first byte after
-** the end of buffer S. This macro returns true if P points to something
-** contained within the buffer S.
-*/
-#define SQLITE_WITHIN(P,S,E) (((uptr)(P)>=(uptr)(S))&&((uptr)(P)<(uptr)(E)))
-
-
/*
** Macros to determine whether the machine is big or little endian,
** and whether or not that determination is run-time or compile-time.
@@ -11539,6 +9053,11 @@ typedef INT16_TYPE LogEst;
** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined
** at run-time.
*/
+#ifdef SQLITE_AMALGAMATION
+SQLITE_PRIVATE const int sqlite3one = 1;
+#else
+SQLITE_PRIVATE const int sqlite3one;
+#endif
#if (defined(i386) || defined(__i386__) || defined(_M_IX86) || \
defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
@@ -11556,11 +9075,6 @@ typedef INT16_TYPE LogEst;
# define SQLITE_UTF16NATIVE SQLITE_UTF16BE
#endif
#if !defined(SQLITE_BYTEORDER)
-# ifdef SQLITE_AMALGAMATION
- const int sqlite3one = 1;
-# else
- extern const int sqlite3one;
-# endif
# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */
# define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0)
# define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1)
@@ -11575,7 +9089,7 @@ typedef INT16_TYPE LogEst;
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
-/*
+/*
** Round up a number to the next larger multiple of 8. This is used
** to force 8-byte alignment on 64-bit architectures.
*/
@@ -11614,14 +9128,16 @@ typedef INT16_TYPE LogEst;
*/
#ifdef __APPLE__
# include <TargetConditionals.h>
+# if TARGET_OS_IPHONE
+# undef SQLITE_MAX_MMAP_SIZE
+# define SQLITE_MAX_MMAP_SIZE 0
+# endif
#endif
#ifndef SQLITE_MAX_MMAP_SIZE
# if defined(__linux__) \
|| defined(_WIN32) \
|| (defined(__APPLE__) && defined(__MACH__)) \
- || defined(__sun) \
- || defined(__FreeBSD__) \
- || defined(__DragonFly__)
+ || defined(__sun)
# define SQLITE_MAX_MMAP_SIZE 0x7fff0000 /* 2147418112 */
# else
# define SQLITE_MAX_MMAP_SIZE 0
@@ -11669,7 +9185,7 @@ typedef INT16_TYPE LogEst;
/*
** An instance of the following structure is used to store the busy-handler
-** callback for a given sqlite handle.
+** callback for a given sqlite handle.
**
** The sqlite.busyHandler member of the sqlite struct contains the busy
** callback for the database handle. Each pager opened via the sqlite
@@ -11714,9 +9230,9 @@ struct BusyHandler {
/*
** The following value as a destructor means to use sqlite3DbFree().
-** The sqlite3DbFree() routine requires two parameters instead of the
-** one parameter that destructors normally want. So we have to introduce
-** this magic value that the code knows to handle differently. Any
+** The sqlite3DbFree() routine requires two parameters instead of the
+** one parameter that destructors normally want. So we have to introduce
+** this magic value that the code knows to handle differently. Any
** pointer will work here as long as it is distinct from SQLITE_STATIC
** and SQLITE_TRANSIENT.
*/
@@ -11743,16 +9259,16 @@ struct BusyHandler {
SQLITE_API int SQLITE_STDCALL sqlite3_wsd_init(int N, int J);
SQLITE_API void *SQLITE_STDCALL sqlite3_wsd_find(void *K, int L);
#else
- #define SQLITE_WSD
+ #define SQLITE_WSD
#define GLOBAL(t,v) v
#define sqlite3GlobalConfig sqlite3Config
#endif
/*
** The following macros are used to suppress compiler warnings and to
-** make it clear to human readers when a function parameter is deliberately
+** make it clear to human readers when a function parameter is deliberately
** left unused within the body of a function. This usually happens when
-** a function is called via a function pointer. For example the
+** a function is called via a function pointer. For example the
** implementation of an SQL aggregate step callback may not use the
** parameter indicating the number of arguments passed to the aggregate,
** if it knows that this is enforced elsewhere.
@@ -11795,7 +9311,6 @@ typedef struct LookasideSlot LookasideSlot;
typedef struct Module Module;
typedef struct NameContext NameContext;
typedef struct Parse Parse;
-typedef struct PreUpdate PreUpdate;
typedef struct PrintfArguments PrintfArguments;
typedef struct RowSet RowSet;
typedef struct Savepoint Savepoint;
@@ -11819,7 +9334,7 @@ typedef struct WhereInfo WhereInfo;
typedef struct With With;
/*
-** Defer sourcing vdbe.h and btree.h until after the "u8" and
+** Defer sourcing vdbe.h and btree.h until after the "u8" and
** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque
** pointer types (i.e. FuncDef) defined above.
*/
@@ -11890,11 +9405,11 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
SQLITE_PRIVATE int sqlite3BtreeClose(Btree*);
SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int);
-SQLITE_PRIVATE int sqlite3BtreeSetSpillSize(Btree*,int);
#if SQLITE_MAX_MMAP_SIZE>0
SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
#endif
SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
+SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree*);
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int);
@@ -11977,37 +9492,8 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
#define BTREE_DATA_VERSION 15 /* A virtual meta-value */
/*
-** Kinds of hints that can be passed into the sqlite3BtreeCursorHint()
-** interface.
-**
-** BTREE_HINT_RANGE (arguments: Expr*, Mem*)
-**
-** The first argument is an Expr* (which is guaranteed to be constant for
-** the lifetime of the cursor) that defines constraints on which rows
-** might be fetched with this cursor. The Expr* tree may contain
-** TK_REGISTER nodes that refer to values stored in the array of registers
-** passed as the second parameter. In other words, if Expr.op==TK_REGISTER
-** then the value of the node is the value in Mem[pExpr.iTable]. Any
-** TK_COLUMN node in the expression tree refers to the Expr.iColumn-th
-** column of the b-tree of the cursor. The Expr tree will not contain
-** any function calls nor subqueries nor references to b-trees other than
-** the cursor being hinted.
-**
-** The design of the _RANGE hint is aid b-tree implementations that try
-** to prefetch content from remote machines - to provide those
-** implementations with limits on what needs to be prefetched and thereby
-** reduce network bandwidth.
-**
-** Note that BTREE_HINT_FLAGS with BTREE_BULKLOAD is the only hint used by
-** standard SQLite. The other hints are provided for extentions that use
-** the SQLite parser and code generator but substitute their own storage
-** engine.
-*/
-#define BTREE_HINT_RANGE 0 /* Range constraints on queries */
-
-/*
-** Values that may be OR'd together to form the argument to the
-** BTREE_HINT_FLAGS hint for sqlite3BtreeCursorHint():
+** Values that may be OR'd together to form the second argument of an
+** sqlite3BtreeCursorHints() call.
**
** The BTREE_BULKLOAD flag is set on index cursors when the index is going
** to be filled with content that is already in sorted order.
@@ -12021,32 +9507,6 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
#define BTREE_BULKLOAD 0x00000001 /* Used to full index in sorted order */
#define BTREE_SEEK_EQ 0x00000002 /* EQ seeks only - no range seeks */
-/*
-** Flags passed as the third argument to sqlite3BtreeCursor().
-**
-** For read-only cursors the wrFlag argument is always zero. For read-write
-** cursors it may be set to either (BTREE_WRCSR|BTREE_FORDELETE) or just
-** (BTREE_WRCSR). If the BTREE_FORDELETE bit is set, then the cursor will
-** only be used by SQLite for the following:
-**
-** * to seek to and then delete specific entries, and/or
-**
-** * to read values that will be used to create keys that other
-** BTREE_FORDELETE cursors will seek to and delete.
-**
-** The BTREE_FORDELETE flag is an optimization hint. It is not used by
-** by this, the native b-tree engine of SQLite, but it is available to
-** alternative storage engines that might be substituted in place of this
-** b-tree system. For alternative storage engines in which a delete of
-** the main table row automatically deletes corresponding index rows,
-** the FORDELETE flag hint allows those alternative storage engines to
-** skip a lot of work. Namely: FORDELETE cursors may treat all SEEK
-** and DELETE operations as no-ops, and any READ operation against a
-** FORDELETE cursor may return a null row: 0x01 0x00.
-*/
-#define BTREE_WRCSR 0x00000004 /* read-write cursor */
-#define BTREE_FORDELETE 0x00000008 /* Cursor is for seek/delete only */
-
SQLITE_PRIVATE int sqlite3BtreeCursor(
Btree*, /* BTree containing table to open */
int iTable, /* Index of root page */
@@ -12056,10 +9516,6 @@ SQLITE_PRIVATE int sqlite3BtreeCursor(
);
SQLITE_PRIVATE int sqlite3BtreeCursorSize(void);
SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor*);
-SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned);
-#ifdef SQLITE_ENABLE_CURSOR_HINTS
-SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor*, int, ...);
-#endif
SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor*);
SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
@@ -12071,12 +9527,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
);
SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor*);
SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor*, int*);
-SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, u8 flags);
-
-/* Allowed flags for the 2nd argument to sqlite3BtreeDelete() */
-#define BTREE_SAVEPOSITION 0x02 /* Leave cursor pointing at NEXT or PREV */
-#define BTREE_AUXDELETE 0x04 /* not the primary delete operation */
-
+SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*);
SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
const void *pData, int nData,
int nZero, int bias, int seekResult);
@@ -12099,7 +9550,10 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *);
SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *);
SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
+SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *, unsigned int mask);
+#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor*, unsigned int mask);
+#endif
SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *pBt);
SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void);
@@ -12128,17 +9582,15 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*, int, int *, int *);
#ifndef SQLITE_OMIT_SHARED_CACHE
SQLITE_PRIVATE void sqlite3BtreeEnter(Btree*);
SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3*);
-SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*);
-SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*);
#else
# define sqlite3BtreeEnter(X)
# define sqlite3BtreeEnterAll(X)
-# define sqlite3BtreeSharable(X) 0
-# define sqlite3BtreeEnterCursor(X)
#endif
#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE
+SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*);
SQLITE_PRIVATE void sqlite3BtreeLeave(Btree*);
+SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*);
SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor*);
SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3*);
#ifndef NDEBUG
@@ -12149,7 +9601,9 @@ SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*);
#endif
#else
+# define sqlite3BtreeSharable(X) 0
# define sqlite3BtreeLeave(X)
+# define sqlite3BtreeEnterCursor(X)
# define sqlite3BtreeLeaveCursor(X)
# define sqlite3BtreeLeaveAll(X)
@@ -12208,29 +9662,24 @@ typedef struct SubProgram SubProgram;
struct VdbeOp {
u8 opcode; /* What operation to perform */
signed char p4type; /* One of the P4_xxx constants for p4 */
- u8 notUsed1;
+ u8 opflags; /* Mask of the OPFLG_* flags in opcodes.h */
u8 p5; /* Fifth parameter is an unsigned character */
int p1; /* First operand */
int p2; /* Second parameter (often the jump destination) */
int p3; /* The third parameter */
- union p4union { /* fourth parameter */
+ union { /* fourth parameter */
int i; /* Integer value if p4type==P4_INT32 */
void *p; /* Generic pointer */
char *z; /* Pointer to data for string (char array) types */
i64 *pI64; /* Used when p4type is P4_INT64 */
double *pReal; /* Used when p4type is P4_REAL */
FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */
- sqlite3_context *pCtx; /* Used when p4type is P4_FUNCCTX */
CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */
Mem *pMem; /* Used when p4type is P4_MEM */
VTable *pVtab; /* Used when p4type is P4_VTAB */
KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */
int *ai; /* Used when p4type is P4_INTARRAY */
SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */
- Table *pTab; /* Used when p4type is P4_TABLE */
-#ifdef SQLITE_ENABLE_CURSOR_HINTS
- Expr *pExpr; /* Used when p4type is P4_EXPR */
-#endif
int (*xAdvance)(BtCursor *, int *);
} p4;
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
@@ -12281,7 +9730,6 @@ typedef struct VdbeOpList VdbeOpList;
#define P4_COLLSEQ (-4) /* P4 is a pointer to a CollSeq structure */
#define P4_FUNCDEF (-5) /* P4 is a pointer to a FuncDef structure */
#define P4_KEYINFO (-6) /* P4 is a pointer to a KeyInfo structure */
-#define P4_EXPR (-7) /* P4 is a pointer to an Expr tree */
#define P4_MEM (-8) /* P4 is a pointer to a Mem* structure */
#define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */
#define P4_VTAB (-10) /* P4 is a pointer to an sqlite3_vtab structure */
@@ -12292,8 +9740,6 @@ typedef struct VdbeOpList VdbeOpList;
#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
#define P4_SUBPROGRAM (-18) /* P4 is a pointer to a SubProgram structure */
#define P4_ADVANCE (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */
-#define P4_TABLE (-20) /* P4 is a pointer to a Table structure */
-#define P4_FUNCCTX (-21) /* P4 is a pointer to an sqlite3_context object */
/* Error message codes for OP_Halt */
#define P5_ConstraintNotNull 1
@@ -12335,209 +9781,197 @@ typedef struct VdbeOpList VdbeOpList;
/************** Include opcodes.h in the middle of vdbe.h ********************/
/************** Begin file opcodes.h *****************************************/
/* Automatically generated. Do not edit */
-/* See the tool/mkopcodeh.tcl script for details */
-#define OP_Savepoint 0
-#define OP_AutoCommit 1
-#define OP_Transaction 2
-#define OP_SorterNext 3
-#define OP_PrevIfOpen 4
-#define OP_NextIfOpen 5
-#define OP_Prev 6
-#define OP_Next 7
-#define OP_Checkpoint 8
-#define OP_JournalMode 9
-#define OP_Vacuum 10
-#define OP_VFilter 11 /* synopsis: iplan=r[P3] zplan='P4' */
-#define OP_VUpdate 12 /* synopsis: data=r[P3@P2] */
-#define OP_Goto 13
-#define OP_Gosub 14
-#define OP_InitCoroutine 15
-#define OP_Yield 16
-#define OP_MustBeInt 17
-#define OP_Jump 18
+/* See the mkopcodeh.awk script for details */
+#define OP_Function 1 /* synopsis: r[P3]=func(r[P2@P5]) */
+#define OP_Savepoint 2
+#define OP_AutoCommit 3
+#define OP_Transaction 4
+#define OP_SorterNext 5
+#define OP_PrevIfOpen 6
+#define OP_NextIfOpen 7
+#define OP_Prev 8
+#define OP_Next 9
+#define OP_AggStep 10 /* synopsis: accum=r[P3] step(r[P2@P5]) */
+#define OP_Checkpoint 11
+#define OP_JournalMode 12
+#define OP_Vacuum 13
+#define OP_VFilter 14 /* synopsis: iplan=r[P3] zplan='P4' */
+#define OP_VUpdate 15 /* synopsis: data=r[P3@P2] */
+#define OP_Goto 16
+#define OP_Gosub 17
+#define OP_Return 18
#define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */
-#define OP_Once 20
-#define OP_If 21
-#define OP_IfNot 22
-#define OP_SeekLT 23 /* synopsis: key=r[P3@P4] */
-#define OP_SeekLE 24 /* synopsis: key=r[P3@P4] */
-#define OP_SeekGE 25 /* synopsis: key=r[P3@P4] */
-#define OP_SeekGT 26 /* synopsis: key=r[P3@P4] */
-#define OP_Or 27 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
-#define OP_And 28 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
-#define OP_NoConflict 29 /* synopsis: key=r[P3@P4] */
-#define OP_NotFound 30 /* synopsis: key=r[P3@P4] */
-#define OP_Found 31 /* synopsis: key=r[P3@P4] */
-#define OP_NotExists 32 /* synopsis: intkey=r[P3] */
-#define OP_Last 33
-#define OP_IsNull 34 /* same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
-#define OP_NotNull 35 /* same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
-#define OP_Ne 36 /* same as TK_NE, synopsis: if r[P1]!=r[P3] goto P2 */
-#define OP_Eq 37 /* same as TK_EQ, synopsis: if r[P1]==r[P3] goto P2 */
-#define OP_Gt 38 /* same as TK_GT, synopsis: if r[P1]>r[P3] goto P2 */
-#define OP_Le 39 /* same as TK_LE, synopsis: if r[P1]<=r[P3] goto P2 */
-#define OP_Lt 40 /* same as TK_LT, synopsis: if r[P1]<r[P3] goto P2 */
-#define OP_Ge 41 /* same as TK_GE, synopsis: if r[P1]>=r[P3] goto P2 */
-#define OP_SorterSort 42
-#define OP_BitAnd 43 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
-#define OP_BitOr 44 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
-#define OP_ShiftLeft 45 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
-#define OP_ShiftRight 46 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
-#define OP_Add 47 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
-#define OP_Subtract 48 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
-#define OP_Multiply 49 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
-#define OP_Divide 50 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
-#define OP_Remainder 51 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
-#define OP_Concat 52 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
-#define OP_Sort 53
-#define OP_BitNot 54 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */
-#define OP_Rewind 55
-#define OP_IdxLE 56 /* synopsis: key=r[P3@P4] */
-#define OP_IdxGT 57 /* synopsis: key=r[P3@P4] */
-#define OP_IdxLT 58 /* synopsis: key=r[P3@P4] */
-#define OP_IdxGE 59 /* synopsis: key=r[P3@P4] */
-#define OP_RowSetRead 60 /* synopsis: r[P3]=rowset(P1) */
-#define OP_RowSetTest 61 /* synopsis: if r[P3] in rowset(P1) goto P2 */
-#define OP_Program 62
-#define OP_FkIfZero 63 /* synopsis: if fkctr[P1]==0 goto P2 */
-#define OP_IfPos 64 /* synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
-#define OP_IfNotZero 65 /* synopsis: if r[P1]!=0 then r[P1]-=P3, goto P2 */
-#define OP_DecrJumpZero 66 /* synopsis: if (--r[P1])==0 goto P2 */
-#define OP_IncrVacuum 67
-#define OP_VNext 68
-#define OP_Init 69 /* synopsis: Start at P2 */
-#define OP_Return 70
-#define OP_EndCoroutine 71
-#define OP_HaltIfNull 72 /* synopsis: if r[P3]=null halt */
-#define OP_Halt 73
-#define OP_Integer 74 /* synopsis: r[P2]=P1 */
-#define OP_Int64 75 /* synopsis: r[P2]=P4 */
-#define OP_String 76 /* synopsis: r[P2]='P4' (len=P1) */
-#define OP_Null 77 /* synopsis: r[P2..P3]=NULL */
-#define OP_SoftNull 78 /* synopsis: r[P1]=NULL */
-#define OP_Blob 79 /* synopsis: r[P2]=P4 (len=P1) */
-#define OP_Variable 80 /* synopsis: r[P2]=parameter(P1,P4) */
-#define OP_Move 81 /* synopsis: r[P2@P3]=r[P1@P3] */
-#define OP_Copy 82 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
-#define OP_SCopy 83 /* synopsis: r[P2]=r[P1] */
-#define OP_IntCopy 84 /* synopsis: r[P2]=r[P1] */
-#define OP_ResultRow 85 /* synopsis: output=r[P1@P2] */
-#define OP_CollSeq 86
-#define OP_Function0 87 /* synopsis: r[P3]=func(r[P2@P5]) */
-#define OP_Function 88 /* synopsis: r[P3]=func(r[P2@P5]) */
-#define OP_AddImm 89 /* synopsis: r[P1]=r[P1]+P2 */
-#define OP_RealAffinity 90
-#define OP_Cast 91 /* synopsis: affinity(r[P1]) */
-#define OP_Permutation 92
-#define OP_Compare 93 /* synopsis: r[P1@P3] <-> r[P2@P3] */
-#define OP_Column 94 /* synopsis: r[P3]=PX */
-#define OP_Affinity 95 /* synopsis: affinity(r[P1@P2]) */
-#define OP_MakeRecord 96 /* synopsis: r[P3]=mkrec(r[P1@P2]) */
+#define OP_InitCoroutine 20
+#define OP_EndCoroutine 21
+#define OP_Yield 22
+#define OP_HaltIfNull 23 /* synopsis: if r[P3]=null halt */
+#define OP_Halt 24
+#define OP_Integer 25 /* synopsis: r[P2]=P1 */
+#define OP_Int64 26 /* synopsis: r[P2]=P4 */
+#define OP_String 27 /* synopsis: r[P2]='P4' (len=P1) */
+#define OP_Null 28 /* synopsis: r[P2..P3]=NULL */
+#define OP_SoftNull 29 /* synopsis: r[P1]=NULL */
+#define OP_Blob 30 /* synopsis: r[P2]=P4 (len=P1) */
+#define OP_Variable 31 /* synopsis: r[P2]=parameter(P1,P4) */
+#define OP_Move 32 /* synopsis: r[P2@P3]=r[P1@P3] */
+#define OP_Copy 33 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
+#define OP_SCopy 34 /* synopsis: r[P2]=r[P1] */
+#define OP_ResultRow 35 /* synopsis: output=r[P1@P2] */
+#define OP_CollSeq 36
+#define OP_AddImm 37 /* synopsis: r[P1]=r[P1]+P2 */
+#define OP_MustBeInt 38
+#define OP_RealAffinity 39
+#define OP_Cast 40 /* synopsis: affinity(r[P1]) */
+#define OP_Permutation 41
+#define OP_Compare 42 /* synopsis: r[P1@P3] <-> r[P2@P3] */
+#define OP_Jump 43
+#define OP_Once 44
+#define OP_If 45
+#define OP_IfNot 46
+#define OP_Column 47 /* synopsis: r[P3]=PX */
+#define OP_Affinity 48 /* synopsis: affinity(r[P1@P2]) */
+#define OP_MakeRecord 49 /* synopsis: r[P3]=mkrec(r[P1@P2]) */
+#define OP_Count 50 /* synopsis: r[P2]=count() */
+#define OP_ReadCookie 51
+#define OP_SetCookie 52
+#define OP_ReopenIdx 53 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenRead 54 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenWrite 55 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenAutoindex 56 /* synopsis: nColumn=P2 */
+#define OP_OpenEphemeral 57 /* synopsis: nColumn=P2 */
+#define OP_SorterOpen 58
+#define OP_SequenceTest 59 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */
+#define OP_OpenPseudo 60 /* synopsis: P3 columns in r[P2] */
+#define OP_Close 61
+#define OP_SeekLT 62 /* synopsis: key=r[P3@P4] */
+#define OP_SeekLE 63 /* synopsis: key=r[P3@P4] */
+#define OP_SeekGE 64 /* synopsis: key=r[P3@P4] */
+#define OP_SeekGT 65 /* synopsis: key=r[P3@P4] */
+#define OP_Seek 66 /* synopsis: intkey=r[P2] */
+#define OP_NoConflict 67 /* synopsis: key=r[P3@P4] */
+#define OP_NotFound 68 /* synopsis: key=r[P3@P4] */
+#define OP_Found 69 /* synopsis: key=r[P3@P4] */
+#define OP_NotExists 70 /* synopsis: intkey=r[P3] */
+#define OP_Or 71 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
+#define OP_And 72 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
+#define OP_Sequence 73 /* synopsis: r[P2]=cursor[P1].ctr++ */
+#define OP_NewRowid 74 /* synopsis: r[P2]=rowid */
+#define OP_Insert 75 /* synopsis: intkey=r[P3] data=r[P2] */
+#define OP_IsNull 76 /* same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
+#define OP_NotNull 77 /* same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
+#define OP_Ne 78 /* same as TK_NE, synopsis: if r[P1]!=r[P3] goto P2 */
+#define OP_Eq 79 /* same as TK_EQ, synopsis: if r[P1]==r[P3] goto P2 */
+#define OP_Gt 80 /* same as TK_GT, synopsis: if r[P1]>r[P3] goto P2 */
+#define OP_Le 81 /* same as TK_LE, synopsis: if r[P1]<=r[P3] goto P2 */
+#define OP_Lt 82 /* same as TK_LT, synopsis: if r[P1]<r[P3] goto P2 */
+#define OP_Ge 83 /* same as TK_GE, synopsis: if r[P1]>=r[P3] goto P2 */
+#define OP_InsertInt 84 /* synopsis: intkey=P3 data=r[P2] */
+#define OP_BitAnd 85 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
+#define OP_BitOr 86 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
+#define OP_ShiftLeft 87 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
+#define OP_ShiftRight 88 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
+#define OP_Add 89 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
+#define OP_Subtract 90 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
+#define OP_Multiply 91 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
+#define OP_Divide 92 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
+#define OP_Remainder 93 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
+#define OP_Concat 94 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
+#define OP_Delete 95
+#define OP_BitNot 96 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */
#define OP_String8 97 /* same as TK_STRING, synopsis: r[P2]='P4' */
-#define OP_Count 98 /* synopsis: r[P2]=count() */
-#define OP_ReadCookie 99
-#define OP_SetCookie 100
-#define OP_ReopenIdx 101 /* synopsis: root=P2 iDb=P3 */
-#define OP_OpenRead 102 /* synopsis: root=P2 iDb=P3 */
-#define OP_OpenWrite 103 /* synopsis: root=P2 iDb=P3 */
-#define OP_OpenAutoindex 104 /* synopsis: nColumn=P2 */
-#define OP_OpenEphemeral 105 /* synopsis: nColumn=P2 */
-#define OP_SorterOpen 106
-#define OP_SequenceTest 107 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */
-#define OP_OpenPseudo 108 /* synopsis: P3 columns in r[P2] */
-#define OP_Close 109
-#define OP_ColumnsUsed 110
-#define OP_Sequence 111 /* synopsis: r[P2]=cursor[P1].ctr++ */
-#define OP_NewRowid 112 /* synopsis: r[P2]=rowid */
-#define OP_Insert 113 /* synopsis: intkey=r[P3] data=r[P2] */
-#define OP_InsertInt 114 /* synopsis: intkey=P3 data=r[P2] */
-#define OP_Delete 115
-#define OP_ResetCount 116
-#define OP_SorterCompare 117 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
-#define OP_SorterData 118 /* synopsis: r[P2]=data */
-#define OP_RowKey 119 /* synopsis: r[P2]=key */
-#define OP_RowData 120 /* synopsis: r[P2]=data */
-#define OP_Rowid 121 /* synopsis: r[P2]=rowid */
-#define OP_NullRow 122
-#define OP_SorterInsert 123
-#define OP_IdxInsert 124 /* synopsis: key=r[P2] */
-#define OP_IdxDelete 125 /* synopsis: key=r[P2@P3] */
-#define OP_Seek 126 /* synopsis: Move P3 to P1.rowid */
-#define OP_IdxRowid 127 /* synopsis: r[P2]=rowid */
-#define OP_Destroy 128
-#define OP_Clear 129
-#define OP_ResetSorter 130
-#define OP_CreateIndex 131 /* synopsis: r[P2]=root iDb=P1 */
-#define OP_CreateTable 132 /* synopsis: r[P2]=root iDb=P1 */
+#define OP_ResetCount 98
+#define OP_SorterCompare 99 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
+#define OP_SorterData 100 /* synopsis: r[P2]=data */
+#define OP_RowKey 101 /* synopsis: r[P2]=key */
+#define OP_RowData 102 /* synopsis: r[P2]=data */
+#define OP_Rowid 103 /* synopsis: r[P2]=rowid */
+#define OP_NullRow 104
+#define OP_Last 105
+#define OP_SorterSort 106
+#define OP_Sort 107
+#define OP_Rewind 108
+#define OP_SorterInsert 109
+#define OP_IdxInsert 110 /* synopsis: key=r[P2] */
+#define OP_IdxDelete 111 /* synopsis: key=r[P2@P3] */
+#define OP_IdxRowid 112 /* synopsis: r[P2]=rowid */
+#define OP_IdxLE 113 /* synopsis: key=r[P3@P4] */
+#define OP_IdxGT 114 /* synopsis: key=r[P3@P4] */
+#define OP_IdxLT 115 /* synopsis: key=r[P3@P4] */
+#define OP_IdxGE 116 /* synopsis: key=r[P3@P4] */
+#define OP_Destroy 117
+#define OP_Clear 118
+#define OP_ResetSorter 119
+#define OP_CreateIndex 120 /* synopsis: r[P2]=root iDb=P1 */
+#define OP_CreateTable 121 /* synopsis: r[P2]=root iDb=P1 */
+#define OP_ParseSchema 122
+#define OP_LoadAnalysis 123
+#define OP_DropTable 124
+#define OP_DropIndex 125
+#define OP_DropTrigger 126
+#define OP_IntegrityCk 127
+#define OP_RowSetAdd 128 /* synopsis: rowset(P1)=r[P2] */
+#define OP_RowSetRead 129 /* synopsis: r[P3]=rowset(P1) */
+#define OP_RowSetTest 130 /* synopsis: if r[P3] in rowset(P1) goto P2 */
+#define OP_Program 131
+#define OP_Param 132
#define OP_Real 133 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
-#define OP_ParseSchema 134
-#define OP_LoadAnalysis 135
-#define OP_DropTable 136
-#define OP_DropIndex 137
-#define OP_DropTrigger 138
-#define OP_IntegrityCk 139
-#define OP_RowSetAdd 140 /* synopsis: rowset(P1)=r[P2] */
-#define OP_Param 141
-#define OP_FkCounter 142 /* synopsis: fkctr[P1]+=P2 */
-#define OP_MemMax 143 /* synopsis: r[P1]=max(r[P1],r[P2]) */
-#define OP_OffsetLimit 144 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
-#define OP_AggStep0 145 /* synopsis: accum=r[P3] step(r[P2@P5]) */
-#define OP_AggStep 146 /* synopsis: accum=r[P3] step(r[P2@P5]) */
-#define OP_AggFinal 147 /* synopsis: accum=r[P1] N=P2 */
-#define OP_Expire 148
-#define OP_TableLock 149 /* synopsis: iDb=P1 root=P2 write=P3 */
-#define OP_VBegin 150
-#define OP_VCreate 151
-#define OP_VDestroy 152
-#define OP_VOpen 153
-#define OP_VColumn 154 /* synopsis: r[P3]=vcolumn(P2) */
-#define OP_VRename 155
-#define OP_Pagecount 156
-#define OP_MaxPgcnt 157
-#define OP_CursorHint 158
-#define OP_Noop 159
-#define OP_Explain 160
+#define OP_FkCounter 134 /* synopsis: fkctr[P1]+=P2 */
+#define OP_FkIfZero 135 /* synopsis: if fkctr[P1]==0 goto P2 */
+#define OP_MemMax 136 /* synopsis: r[P1]=max(r[P1],r[P2]) */
+#define OP_IfPos 137 /* synopsis: if r[P1]>0 goto P2 */
+#define OP_IfNeg 138 /* synopsis: r[P1]+=P3, if r[P1]<0 goto P2 */
+#define OP_IfNotZero 139 /* synopsis: if r[P1]!=0 then r[P1]+=P3, goto P2 */
+#define OP_DecrJumpZero 140 /* synopsis: if (--r[P1])==0 goto P2 */
+#define OP_JumpZeroIncr 141 /* synopsis: if (r[P1]++)==0 ) goto P2 */
+#define OP_AggFinal 142 /* synopsis: accum=r[P1] N=P2 */
+#define OP_IncrVacuum 143
+#define OP_Expire 144
+#define OP_TableLock 145 /* synopsis: iDb=P1 root=P2 write=P3 */
+#define OP_VBegin 146
+#define OP_VCreate 147
+#define OP_VDestroy 148
+#define OP_VOpen 149
+#define OP_VColumn 150 /* synopsis: r[P3]=vcolumn(P2) */
+#define OP_VNext 151
+#define OP_VRename 152
+#define OP_Pagecount 153
+#define OP_MaxPgcnt 154
+#define OP_Init 155 /* synopsis: Start at P2 */
+#define OP_Noop 156
+#define OP_Explain 157
+
/* Properties such as "out2" or "jump" that are specified in
** comments following the "case" for each opcode in the vdbe.c
** are encoded into bitvectors as follows:
*/
-#define OPFLG_JUMP 0x01 /* jump: P2 holds jmp target */
-#define OPFLG_IN1 0x02 /* in1: P1 is an input */
-#define OPFLG_IN2 0x04 /* in2: P2 is an input */
-#define OPFLG_IN3 0x08 /* in3: P3 is an input */
-#define OPFLG_OUT2 0x10 /* out2: P2 is an output */
-#define OPFLG_OUT3 0x20 /* out3: P3 is an output */
+#define OPFLG_JUMP 0x0001 /* jump: P2 holds jmp target */
+#define OPFLG_IN1 0x0002 /* in1: P1 is an input */
+#define OPFLG_IN2 0x0004 /* in2: P2 is an input */
+#define OPFLG_IN3 0x0008 /* in3: P3 is an input */
+#define OPFLG_OUT2 0x0010 /* out2: P2 is an output */
+#define OPFLG_OUT3 0x0020 /* out3: P3 is an output */
#define OPFLG_INITIALIZER {\
-/* 0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,\
-/* 8 */ 0x00, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01,\
-/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x03, 0x03, 0x09,\
-/* 24 */ 0x09, 0x09, 0x09, 0x26, 0x26, 0x09, 0x09, 0x09,\
-/* 32 */ 0x09, 0x01, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
-/* 40 */ 0x0b, 0x0b, 0x01, 0x26, 0x26, 0x26, 0x26, 0x26,\
-/* 48 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x01, 0x12, 0x01,\
-/* 56 */ 0x01, 0x01, 0x01, 0x01, 0x23, 0x0b, 0x01, 0x01,\
-/* 64 */ 0x03, 0x03, 0x03, 0x01, 0x01, 0x01, 0x02, 0x02,\
-/* 72 */ 0x08, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10,\
-/* 80 */ 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00,\
-/* 88 */ 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,\
-/* 96 */ 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,\
-/* 104 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\
-/* 112 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 120 */ 0x00, 0x10, 0x00, 0x04, 0x04, 0x00, 0x00, 0x10,\
-/* 128 */ 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00,\
-/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x06, 0x10, 0x00, 0x04,\
-/* 144 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\
-/* 160 */ 0x00,}
-
-/* The sqlite3P2Values() routine is able to run faster if it knows
-** the value of the largest JUMP opcode. The smaller the maximum
-** JUMP opcode the better, so the mkopcodeh.tcl script that
-** generated this include file strives to group all JUMP opcodes
-** together near the beginning of the list.
-*/
-#define SQLITE_MX_JUMP_OPCODE 69 /* Maximum JUMP opcode */
+/* 0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,\
+/* 8 */ 0x01, 0x01, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,\
+/* 16 */ 0x01, 0x01, 0x02, 0x12, 0x01, 0x02, 0x03, 0x08,\
+/* 24 */ 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10,\
+/* 32 */ 0x00, 0x00, 0x10, 0x00, 0x00, 0x02, 0x03, 0x02,\
+/* 40 */ 0x02, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x00,\
+/* 48 */ 0x00, 0x00, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00,\
+/* 56 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09,\
+/* 64 */ 0x09, 0x09, 0x04, 0x09, 0x09, 0x09, 0x09, 0x26,\
+/* 72 */ 0x26, 0x10, 0x10, 0x00, 0x03, 0x03, 0x0b, 0x0b,\
+/* 80 */ 0x0b, 0x0b, 0x0b, 0x0b, 0x00, 0x26, 0x26, 0x26,\
+/* 88 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00,\
+/* 96 */ 0x12, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\
+/* 104 */ 0x00, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x00,\
+/* 112 */ 0x10, 0x01, 0x01, 0x01, 0x01, 0x10, 0x00, 0x00,\
+/* 120 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 128 */ 0x06, 0x23, 0x0b, 0x01, 0x10, 0x10, 0x00, 0x01,\
+/* 136 */ 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x01,\
+/* 144 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\
+/* 152 */ 0x00, 0x10, 0x10, 0x01, 0x00, 0x00,}
/************** End of opcodes.h *********************************************/
/************** Continuing where we left off in vdbe.h ***********************/
@@ -12550,28 +9984,17 @@ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse*);
SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe*,int);
SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe*,int,int);
SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe*,int,int,int);
-SQLITE_PRIVATE int sqlite3VdbeGoto(Vdbe*,int);
-SQLITE_PRIVATE int sqlite3VdbeLoadString(Vdbe*,int,const char*);
-SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe*,int,const char*,...);
SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
-SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int);
SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
-SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe*,int);
-#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
-SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N);
-#else
-# define sqlite3VdbeVerifyNoMallocRequired(A,B)
-#endif
-SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
+SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
-SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8);
SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1);
SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2);
SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3);
SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u8 P5);
SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr);
-SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe*, int addr);
+SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe*, int addr);
SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op);
SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N);
SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*);
@@ -12579,7 +10002,6 @@ SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int);
SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*);
-SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3*,Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,Parse*);
@@ -12760,11 +10182,7 @@ typedef struct PgHdr DbPage;
#define PAGER_LOCKINGMODE_EXCLUSIVE 1
/*
-** Numeric constants that encode the journalmode.
-**
-** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY)
-** are exposed in the API via the "PRAGMA journal_mode" command and
-** therefore cannot be changed without a compatibility break.
+** Numeric constants that encode the journalmode.
*/
#define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */
#define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */
@@ -12775,28 +10193,22 @@ typedef struct PgHdr DbPage;
#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
/*
-** Flags that make up the mask passed to sqlite3PagerGet().
+** Flags that make up the mask passed to sqlite3PagerAcquire().
*/
#define PAGER_GET_NOCONTENT 0x01 /* Do not load data from disk */
#define PAGER_GET_READONLY 0x02 /* Read-only page is acceptable */
/*
** Flags for sqlite3PagerSetFlags()
-**
-** Value constraints (enforced via assert()):
-** PAGER_FULLFSYNC == SQLITE_FullFSync
-** PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync
-** PAGER_CACHE_SPILL == SQLITE_CacheSpill
*/
#define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */
#define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */
#define PAGER_SYNCHRONOUS_FULL 0x03 /* PRAGMA synchronous=FULL */
-#define PAGER_SYNCHRONOUS_EXTRA 0x04 /* PRAGMA synchronous=EXTRA */
-#define PAGER_SYNCHRONOUS_MASK 0x07 /* Mask for four values above */
-#define PAGER_FULLFSYNC 0x08 /* PRAGMA fullfsync=ON */
-#define PAGER_CKPT_FULLFSYNC 0x10 /* PRAGMA checkpoint_fullfsync=ON */
-#define PAGER_CACHESPILL 0x20 /* PRAGMA cache_spill=ON */
-#define PAGER_FLAGS_MASK 0x38 /* All above except SYNCHRONOUS */
+#define PAGER_SYNCHRONOUS_MASK 0x03 /* Mask for three values above */
+#define PAGER_FULLFSYNC 0x04 /* PRAGMA fullfsync=ON */
+#define PAGER_CKPT_FULLFSYNC 0x08 /* PRAGMA checkpoint_fullfsync=ON */
+#define PAGER_CACHESPILL 0x10 /* PRAGMA cache_spill=ON */
+#define PAGER_FLAGS_MASK 0x1c /* All above except SYNCHRONOUS */
/*
** The remainder of this file contains the declarations of the functions
@@ -12820,12 +10232,8 @@ SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
/* Functions used to configure a Pager object. */
SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);
-#ifdef SQLITE_HAS_CODEC
-SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager*,Pager*);
-#endif
SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int);
SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
-SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int);
SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
SQLITE_PRIVATE void sqlite3PagerShrink(Pager*);
SQLITE_PRIVATE void sqlite3PagerSetFlags(Pager*,unsigned);
@@ -12835,10 +10243,10 @@ SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*);
SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager*);
SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager*);
-SQLITE_PRIVATE int sqlite3PagerFlush(Pager*);
/* Functions used to obtain and release page references. */
-SQLITE_PRIVATE int sqlite3PagerGet(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
+SQLITE_PRIVATE int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
+#define sqlite3PagerGet(A,B,C) sqlite3PagerAcquire(A,B,C,0)
SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
SQLITE_PRIVATE void sqlite3PagerRef(DbPage*);
SQLITE_PRIVATE void sqlite3PagerUnref(DbPage*);
@@ -12870,10 +10278,6 @@ SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager);
SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager);
SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager);
-# ifdef SQLITE_ENABLE_SNAPSHOT
-SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
-SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
-# endif
#endif
#ifdef SQLITE_ENABLE_ZIPVFS
@@ -12883,15 +10287,13 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager);
/* Functions used to query pager state and configuration. */
SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager*);
-#ifdef SQLITE_DEBUG
-SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
-#endif
+SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*, int);
-SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*);
+SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager*);
SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
-SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*);
SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
+SQLITE_PRIVATE int sqlite3PagerNosync(Pager*);
SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
@@ -12956,7 +10358,7 @@ struct PgHdr {
sqlite3_pcache_page *pPage; /* Pcache object page handle */
void *pData; /* Page data */
void *pExtra; /* Extra content */
- PgHdr *pDirty; /* Transient list of dirty sorted by pgno */
+ PgHdr *pDirty; /* Transient list of dirty pages */
Pager *pPager; /* The pager this page is part of */
Pgno pgno; /* Page number for this page */
#ifdef SQLITE_CHECK_PAGES
@@ -12976,15 +10378,14 @@ struct PgHdr {
};
/* Bit values for PgHdr.flags */
-#define PGHDR_CLEAN 0x001 /* Page not on the PCache.pDirty list */
-#define PGHDR_DIRTY 0x002 /* Page is on the PCache.pDirty list */
-#define PGHDR_WRITEABLE 0x004 /* Journaled and ready to modify */
-#define PGHDR_NEED_SYNC 0x008 /* Fsync the rollback journal before
- ** writing this page to the database */
-#define PGHDR_DONT_WRITE 0x010 /* Do not write content to disk */
-#define PGHDR_MMAP 0x020 /* This is an mmap page object */
+#define PGHDR_DIRTY 0x002 /* Page has changed */
+#define PGHDR_NEED_SYNC 0x004 /* Fsync the rollback journal before
+ ** writing this page to the database */
+#define PGHDR_NEED_READ 0x008 /* Content is unread */
+#define PGHDR_REUSE_UNLIKELY 0x010 /* A hint that reuse is unlikely */
+#define PGHDR_DONT_WRITE 0x020 /* Do not write content to disk */
-#define PGHDR_WAL_APPEND 0x040 /* Appended to wal file */
+#define PGHDR_MMAP 0x040 /* This is an mmap page object */
/* Initialize and shutdown the page cache subsystem */
SQLITE_PRIVATE int sqlite3PcacheInitialize(void);
@@ -13028,7 +10429,6 @@ SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr*); /* Remove page from cache
SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr*); /* Make sure page is marked dirty */
SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr*); /* Mark a single page as clean */
SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache*); /* Mark all dirty list pages as clean */
-SQLITE_PRIVATE void sqlite3PcacheClearWritable(PCache*);
/* Change a page number. Used by incr-vacuum. */
SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr*, Pgno);
@@ -13067,11 +10467,6 @@ SQLITE_PRIVATE int sqlite3PcachePagecount(PCache*);
SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *));
#endif
-#if defined(SQLITE_DEBUG)
-/* Check invariants on a PgHdr object */
-SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr*);
-#endif
-
/* Set and get the suggested cache-size for the specified pager-cache.
**
** If no global maximum is configured, then the system attempts to limit
@@ -13083,13 +10478,6 @@ SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *, int);
SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *);
#endif
-/* Set or get the suggested spill-size for the specified pager-cache.
-**
-** The spill-size is the minimum number of pages in cache before the cache
-** will attempt to spill dirty pages by calling xStress.
-*/
-SQLITE_PRIVATE int sqlite3PcacheSetSpillsize(PCache *, int);
-
/* Free up as much memory as possible from the page cache */
SQLITE_PRIVATE void sqlite3PcacheShrink(PCache*);
@@ -13108,13 +10496,11 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
SQLITE_PRIVATE int sqlite3HeaderSizePcache(void);
SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void);
-/* Number of dirty pages as a percentage of the configured cache size */
-SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*);
-
#endif /* _PCACHE_H_ */
/************** End of pcache.h **********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
+
/************** Include os.h in the middle of sqliteInt.h ********************/
/************** Begin file os.h **********************************************/
/*
@@ -13340,7 +10726,7 @@ SQLITE_PRIVATE int sqlite3OsInit(void);
/*
** Functions for accessing sqlite3_file methods
*/
-SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file*);
+SQLITE_PRIVATE int sqlite3OsClose(sqlite3_file*);
SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset);
SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file*, i64 size);
@@ -13377,7 +10763,6 @@ SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *, void *);
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *, int);
-SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs*);
SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
/*
@@ -13385,7 +10770,7 @@ SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
** sqlite3_malloc() to obtain space for the file-handle structure.
*/
SQLITE_PRIVATE int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*);
-SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *);
+SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *);
#endif /* _SQLITE_OS_H_ */
@@ -13467,36 +10852,6 @@ SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *);
/************** End of mutex.h ***********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
-/* The SQLITE_EXTRA_DURABLE compile-time option used to set the default
-** synchronous setting to EXTRA. It is no longer supported.
-*/
-#ifdef SQLITE_EXTRA_DURABLE
-# warning Use SQLITE_DEFAULT_SYNCHRONOUS=3 instead of SQLITE_EXTRA_DURABLE
-# define SQLITE_DEFAULT_SYNCHRONOUS 3
-#endif
-
-/*
-** Default synchronous levels.
-**
-** Note that (for historcal reasons) the PAGER_SYNCHRONOUS_* macros differ
-** from the SQLITE_DEFAULT_SYNCHRONOUS value by 1.
-**
-** PAGER_SYNCHRONOUS DEFAULT_SYNCHRONOUS
-** OFF 1 0
-** NORMAL 2 1
-** FULL 3 2
-** EXTRA 4 3
-**
-** The "PRAGMA synchronous" statement also uses the zero-based numbers.
-** In other words, the zero-based numbers are used for all external interfaces
-** and the one-based values are used internally.
-*/
-#ifndef SQLITE_DEFAULT_SYNCHRONOUS
-# define SQLITE_DEFAULT_SYNCHRONOUS (PAGER_SYNCHRONOUS_FULL-1)
-#endif
-#ifndef SQLITE_DEFAULT_WAL_SYNCHRONOUS
-# define SQLITE_DEFAULT_WAL_SYNCHRONOUS SQLITE_DEFAULT_SYNCHRONOUS
-#endif
/*
** Each database file to be accessed by the system is an instance
@@ -13509,7 +10864,6 @@ struct Db {
char *zName; /* Name of this database */
Btree *pBt; /* The B*Tree structure for this database file */
u8 safety_level; /* How aggressive at syncing data to disk */
- u8 bSyncSet; /* True if "PRAGMA synchronous=N" has been run */
Schema *pSchema; /* Pointer to database schema (possibly shared) */
};
@@ -13520,7 +10874,7 @@ struct Db {
** the Schema for the TEMP databaes (sqlite3.aDb[1]) which is free-standing.
** In shared cache mode, a single Schema object can be shared by multiple
** Btrees that refer to the same underlying BtShared object.
-**
+**
** Schema objects are automatically deallocated when the last Btree that
** references them is destroyed. The TEMP Schema is manually freed by
** sqlite3_close().
@@ -13545,7 +10899,7 @@ struct Schema {
};
/*
-** These macros can be used to test, set, or clear bits in the
+** These macros can be used to test, set, or clear bits in the
** Db.pSchema->flags field.
*/
#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))==(P))
@@ -13594,8 +10948,8 @@ struct Schema {
** lookaside allocations are not used to construct the schema objects.
*/
struct Lookaside {
- u32 bDisable; /* Only operate the lookaside when zero */
u16 sz; /* Size of each buffer in bytes */
+ u8 bEnabled; /* False to disable new lookaside allocations */
u8 bMalloced; /* True if pStart obtained from sqlite3_malloc() */
int nOut; /* Number of buffers currently checked out */
int mxOut; /* Highwater mark for nOut */
@@ -13609,15 +10963,13 @@ struct LookasideSlot {
};
/*
-** A hash table for built-in function definitions. (Application-defined
-** functions use a regular table table from hash.h.)
+** A hash table for function definitions.
**
** Hash each FuncDef structure into one of the FuncDefHash.a[] slots.
-** Collisions are on the FuncDef.u.pHash chain.
+** Collisions are on the FuncDef.pHash chain.
*/
-#define SQLITE_FUNC_HASH_SZ 23
struct FuncDefHash {
- FuncDef *a[SQLITE_FUNC_HASH_SZ]; /* Hash table for functions */
+ FuncDef *a[23]; /* Hash table for functions */
};
#ifdef SQLITE_USER_AUTHENTICATION
@@ -13675,13 +11027,11 @@ struct sqlite3 {
unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
int errCode; /* Most recent error code (SQLITE_*) */
int errMask; /* & result codes with this before returning */
- int iSysErrno; /* Errno value from last system error */
u16 dbOptFlags; /* Flags to enable/disable optimizations */
u8 enc; /* Text encoding */
u8 autoCommit; /* The auto-commit flag. */
u8 temp_store; /* 1: file 2: memory 0: default */
u8 mallocFailed; /* True if we have seen a malloc failure */
- u8 bBenignMalloc; /* Do not require OOMs if true */
u8 dfltLockMode; /* Default locking-mode for attached dbs */
signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */
u8 suppressErr; /* Do not issue error messages if true */
@@ -13711,19 +11061,12 @@ struct sqlite3 {
void *pTraceArg; /* Argument to the trace function */
void (*xProfile)(void*,const char*,u64); /* Profiling function */
void *pProfileArg; /* Argument to profile function */
- void *pCommitArg; /* Argument to xCommitCallback() */
+ void *pCommitArg; /* Argument to xCommitCallback() */
int (*xCommitCallback)(void*); /* Invoked at every commit. */
- void *pRollbackArg; /* Argument to xRollbackCallback() */
+ void *pRollbackArg; /* Argument to xRollbackCallback() */
void (*xRollbackCallback)(void*); /* Invoked at every commit. */
void *pUpdateArg;
void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64);
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
- void *pPreUpdateArg; /* First argument to xPreUpdateCallback */
- void (*xPreUpdateCallback)( /* Registered using sqlite3_preupdate_hook() */
- void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64
- );
- PreUpdate *pPreUpdate; /* Context for active pre-update callback */
-#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
#ifndef SQLITE_OMIT_WAL
int (*xWalCallback)(void *, sqlite3 *, const char *, int);
void *pWalArg;
@@ -13753,7 +11096,7 @@ struct sqlite3 {
VTable **aVTrans; /* Virtual tables with open transactions */
VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */
#endif
- Hash aFunc; /* Hash table of connection functions */
+ FuncDefHash aFunc; /* Hash table of connection functions */
Hash aCollSeq; /* All collating sequences */
BusyHandler busyHandler; /* Busy callback */
Db aDbStatic[2]; /* Static space for the 2 default backends */
@@ -13765,8 +11108,8 @@ struct sqlite3 {
i64 nDeferredImmCons; /* Net deferred immediate constraints */
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
- /* The following variables are all protected by the STATIC_MASTER
- ** mutex, not by sqlite3.mutex. They are used by code in notify.c.
+ /* The following variables are all protected by the STATIC_MASTER
+ ** mutex, not by sqlite3.mutex. They are used by code in notify.c.
**
** When X.pUnlockConnection==Y, that means that X is waiting for Y to
** unlock so that it can proceed.
@@ -13794,18 +11137,13 @@ struct sqlite3 {
/*
** Possible values for the sqlite3.flags.
-**
-** Value constraints (enforced via assert()):
-** SQLITE_FullFSync == PAGER_FULLFSYNC
-** SQLITE_CkptFullFSync == PAGER_CKPT_FULLFSYNC
-** SQLITE_CacheSpill == PAGER_CACHE_SPILL
*/
#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
#define SQLITE_InternChanges 0x00000002 /* Uncommitted Hash table changes */
-#define SQLITE_FullColNames 0x00000004 /* Show full column names on SELECT */
-#define SQLITE_FullFSync 0x00000008 /* Use full fsync on the backend */
-#define SQLITE_CkptFullFSync 0x00000010 /* Use full fsync for checkpoint */
-#define SQLITE_CacheSpill 0x00000020 /* OK to spill pager cache */
+#define SQLITE_FullFSync 0x00000004 /* Use full fsync on the backend */
+#define SQLITE_CkptFullFSync 0x00000008 /* Use full fsync for checkpoint */
+#define SQLITE_CacheSpill 0x00000010 /* OK to spill pager cache */
+#define SQLITE_FullColNames 0x00000020 /* Show full column names on SELECT */
#define SQLITE_ShortColNames 0x00000040 /* Show short columns names */
#define SQLITE_CountRows 0x00000080 /* Count rows changed by INSERT, */
/* DELETE, or UPDATE and return */
@@ -13826,14 +11164,11 @@ struct sqlite3 {
#define SQLITE_AutoIndex 0x00100000 /* Enable automatic indexes */
#define SQLITE_PreferBuiltin 0x00200000 /* Preference to built-in funcs */
#define SQLITE_LoadExtension 0x00400000 /* Enable load_extension */
-#define SQLITE_LoadExtFunc 0x00800000 /* Enable load_extension() SQL func */
-#define SQLITE_EnableTrigger 0x01000000 /* True to enable triggers */
-#define SQLITE_DeferFKs 0x02000000 /* Defer all FK constraints */
-#define SQLITE_QueryOnly 0x04000000 /* Disable database changes */
-#define SQLITE_VdbeEQP 0x08000000 /* Debug EXPLAIN QUERY PLAN */
-#define SQLITE_Vacuum 0x10000000 /* Currently in a VACUUM */
-#define SQLITE_CellSizeCk 0x20000000 /* Check btree cell sizes on load */
-#define SQLITE_Fts3Tokenizer 0x40000000 /* Enable fts3_tokenizer(2) */
+#define SQLITE_EnableTrigger 0x00800000 /* True to enable triggers */
+#define SQLITE_DeferFKs 0x01000000 /* Defer all FK constraints */
+#define SQLITE_QueryOnly 0x02000000 /* Disable database changes */
+#define SQLITE_VdbeEQP 0x04000000 /* Debug EXPLAIN QUERY PLAN */
+#define SQLITE_Vacuum 0x08000000 /* Currently in a VACUUM */
/*
@@ -13853,7 +11188,6 @@ struct sqlite3 {
#define SQLITE_Transitive 0x0200 /* Transitive constraints */
#define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */
#define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */
-#define SQLITE_CursorHints 0x2000 /* Add OP_CursorHint opcodes */
#define SQLITE_AllOpts 0xffff /* All optimizations */
/*
@@ -13887,33 +11221,28 @@ struct sqlite3 {
/*
** Each SQL function is defined by an instance of the following
-** structure. For global built-in functions (ex: substr(), max(), count())
-** a pointer to this structure is held in the sqlite3BuiltinFunctions object.
-** For per-connection application-defined functions, a pointer to this
-** structure is held in the db->aHash hash table.
-**
-** The u.pHash field is used by the global built-ins. The u.pDestructor
-** field is used by per-connection app-def functions.
+** structure. A pointer to this structure is stored in the sqlite.aFunc
+** hash table. When multiple functions have the same name, the hash table
+** points to a linked list of these structures.
*/
struct FuncDef {
- i8 nArg; /* Number of arguments. -1 means unlimited */
+ i16 nArg; /* Number of arguments. -1 means unlimited */
u16 funcFlags; /* Some combination of SQLITE_FUNC_* */
void *pUserData; /* User data parameter */
FuncDef *pNext; /* Next function with same name */
- void (*xSFunc)(sqlite3_context*,int,sqlite3_value**); /* func or agg-step */
- void (*xFinalize)(sqlite3_context*); /* Agg finalizer */
- const char *zName; /* SQL name of the function. */
- union {
- FuncDef *pHash; /* Next with a different name but the same hash */
- FuncDestructor *pDestructor; /* Reference counted destructor function */
- } u;
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**); /* Regular function */
+ void (*xStep)(sqlite3_context*,int,sqlite3_value**); /* Aggregate step */
+ 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
+** 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
@@ -13931,52 +11260,36 @@ struct FuncDestructor {
/*
** Possible values for FuncDef.flags. Note that the _LENGTH and _TYPEOF
-** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG. And
-** SQLITE_FUNC_CONSTANT must be the same as SQLITE_DETERMINISTIC. There
+** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG. There
** are assert() statements in the code to verify this.
-**
-** Value constraints (enforced via assert()):
-** SQLITE_FUNC_MINMAX == NC_MinMaxAgg == SF_MinMaxAgg
-** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG
-** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG
-** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API
-** SQLITE_FUNC_ENCMASK depends on SQLITE_UTF* macros in the API
-*/
-#define SQLITE_FUNC_ENCMASK 0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
-#define SQLITE_FUNC_LIKE 0x0004 /* Candidate for the LIKE optimization */
-#define SQLITE_FUNC_CASE 0x0008 /* Case-sensitive LIKE-type function */
-#define SQLITE_FUNC_EPHEM 0x0010 /* Ephemeral. Delete with VDBE */
-#define SQLITE_FUNC_NEEDCOLL 0x0020 /* sqlite3GetFuncCollSeq() might be called*/
-#define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */
-#define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */
-#define SQLITE_FUNC_COUNT 0x0100 /* Built-in count(*) aggregate */
-#define SQLITE_FUNC_COALESCE 0x0200 /* Built-in coalesce() or ifnull() */
-#define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */
-#define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */
-#define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */
-#define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a
- ** single query - might change over time */
+*/
+#define SQLITE_FUNC_ENCMASK 0x003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
+#define SQLITE_FUNC_LIKE 0x004 /* Candidate for the LIKE optimization */
+#define SQLITE_FUNC_CASE 0x008 /* Case-sensitive LIKE-type function */
+#define SQLITE_FUNC_EPHEM 0x010 /* Ephemeral. Delete with VDBE */
+#define SQLITE_FUNC_NEEDCOLL 0x020 /* sqlite3GetFuncCollSeq() might be called */
+#define SQLITE_FUNC_LENGTH 0x040 /* Built-in length() function */
+#define SQLITE_FUNC_TYPEOF 0x080 /* Built-in typeof() function */
+#define SQLITE_FUNC_COUNT 0x100 /* Built-in count(*) aggregate */
+#define SQLITE_FUNC_COALESCE 0x200 /* Built-in coalesce() or ifnull() */
+#define SQLITE_FUNC_UNLIKELY 0x400 /* Built-in unlikely() function */
+#define SQLITE_FUNC_CONSTANT 0x800 /* Constant inputs give a constant output */
+#define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */
/*
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
** used to create the initializers for the FuncDef structures.
**
** FUNCTION(zName, nArg, iArg, bNC, xFunc)
-** Used to create a scalar function definition of a function zName
+** Used to create a scalar function definition of a function zName
** implemented by C function xFunc that accepts nArg arguments. The
** value passed as iArg is cast to a (void*) and made available
-** as the user-data (sqlite3_user_data()) for the function. If
+** as the user-data (sqlite3_user_data()) for the function. If
** argument bNC is true, then the SQLITE_FUNC_NEEDCOLL flag is set.
**
** VFUNCTION(zName, nArg, iArg, bNC, xFunc)
** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag.
**
-** DFUNCTION(zName, nArg, iArg, bNC, xFunc)
-** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and
-** adds the SQLITE_FUNC_SLOCHNG flag. Used for date & time functions
-** and functions like sqlite_version() that can change, but not during
-** a single query.
-**
** AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal)
** Used to create an aggregate function definition implemented by
** the C functions xStep and xFinal. The first four parameters
@@ -13984,8 +11297,8 @@ struct FuncDestructor {
** FUNCTION().
**
** LIKEFUNC(zName, nArg, pArg, flags)
-** Used to create a scalar function definition of a function zName
-** that accepts nArg arguments and is implemented by a call to C
+** Used to create a scalar function definition of a function zName
+** that accepts nArg arguments and is implemented by a call to C
** function likeFunc. Argument pArg is cast to a (void *) and made
** available as the function user-data (sqlite3_user_data()). The
** FuncDef.flags variable is set to the value passed as the flags
@@ -13993,28 +11306,25 @@ struct FuncDestructor {
*/
#define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
{nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
#define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \
{nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
-#define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \
- {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
#define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
{nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 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_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
- pArg, 0, xFunc, 0, #zName, }
+ {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
+ pArg, 0, xFunc, 0, 0, #zName, 0, 0}
#define LIKEFUNC(zName, nArg, arg, flags) \
{nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \
- (void *)arg, 0, likeFunc, 0, #zName, {0} }
+ (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, xStep,xFinal,#zName, {0}}
+ SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
#define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
- SQLITE_INT_TO_PTR(arg), 0, 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
@@ -14048,7 +11358,6 @@ struct Module {
const char *zName; /* Name passed to create_module() */
void *pAux; /* pAux passed to create_module() */
void (*xDestroy)(void *); /* Module destructor function */
- Table *pEpoTab; /* Eponymous table for this module */
};
/*
@@ -14056,12 +11365,14 @@ struct Module {
** of this structure.
*/
struct Column {
- char *zName; /* Name of this column, \000, then the type */
+ char *zName; /* Name of this column */
Expr *pDflt; /* Default value of this column */
+ char *zDflt; /* Original text of the default value */
+ char *zType; /* Data type for this column */
char *zColl; /* Collating sequence. If NULL, use the default */
u8 notNull; /* An OE_ code for handling a NOT NULL constraint */
char affinity; /* One of the SQLITE_AFF_... values */
- u8 szEst; /* Estimated size of value in this column. sizeof(INT)==1 */
+ u8 szEst; /* Estimated size of this column. INT==1 */
u8 colFlags; /* Boolean properties. See COLFLAG_ defines below */
};
@@ -14069,7 +11380,6 @@ struct Column {
*/
#define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */
#define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */
-#define COLFLAG_HASTYPE 0x0004 /* Type name follows column name */
/*
** A "Collating Sequence" is defined by an instance of the following
@@ -14093,23 +11403,22 @@ struct CollSeq {
*/
#define SQLITE_SO_ASC 0 /* Sort in ascending order */
#define SQLITE_SO_DESC 1 /* Sort in ascending order */
-#define SQLITE_SO_UNDEFINED -1 /* No sort order specified */
/*
** Column affinity types.
**
** These used to have mnemonic name like 'i' for SQLITE_AFF_INTEGER and
** 't' for SQLITE_AFF_TEXT. But we can save a little space and improve
-** the speed a little by numbering the values consecutively.
+** the speed a little by numbering the values consecutively.
**
** But rather than start with 0 or 1, we begin with 'A'. That way,
** when multiple affinity types are concatenated into a string and
** used as the P4 operand, they will be more readable.
**
** Note also that the numeric types are grouped together so that testing
-** for a numeric type is a single comparison. And the BLOB type is first.
+** for a numeric type is a single comparison. And the NONE type is first.
*/
-#define SQLITE_AFF_BLOB 'A'
+#define SQLITE_AFF_NONE 'A'
#define SQLITE_AFF_TEXT 'B'
#define SQLITE_AFF_NUMERIC 'C'
#define SQLITE_AFF_INTEGER 'D'
@@ -14119,7 +11428,7 @@ struct CollSeq {
/*
** The SQLITE_AFF_MASK values masks off the significant bits of an
-** affinity value.
+** affinity value.
*/
#define SQLITE_AFF_MASK 0x47
@@ -14139,20 +11448,20 @@ struct CollSeq {
/*
** An object of this type is created for each virtual table present in
-** the database schema.
+** the database schema.
**
** If the database schema is shared, then there is one instance of this
** structure for each database connection (sqlite3*) that uses the shared
** schema. This is because each database connection requires its own unique
-** instance of the sqlite3_vtab* handle used to access the virtual table
-** implementation. sqlite3_vtab* handles can not be shared between
-** database connections, even when the rest of the in-memory database
+** instance of the sqlite3_vtab* handle used to access the virtual table
+** implementation. sqlite3_vtab* handles can not be shared between
+** database connections, even when the rest of the in-memory database
** schema is shared, as the implementation often stores the database
** connection handle passed to it via the xConnect() or xCreate() method
** during initialization internally. This database connection handle may
-** then be used by the virtual table implementation to access real tables
-** within the database. So that they appear as part of the callers
-** transaction, these accesses need to be made via the same database
+** then be used by the virtual table implementation to access real tables
+** within the database. So that they appear as part of the callers
+** transaction, these accesses need to be made via the same database
** connection as that used to execute SQL operations on the virtual table.
**
** All VTable objects that correspond to a single table in a shared
@@ -14164,19 +11473,19 @@ struct CollSeq {
** sqlite3_vtab* handle in the compiled query.
**
** When an in-memory Table object is deleted (for example when the
-** schema is being reloaded for some reason), the VTable objects are not
-** deleted and the sqlite3_vtab* handles are not xDisconnect()ed
+** schema is being reloaded for some reason), the VTable objects are not
+** deleted and the sqlite3_vtab* handles are not xDisconnect()ed
** immediately. Instead, they are moved from the Table.pVTable list to
** another linked list headed by the sqlite3.pDisconnect member of the
-** corresponding sqlite3 structure. They are then deleted/xDisconnected
+** corresponding sqlite3 structure. They are then deleted/xDisconnected
** next time a statement is prepared using said sqlite3*. This is done
** to avoid deadlock issues involving multiple sqlite3.mutex mutexes.
** Refer to comments above function sqlite3VtabUnlockList() for an
** explanation as to why it is safe to add an entry to an sqlite3.pDisconnect
** list without holding the corresponding sqlite3.mutex mutex.
**
-** The memory for objects of this type is always allocated by
-** sqlite3DbMalloc(), using the connection handle stored in VTable.db as
+** The memory for objects of this type is always allocated by
+** sqlite3DbMalloc(), using the connection handle stored in VTable.db as
** the first argument.
*/
struct VTable {
@@ -14200,8 +11509,9 @@ struct Table {
Select *pSelect; /* NULL for tables. Points to definition if a view. */
FKey *pFKey; /* Linked list of all foreign keys in this table */
char *zColAff; /* String defining the affinity of each column */
+#ifndef SQLITE_OMIT_CHECK
ExprList *pCheck; /* All CHECK constraints */
- /* ... also used as column name list in a VIEW */
+#endif
int tnum; /* Root BTree page for this table */
i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */
i16 nCol; /* Number of columns in this table */
@@ -14218,7 +11528,7 @@ struct Table {
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
int nModuleArg; /* Number of arguments to the module */
- char **azModuleArg; /* 0: module 1: schema 2: vtab name 3...: args */
+ char **azModuleArg; /* Text of all module args. [0] is module name */
VTable *pVTable; /* List of VTable objects. */
#endif
Trigger *pTrigger; /* List of triggers stored in pSchema */
@@ -14229,7 +11539,7 @@ struct Table {
/*
** Allowed values for Table.tabFlags.
**
-** TF_OOOHidden applies to tables or view that have hidden columns that are
+** TF_OOOHidden applies to virtual tables that have hidden columns that are
** followed by non-hidden columns. Example: "CREATE VIRTUAL TABLE x USING
** vtab1(a HIDDEN, b);". Since "b" is a non-hidden column but "a" is hidden,
** the TF_OOOHidden attribute would apply in this case. Such tables require
@@ -14240,9 +11550,8 @@ struct Table {
#define TF_HasPrimaryKey 0x04 /* Table has a primary key */
#define TF_Autoincrement 0x08 /* Integer primary key is autoincrement */
#define TF_Virtual 0x10 /* Is a virtual table */
-#define TF_WithoutRowid 0x20 /* No rowid. PRIMARY KEY is the key */
-#define TF_NoVisibleRowid 0x40 /* No user-visible "rowid" column */
-#define TF_OOOHidden 0x80 /* Out-of-Order hidden columns */
+#define TF_WithoutRowid 0x20 /* No rowid used. PRIMARY KEY is the key */
+#define TF_OOOHidden 0x40 /* Out-of-Order hidden columns */
/*
@@ -14252,31 +11561,14 @@ struct Table {
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
# define IsVirtual(X) (((X)->tabFlags & TF_Virtual)!=0)
+# define IsHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0)
#else
# define IsVirtual(X) 0
+# define IsHiddenColumn(X) 0
#endif
-/*
-** Macros to determine if a column is hidden. IsOrdinaryHiddenColumn()
-** only works for non-virtual tables (ordinary tables and views) and is
-** always false unless SQLITE_ENABLE_HIDDEN_COLUMNS is defined. The
-** IsHiddenColumn() macro is general purpose.
-*/
-#if defined(SQLITE_ENABLE_HIDDEN_COLUMNS)
-# define IsHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0)
-# define IsOrdinaryHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0)
-#elif !defined(SQLITE_OMIT_VIRTUALTABLE)
-# define IsHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0)
-# define IsOrdinaryHiddenColumn(X) 0
-#else
-# define IsHiddenColumn(X) 0
-# define IsOrdinaryHiddenColumn(X) 0
-#endif
-
-
/* Does the table have a rowid */
#define HasRowid(X) (((X)->tabFlags & TF_WithoutRowid)==0)
-#define VisibleRowid(X) (((X)->tabFlags & TF_NoVisibleRowid)==0)
/*
** Each foreign key constraint is an instance of the following structure.
@@ -14344,7 +11636,7 @@ struct FKey {
** key is set to NULL. CASCADE means that a DELETE or UPDATE of the
** referenced table row is propagated into the row that holds the
** foreign key.
-**
+**
** The following symbolic values are used to record which type
** of action to take.
*/
@@ -14365,7 +11657,7 @@ struct FKey {
/*
** An instance of the following structure is passed as the first
-** argument to sqlite3VdbeKeyCompare and is used to control the
+** argument to sqlite3VdbeKeyCompare and is used to control the
** comparison of the two index keys.
**
** Note that aSortOrder[] and aColl[] have nField+1 slots. There
@@ -14383,8 +11675,9 @@ struct KeyInfo {
};
/*
-** This object holds a record which has been parsed out into individual
-** fields, for the purposes of doing a comparison.
+** An instance of the following structure holds information about a
+** single index record that has already been parsed out into individual
+** values.
**
** A record is an object that contains one or more fields of data.
** Records are used to store the content of a table row and to store
@@ -14392,40 +11685,20 @@ struct KeyInfo {
** the OP_MakeRecord opcode of the VDBE and is disassembled by the
** OP_Column opcode.
**
-** An instance of this object serves as a "key" for doing a search on
-** an index b+tree. The goal of the search is to find the entry that
-** is closed to the key described by this object. This object might hold
-** just a prefix of the key. The number of fields is given by
-** pKeyInfo->nField.
-**
-** The r1 and r2 fields are the values to return if this key is less than
-** or greater than a key in the btree, respectively. These are normally
-** -1 and +1 respectively, but might be inverted to +1 and -1 if the b-tree
-** is in DESC order.
-**
-** The key comparison functions actually return default_rc when they find
-** an equals comparison. default_rc can be -1, 0, or +1. If there are
-** multiple entries in the b-tree with the same key (when only looking
-** at the first pKeyInfo->nFields,) then default_rc can be set to -1 to
-** cause the search to find the last match, or +1 to cause the search to
-** find the first match.
-**
-** The key comparison functions will set eqSeen to true if they ever
-** get and equal results when comparing this structure to a b-tree record.
-** When default_rc!=0, the search might end up on the record immediately
-** before the first match or immediately after the last match. The
-** eqSeen field will indicate whether or not an exact match exists in the
-** b-tree.
+** This structure holds a record that has already been disassembled
+** into its constituent fields.
+**
+** The r1 and r2 member variables are only used by the optimized comparison
+** functions vdbeRecordCompareInt() and vdbeRecordCompareString().
*/
struct UnpackedRecord {
KeyInfo *pKeyInfo; /* Collation and sort-order information */
- Mem *aMem; /* Values */
u16 nField; /* Number of entries in apMem[] */
i8 default_rc; /* Comparison result if keys are equal */
u8 errCode; /* Error detected by xRecordCompare (CORRUPT or NOMEM) */
- i8 r1; /* Value to return if (lhs > rhs) */
- i8 r2; /* Value to return if (rhs < lhs) */
- u8 eqSeen; /* True if an equality comparison has been seen */
+ Mem *aMem; /* Values */
+ int r1; /* Value to return if (lhs > rhs) */
+ int r2; /* Value to return if (rhs < lhs) */
};
@@ -14443,7 +11716,7 @@ struct UnpackedRecord {
** In the Table structure describing Ex1, nCol==3 because there are
** three columns in the table. In the Index structure describing
** Ex2, nColumn==2 since 2 of the 3 columns of Ex1 are indexed.
-** The value of aiColumn is {2, 0}. aiColumn[0]==2 because the
+** The value of aiColumn is {2, 0}. aiColumn[0]==2 because the
** first column to be indexed (c3) has an index of 2 in Ex1.aCol[].
** The second column to be indexed (c1) has an index of 0 in
** Ex1.aCol[], hence Ex2.aiColumn[1]==0.
@@ -14451,17 +11724,9 @@ struct UnpackedRecord {
** The Index.onError field determines whether or not the indexed columns
** must be unique and what to do if they are not. When Index.onError=OE_None,
** it means this is not a unique index. Otherwise it is a unique index
-** and the value of Index.onError indicate the which conflict resolution
+** and the value of Index.onError indicate the which conflict resolution
** algorithm to employ whenever an attempt is made to insert a non-unique
** element.
-**
-** While parsing a CREATE TABLE or CREATE INDEX statement in order to
-** generate VDBE code (as opposed to parsing one read from an sqlite_master
-** table as part of parsing an existing database schema), transient instances
-** of this structure may be created. In this case the Index.tnum variable is
-** used to store the address of a VDBE instruction, not a database page
-** number (it cannot - the database page is not allocated until the VDBE
-** program is executed). See convertToWithoutRowidTable() for details.
*/
struct Index {
char *zName; /* Name of this index */
@@ -14472,9 +11737,8 @@ struct Index {
Index *pNext; /* The next index associated with the same table */
Schema *pSchema; /* Schema containing this index */
u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
- const char **azColl; /* Array of collation sequence names for index */
+ char **azColl; /* Array of collation sequence names for index */
Expr *pPartIdxWhere; /* WHERE clause for partial indices */
- ExprList *aColExpr; /* Column expressions */
int tnum; /* DB Page containing root of this index */
LogEst szIdxRow; /* Estimated average row size in bytes */
u16 nKeyCol; /* Number of columns forming the key */
@@ -14509,14 +11773,8 @@ struct Index {
/* Return true if index X is a UNIQUE index */
#define IsUniqueIndex(X) ((X)->onError!=OE_None)
-/* The Index.aiColumn[] values are normally positive integer. But
-** there are some negative values that have special meaning:
-*/
-#define XN_ROWID (-1) /* Indexed column is the rowid */
-#define XN_EXPR (-2) /* Indexed column is an expression */
-
/*
-** Each sample stored in the sqlite_stat3 table is represented in memory
+** Each sample stored in the sqlite_stat3 table is represented in memory
** using a structure of this type. See documentation at the top of the
** analyze.c source file for additional information.
*/
@@ -14611,9 +11869,9 @@ typedef int ynVar;
** to represent the greater-than-or-equal-to operator in the expression
** tree.
**
-** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB,
+** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB,
** or TK_STRING), then Expr.token contains the text of the SQL literal. If
-** the expression is a variable (TK_VARIABLE), then Expr.token contains the
+** the expression is a variable (TK_VARIABLE), then Expr.token contains the
** variable name. Finally, if the expression is an SQL function (TK_FUNCTION),
** then Expr.token contains the name of the function.
**
@@ -14624,7 +11882,7 @@ typedef int ynVar;
** a CASE expression or an IN expression of the form "<lhs> IN (<y>, <z>...)".
** Expr.x.pSelect is used if the expression is a sub-select or an expression of
** the form "<lhs> IN (SELECT ...)". If the EP_xIsSelect bit is set in the
-** Expr.flags mask, then Expr.x.pSelect is valid. Otherwise, Expr.x.pList is
+** Expr.flags mask, then Expr.x.pSelect is valid. Otherwise, Expr.x.pList is
** valid.
**
** An expression of the form ID or ID.ID refers to a column in a table.
@@ -14635,8 +11893,8 @@ typedef int ynVar;
** value is also stored in the Expr.iAgg column in the aggregate so that
** it can be accessed after all aggregates are computed.
**
-** If the expression is an unbound variable marker (a question mark
-** character '?' in the original SQL) then the Expr.iTable holds the index
+** If the expression is an unbound variable marker (a question mark
+** character '?' in the original SQL) then the Expr.iTable holds the index
** number for that variable.
**
** If the expression is a subquery then Expr.iColumn holds an integer
@@ -14675,7 +11933,7 @@ struct Expr {
/* If the EP_TokenOnly flag is set in the Expr.flags mask, then no
** space is allocated for the fields below this point. An attempt to
- ** access them will result in a segfault or malfunction.
+ ** access them will result in a segfault or malfunction.
*********************************************************************/
Expr *pLeft; /* Left subnode */
@@ -14730,10 +11988,9 @@ struct Expr {
#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */
#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */
-#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
+#define EP_ConstFunc 0x080000 /* Node is a SQLITE_FUNC_CONSTANT function */
#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */
-#define EP_Alias 0x400000 /* Is an alias for a result set column */
/*
** Combinations of two or more EP_* flags
@@ -14741,7 +11998,7 @@ struct Expr {
#define EP_Propagate (EP_Collate|EP_Subquery) /* Propagate these bits up tree */
/*
-** These macros can be used to test, set, or clear bits in the
+** These macros can be used to test, set, or clear bits in the
** Expr.flags field.
*/
#define ExprHasProperty(E,P) (((E)->flags&(P))!=0)
@@ -14760,8 +12017,8 @@ struct Expr {
#endif
/*
-** Macros to determine the number of bytes required by a normal Expr
-** struct, an Expr struct with the EP_Reduced flag set in Expr.flags
+** Macros to determine the number of bytes required by a normal Expr
+** struct, an Expr struct with the EP_Reduced flag set in Expr.flags
** and an Expr struct with the EP_TokenOnly flag set.
*/
#define EXPR_FULLSIZE sizeof(Expr) /* Full size */
@@ -14769,7 +12026,7 @@ struct Expr {
#define EXPR_TOKENONLYSIZE offsetof(Expr,pLeft) /* Fewer features */
/*
-** Flags passed to the sqlite3ExprDup() function. See the header comment
+** Flags passed to the sqlite3ExprDup() function. See the header comment
** above sqlite3ExprDup() for details.
*/
#define EXPRDUP_REDUCE 0x0001 /* Used reduced-size Expr nodes */
@@ -14851,11 +12108,7 @@ struct IdList {
** tables in a join to 32 instead of 64. But it also reduces the size
** of the library by 738 bytes on ix86.
*/
-#ifdef SQLITE_BITMASK_TYPE
- typedef SQLITE_BITMASK_TYPE Bitmask;
-#else
- typedef u64 Bitmask;
-#endif
+typedef u64 Bitmask;
/*
** The number of bits in a Bitmask. "BMS" means "BitMask Size".
@@ -14867,7 +12120,6 @@ struct IdList {
*/
#define MASKBIT(n) (((Bitmask)1)<<(n))
#define MASKBIT32(n) (((unsigned int)1)<<(n))
-#define ALLBITS ((Bitmask)-1)
/*
** The following structure describes the FROM clause of a SELECT statement.
@@ -14901,15 +12153,11 @@ struct SrcList {
int addrFillSub; /* Address of subroutine to manifest a subquery */
int regReturn; /* Register holding return address of addrFillSub */
int regResult; /* Registers holding results of a co-routine */
- struct {
- u8 jointype; /* Type of join between this able and the previous */
- unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
- unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */
- unsigned isTabFunc :1; /* True if table-valued-function syntax */
- unsigned isCorrelated :1; /* True if sub-query is correlated */
- unsigned viaCoroutine :1; /* Implemented as a co-routine */
- unsigned isRecursive :1; /* True for recursive reference in WITH */
- } fg;
+ u8 jointype; /* Type of join between this able and the previous */
+ unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
+ unsigned isCorrelated :1; /* True if sub-query is correlated */
+ unsigned viaCoroutine :1; /* Implemented as a co-routine */
+ unsigned isRecursive :1; /* True for recursive reference in WITH */
#ifndef SQLITE_OMIT_EXPLAIN
u8 iSelectId; /* If pSelect!=0, the id of the sub-select in EQP */
#endif
@@ -14917,11 +12165,8 @@ struct SrcList {
Expr *pOn; /* The ON clause of a join */
IdList *pUsing; /* The USING clause of a join */
Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */
- union {
- char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
- ExprList *pFuncArg; /* Arguments to table-valued-function */
- } u1;
- Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
+ char *zIndex; /* Identifier from "INDEXED BY <zIndex>" clause */
+ Index *pIndex; /* Index structure corresponding to zIndex, if any */
} a[1]; /* One entry for each identifier on the list */
};
@@ -14940,9 +12185,6 @@ struct SrcList {
/*
** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin()
** and the WhereInfo.wctrlFlags member.
-**
-** Value constraints (enforced via assert()):
-** WHERE_USE_LIMIT == SF_FixedLimit
*/
#define WHERE_ORDERBY_NORMAL 0x0000 /* No-op */
#define WHERE_ORDERBY_MIN 0x0001 /* ORDER BY processing for min() func */
@@ -14958,9 +12200,6 @@ struct SrcList {
#define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */
#define WHERE_SORTBYGROUP 0x0800 /* Support sqlite3WhereIsSorted() */
#define WHERE_REOPEN_IDX 0x1000 /* Try to use OP_ReopenIdx */
-#define WHERE_ONEPASS_MULTIROW 0x2000 /* ONEPASS is ok with multiple rows */
-#define WHERE_USE_LIMIT 0x4000 /* There is a constant LIMIT clause */
-#define WHERE_SEEK_TABLE 0x8000 /* Do not defer seeks on main table */
/* Allowed return values from sqlite3WhereIsDistinct()
*/
@@ -14978,12 +12217,12 @@ struct SrcList {
** pEList corresponds to the result set of a SELECT and is NULL for
** other statements.
**
-** NameContexts can be nested. When resolving names, the inner-most
+** NameContexts can be nested. When resolving names, the inner-most
** context is searched first. If no match is found, the next outer
** context is checked. If there is still no match, the next context
** is checked. This process continues until either a match is found
** or all contexts are check. When a match is found, the nRef member of
-** the context containing the match is incremented.
+** the context containing the match is incremented.
**
** Each subquery gets a new NameContext. The pNext field points to the
** NameContext in the parent query. Thus the process of scanning the
@@ -15004,18 +12243,15 @@ struct NameContext {
/*
** Allowed values for the NameContext, ncFlags field.
**
-** Value constraints (all checked via assert()):
-** NC_HasAgg == SF_HasAgg
-** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX
-**
+** Note: NC_MinMaxAgg must have the same value as SF_MinMaxAgg and
+** SQLITE_FUNC_MINMAX.
+**
*/
#define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */
-#define NC_PartIdx 0x0002 /* True if resolving a partial index WHERE */
+#define NC_HasAgg 0x0002 /* One or more aggregate functions seen */
#define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */
#define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */
-#define NC_HasAgg 0x0010 /* One or more aggregate functions seen */
-#define NC_IdxExpr 0x0020 /* True if resolving columns of CREATE INDEX */
-#define NC_VarSelect 0x0040 /* A correlated subquery has been seen */
+#define NC_PartIdx 0x0010 /* True if resolving a partial index WHERE */
#define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */
/*
@@ -15041,13 +12277,13 @@ struct NameContext {
struct Select {
ExprList *pEList; /* The fields of the result */
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
- LogEst nSelectRow; /* Estimated number of result rows */
- u32 selFlags; /* Various SF_* values */
+ u16 selFlags; /* Various SF_* values */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
#if SELECTTRACE_ENABLED
char zSelName[12]; /* Symbolic name of this SELECT use for debugging */
#endif
int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */
+ u64 nSelectRow; /* Estimated number of result rows */
SrcList *pSrc; /* The FROM clause */
Expr *pWhere; /* The WHERE clause */
ExprList *pGroupBy; /* The GROUP BY clause */
@@ -15063,30 +12299,21 @@ struct Select {
/*
** Allowed values for Select.selFlags. The "SF" prefix stands for
** "Select Flag".
-**
-** Value constraints (all checked via assert())
-** SF_HasAgg == NC_HasAgg
-** SF_MinMaxAgg == NC_MinMaxAgg == SQLITE_FUNC_MINMAX
-** SF_FixedLimit == WHERE_USE_LIMIT
-*/
-#define SF_Distinct 0x00001 /* Output should be DISTINCT */
-#define SF_All 0x00002 /* Includes the ALL keyword */
-#define SF_Resolved 0x00004 /* Identifiers have been resolved */
-#define SF_Aggregate 0x00008 /* Contains agg functions or a GROUP BY */
-#define SF_HasAgg 0x00010 /* Contains aggregate functions */
-#define SF_UsesEphemeral 0x00020 /* Uses the OpenEphemeral opcode */
-#define SF_Expanded 0x00040 /* sqlite3SelectExpand() called on this */
-#define SF_HasTypeInfo 0x00080 /* FROM subqueries have Table metadata */
-#define SF_Compound 0x00100 /* Part of a compound query */
-#define SF_Values 0x00200 /* Synthesized from VALUES clause */
-#define SF_MultiValue 0x00400 /* Single VALUES term with multiple rows */
-#define SF_NestedFrom 0x00800 /* Part of a parenthesized FROM clause */
-#define SF_MinMaxAgg 0x01000 /* Aggregate containing min() or max() */
-#define SF_Recursive 0x02000 /* The recursive part of a recursive CTE */
-#define SF_FixedLimit 0x04000 /* nSelectRow set by a constant LIMIT */
-#define SF_MaybeConvert 0x08000 /* Need convertCompoundSelectToSubquery() */
-#define SF_Converted 0x10000 /* By convertCompoundSelectToSubquery() */
-#define SF_IncludeHidden 0x20000 /* Include hidden columns in output */
+*/
+#define SF_Distinct 0x0001 /* Output should be DISTINCT */
+#define SF_Resolved 0x0002 /* Identifiers have been resolved */
+#define SF_Aggregate 0x0004 /* Contains aggregate functions */
+#define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
+#define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
+#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
+#define SF_Compound 0x0040 /* Part of a compound query */
+#define SF_Values 0x0080 /* Synthesized from VALUES clause */
+#define SF_MultiValue 0x0100 /* Single VALUES term with multiple rows */
+#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
+#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
+#define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
+#define SF_MinMaxAgg 0x1000 /* Aggregate containing min() or max() */
+#define SF_Converted 0x2000 /* By convertCompoundSelectToSubquery() */
/*
@@ -15094,7 +12321,7 @@ struct Select {
** by one of the following macros. The "SRT" prefix means "SELECT Result
** Type".
**
-** SRT_Union Store results as a key in a temporary index
+** SRT_Union Store results as a key in a temporary index
** identified by pDest->iSDParm.
**
** SRT_Except Remove results from the temporary index pDest->iSDParm.
@@ -15118,7 +12345,7 @@ struct Select {
** of the query. This destination implies "LIMIT 1".
**
** SRT_Set The result must be a single column. Store each
-** row of result as the key in table pDest->iSDParm.
+** row of result as the key in table pDest->iSDParm.
** Apply the affinity pDest->affSdst before storing
** results. Used to implement "IN (SELECT ...)".
**
@@ -15186,11 +12413,11 @@ struct SelectDest {
};
/*
-** During code generation of statements that do inserts into AUTOINCREMENT
+** During code generation of statements that do inserts into AUTOINCREMENT
** tables, the following information is attached to the Table.u.autoInc.p
** pointer of each autoincrement table to record some side information that
** the code generator needs. We have to keep per-table autoincrement
-** information in case inserts are done within triggers. Triggers do not
+** information in case inserts are down within triggers. Triggers do not
** normally coordinate their activities, but we do need to coordinate the
** loading and saving of autoincrement information.
*/
@@ -15209,7 +12436,7 @@ struct AutoincInfo {
#endif
/*
-** At least one instance of the following structure is created for each
+** At least one instance of the following structure is created for each
** trigger that may be fired while parsing an INSERT, UPDATE or DELETE
** statement. All such objects are stored in the linked list headed at
** Parse.pTriggerPrg and deleted once statement compilation has been
@@ -15222,7 +12449,7 @@ struct AutoincInfo {
** values for both pTrigger and orconf.
**
** The TriggerPrg.aColmask[0] variable is set to a mask of old.* columns
-** accessed (or set to 0 for triggers fired as a result of INSERT
+** accessed (or set to 0 for triggers fired as a result of INSERT
** statements). Similarly, the TriggerPrg.aColmask[1] variable is set to
** a mask of new.* columns used by the program.
*/
@@ -15263,7 +12490,7 @@ struct TriggerPrg {
** is constant but the second part is reset at the beginning and end of
** each recursion.
**
-** The nTableLock and aTableLock variables are only used if the shared-cache
+** The nTableLock and aTableLock variables are only used if the shared-cache
** feature is enabled (if sqlite3Tsd()->useSharedData is true). They are
** used to store the set of table-locks required by the statement being
** compiled. Function sqlite3TableLock() is used to add entries to the
@@ -15282,8 +12509,6 @@ struct Parse {
u8 mayAbort; /* True if statement may throw an ABORT exception */
u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
u8 okConstFactor; /* OK to factor out constants */
- u8 disableLookaside; /* Number of times lookaside has been disabled */
- u8 nColCache; /* Number of entries in aColCache[] */
int aTempReg[8]; /* Holding area for temporary registers */
int nRangeReg; /* Size of the temporary register block */
int iRangeReg; /* First register in temporary register block */
@@ -15293,10 +12518,9 @@ struct Parse {
int nSet; /* Number of sets used so far */
int nOnce; /* Number of OP_Once instructions so far */
int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */
- int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */
int iFixedOp; /* Never back out opcodes iFixedOp-1 or earlier */
int ckBase; /* Base register of data during check constraints */
- int iSelfTab; /* Table of an index whose exprs are being coded */
+ int iPartIdxTab; /* Table corresponding to a partial index */
int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
int iCacheCnt; /* Counter used to generate aColCache[].lru values */
int nLabel; /* Number of labels used */
@@ -15331,6 +12555,7 @@ struct Parse {
Parse *pToplevel; /* Parse structure for main program (or NULL) */
Table *pTriggerTab; /* Table triggers are being coded for */
int addrCrTab; /* Address of OP_CreateTable opcode on CREATE TABLE */
+ int addrSkipPK; /* Address of instruction to skip PRIMARY KEY index */
u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
u32 oldmask; /* Mask of old.* columns referenced */
u32 newmask; /* Mask of new.* columns referenced */
@@ -15345,9 +12570,10 @@ struct Parse {
** in the recursive region.
************************************************************************/
- ynVar nVar; /* Number of '?' variables seen in the SQL so far */
+ int nVar; /* Number of '?' variables seen in the SQL so far */
int nzVar; /* Number of available slots in azVar[] */
u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */
+ u8 bFreeWith; /* True if pWith should be freed with parser */
u8 explain; /* True if the EXPLAIN flag is found on the query */
#ifndef SQLITE_OMIT_VIRTUALTABLE
u8 declareVtab; /* True if inside sqlite3_declare_vtab() */
@@ -15374,7 +12600,6 @@ struct Parse {
Table *pZombieTab; /* List of Table objects to delete after code gen */
TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
With *pWith; /* Current WITH clause, or NULL */
- With *pWithToFree; /* Free this WITH object at the end of the parse */
};
/*
@@ -15397,42 +12622,26 @@ struct AuthContext {
/*
** Bitfield flags for P5 value in various opcodes.
-**
-** Value constraints (enforced via assert()):
-** OPFLAG_LENGTHARG == SQLITE_FUNC_LENGTH
-** OPFLAG_TYPEOFARG == SQLITE_FUNC_TYPEOF
-** OPFLAG_BULKCSR == BTREE_BULKLOAD
-** OPFLAG_SEEKEQ == BTREE_SEEK_EQ
-** OPFLAG_FORDELETE == BTREE_FORDELETE
-** OPFLAG_SAVEPOSITION == BTREE_SAVEPOSITION
-** OPFLAG_AUXDELETE == BTREE_AUXDELETE
-*/
-#define OPFLAG_NCHANGE 0x01 /* OP_Insert: Set to update db->nChange */
- /* Also used in P2 (not P5) of OP_Delete */
+*/
+#define OPFLAG_NCHANGE 0x01 /* Set to update db->nChange */
#define OPFLAG_EPHEM 0x01 /* OP_Column: Ephemeral output is ok */
#define OPFLAG_LASTROWID 0x02 /* Set to update db->lastRowid */
#define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */
#define OPFLAG_APPEND 0x08 /* This is likely to be an append */
#define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
-#define OPFLAG_ISNOOP 0x40 /* OP_Delete does pre-update-hook only */
-#endif
#define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */
#define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */
#define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */
#define OPFLAG_SEEKEQ 0x02 /* OP_Open** cursor uses EQ seek only */
-#define OPFLAG_FORDELETE 0x08 /* OP_Open should use BTREE_FORDELETE */
-#define OPFLAG_P2ISREG 0x10 /* P2 to OP_Open** is a register number */
+#define OPFLAG_P2ISREG 0x04 /* P2 to OP_Open** is a register number */
#define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */
-#define OPFLAG_SAVEPOSITION 0x02 /* OP_Delete: keep cursor position */
-#define OPFLAG_AUXDELETE 0x04 /* OP_Delete: index in a DELETE op */
/*
* Each trigger present in the database schema is stored as an instance of
- * struct Trigger.
+ * struct Trigger.
*
* Pointers to instances of struct Trigger are stored in two ways.
- * 1. In the "trigHash" hash table (part of the sqlite3* that represents the
+ * 1. In the "trigHash" hash table (part of the sqlite3* that represents the
* database). This allows Trigger structures to be retrieved by name.
* 2. All triggers associated with a single table form a linked list, using the
* pNext member of struct Trigger. A pointer to the first element of the
@@ -15458,7 +12667,7 @@ struct Trigger {
/*
** A trigger is either a BEFORE or an AFTER trigger. The following constants
-** determine which.
+** determine which.
**
** If there are multiple triggers, you might of some BEFORE and some AFTER.
** In that cases, the constants below can be ORed together.
@@ -15468,15 +12677,15 @@ struct Trigger {
/*
* An instance of struct TriggerStep is used to store a single SQL statement
- * that is a part of a trigger-program.
+ * that is a part of a trigger-program.
*
* Instances of struct TriggerStep are stored in a singly linked list (linked
- * using the "pNext" member) referenced by the "step_list" member of the
+ * using the "pNext" member) referenced by the "step_list" member of the
* associated struct Trigger instance. The first element of the linked list is
* the first step of the trigger-program.
- *
+ *
* The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or
- * "SELECT" statement. The meanings of the other members is determined by the
+ * "SELECT" statement. The meanings of the other members is determined by the
* value of "op" as follows:
*
* (op == TK_INSERT)
@@ -15486,7 +12695,7 @@ struct Trigger {
* zTarget -> Dequoted name of the table to insert into.
* pExprList -> If this is an INSERT INTO ... VALUES ... statement, then
* this stores values to be inserted. Otherwise NULL.
- * pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ...
+ * pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ...
* statement, then this stores the column-names to be
* inserted into.
*
@@ -15494,7 +12703,7 @@ struct Trigger {
* zTarget -> Dequoted name of the table to delete from.
* pWhere -> The WHERE clause of the DELETE statement if one is specified.
* Otherwise NULL.
- *
+ *
* (op == TK_UPDATE)
* zTarget -> Dequoted name of the table to update.
* pWhere -> The WHERE clause of the UPDATE statement if one is specified.
@@ -15502,7 +12711,7 @@ struct Trigger {
* pExprList -> A list of the columns to update and the expressions to update
* them to. See sqlite3Update() documentation of "pChanges"
* argument.
- *
+ *
*/
struct TriggerStep {
u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */
@@ -15520,7 +12729,7 @@ struct TriggerStep {
/*
** The following structure contains information used by the sqliteFix...
** routines as they walk the parse tree to make database references
-** explicit.
+** explicit.
*/
typedef struct DbFixer DbFixer;
struct DbFixer {
@@ -15540,20 +12749,13 @@ struct StrAccum {
sqlite3 *db; /* Optional database for lookaside. Can be NULL */
char *zBase; /* A base allocation. Not from malloc. */
char *zText; /* The string collected so far */
- u32 nChar; /* Length of the string so far */
- u32 nAlloc; /* Amount of space allocated in zText */
- u32 mxAlloc; /* Maximum allowed allocation. 0 for no malloc usage */
+ int nChar; /* Length of the string so far */
+ int nAlloc; /* Amount of space allocated in zText */
+ int mxAlloc; /* Maximum allowed allocation. 0 for no malloc usage */
u8 accError; /* STRACCUM_NOMEM or STRACCUM_TOOBIG */
- u8 printfFlags; /* SQLITE_PRINTF flags below */
};
#define STRACCUM_NOMEM 1
#define STRACCUM_TOOBIG 2
-#define SQLITE_PRINTF_INTERNAL 0x01 /* Internal-use-only converters allowed */
-#define SQLITE_PRINTF_SQLFUNC 0x02 /* SQL function arguments to VXPrintf */
-#define SQLITE_PRINTF_MALLOCED 0x04 /* True if xText is allocated space */
-
-#define isMalloced(X) (((X)->printfFlags & SQLITE_PRINTF_MALLOCED)!=0)
-
/*
** A pointer to this structure is used to communicate information
@@ -15581,7 +12783,6 @@ struct Sqlite3Config {
int neverCorrupt; /* Database is always well-formed */
int szLookaside; /* Default lookaside buffer size */
int nLookaside; /* Default lookaside buffer count */
- int nStmtSpill; /* Stmt-journal spill-to-disk threshold */
sqlite3_mem_methods m; /* Low-level memory allocation interface */
sqlite3_mutex_methods mutex; /* Low-level mutex interface */
sqlite3_pcache_methods2 pcache2; /* Low-level page-cache interface */
@@ -15649,10 +12850,10 @@ struct Sqlite3Config {
** Context pointer passed down through the tree-walk.
*/
struct Walker {
- Parse *pParse; /* Parser context. */
int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */
int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */
void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */
+ Parse *pParse; /* Parser context. */
int walkerDepth; /* Number of subqueries */
u8 eCode; /* A small processing code */
union { /* Extra data for callback */
@@ -15661,8 +12862,6 @@ struct Walker {
int iCur; /* A cursor number */
SrcList *pSrcList; /* FROM clause */
struct SrcCount *pSrcCount; /* Counting column references */
- struct CCurHint *pCCurHint; /* Used by codeCursorHint() */
- int *aiCol; /* array of column indexes */
} u;
};
@@ -15672,7 +12871,6 @@ SQLITE_PRIVATE int sqlite3WalkExprList(Walker*, ExprList*);
SQLITE_PRIVATE int sqlite3WalkSelect(Walker*, Select*);
SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker*, Select*);
SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker*, Select*);
-SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker*, Expr*);
/*
** Return code from the parse-tree walking primitives and their
@@ -15693,7 +12891,7 @@ struct With {
char *zName; /* Name of this CTE */
ExprList *pCols; /* List of explicit column names, or NULL */
Select *pSelect; /* The definition of this CTE */
- const char *zCteErr; /* Error message for circular references */
+ const char *zErr; /* Error message for circular references */
} a[1];
};
@@ -15731,23 +12929,7 @@ SQLITE_PRIVATE int sqlite3CantopenError(int);
#define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__)
#define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__)
#define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__)
-#ifdef SQLITE_DEBUG
-SQLITE_PRIVATE int sqlite3NomemError(int);
-SQLITE_PRIVATE int sqlite3IoerrnomemError(int);
-# define SQLITE_NOMEM_BKPT sqlite3NomemError(__LINE__)
-# define SQLITE_IOERR_NOMEM_BKPT sqlite3IoerrnomemError(__LINE__)
-#else
-# define SQLITE_NOMEM_BKPT SQLITE_NOMEM
-# define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM
-#endif
-/*
-** FTS3 and FTS4 both require virtual table support
-*/
-#if defined(SQLITE_OMIT_VIRTUALTABLE)
-# undef SQLITE_ENABLE_FTS3
-# undef SQLITE_ENABLE_FTS4
-#endif
/*
** FTS4 is really an extension for FTS3. It is enabled using the
@@ -15780,7 +12962,6 @@ SQLITE_PRIVATE int sqlite3IoerrnomemError(int);
# define sqlite3Isdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x04)
# define sqlite3Isxdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x08)
# define sqlite3Tolower(x) (sqlite3UpperToLower[(unsigned char)(x)])
-# define sqlite3Isquote(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x80)
#else
# define sqlite3Toupper(x) toupper((unsigned char)(x))
# define sqlite3Isspace(x) isspace((unsigned char)(x))
@@ -15789,18 +12970,14 @@ SQLITE_PRIVATE int sqlite3IoerrnomemError(int);
# define sqlite3Isdigit(x) isdigit((unsigned char)(x))
# define sqlite3Isxdigit(x) isxdigit((unsigned char)(x))
# define sqlite3Tolower(x) tolower((unsigned char)(x))
-# define sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`')
#endif
-#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
SQLITE_PRIVATE int sqlite3IsIdChar(u8);
-#endif
/*
** Internal function prototypes
*/
-SQLITE_PRIVATE int sqlite3StrICmp(const char*,const char*);
+#define sqlite3StrICmp sqlite3_stricmp
SQLITE_PRIVATE int sqlite3Strlen30(const char*);
-SQLITE_PRIVATE char *sqlite3ColumnType(Column*,char*);
#define sqlite3StrNICmp sqlite3_strnicmp
SQLITE_PRIVATE int sqlite3MallocInit(void);
@@ -15809,7 +12986,6 @@ SQLITE_PRIVATE void *sqlite3Malloc(u64);
SQLITE_PRIVATE void *sqlite3MallocZero(u64);
SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3*, u64);
SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3*, u64);
-SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3*, u64);
SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3*,const char*);
SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, u64);
SQLITE_PRIVATE void *sqlite3Realloc(void*, u64);
@@ -15823,9 +12999,7 @@ SQLITE_PRIVATE void sqlite3ScratchFree(void*);
SQLITE_PRIVATE void *sqlite3PageMalloc(int);
SQLITE_PRIVATE void sqlite3PageFree(void*);
SQLITE_PRIVATE void sqlite3MemSetDefault(void);
-#ifndef SQLITE_OMIT_BUILTIN_TEST
SQLITE_PRIVATE void sqlite3BenignMallocHooks(void (*)(void), void (*)(void));
-#endif
SQLITE_PRIVATE int sqlite3HeapNearlyFull(void);
/*
@@ -15839,7 +13013,7 @@ SQLITE_PRIVATE int sqlite3HeapNearlyFull(void);
#ifdef SQLITE_USE_ALLOCA
# define sqlite3StackAllocRaw(D,N) alloca(N)
# define sqlite3StackAllocZero(D,N) memset(alloca(N), 0, N)
-# define sqlite3StackFree(D,P)
+# define sqlite3StackFree(D,P)
#else
# define sqlite3StackAllocRaw(D,N) sqlite3DbMallocRaw(D,N)
# define sqlite3StackAllocZero(D,N) sqlite3DbMallocZero(D,N)
@@ -15861,16 +13035,11 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int);
SQLITE_PRIVATE int sqlite3MutexInit(void);
SQLITE_PRIVATE int sqlite3MutexEnd(void);
#endif
-#if !defined(SQLITE_MUTEX_OMIT) && !defined(SQLITE_MUTEX_NOOP)
-SQLITE_PRIVATE void sqlite3MemoryBarrier(void);
-#else
-# define sqlite3MemoryBarrier()
-#endif
SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int);
SQLITE_PRIVATE void sqlite3StatusUp(int, int);
SQLITE_PRIVATE void sqlite3StatusDown(int, int);
-SQLITE_PRIVATE void sqlite3StatusHighwater(int, int);
+SQLITE_PRIVATE void sqlite3StatusSet(int, int);
/* Access to mutexes used by sqlite3_status() */
SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void);
@@ -15892,10 +13061,13 @@ struct PrintfArguments {
sqlite3_value **apArg; /* The argument values */
};
-SQLITE_PRIVATE void sqlite3VXPrintf(StrAccum*, const char*, va_list);
-SQLITE_PRIVATE void sqlite3XPrintf(StrAccum*, const char*, ...);
+#define SQLITE_PRINTF_INTERNAL 0x01
+#define SQLITE_PRINTF_SQLFUNC 0x02
+SQLITE_PRIVATE void sqlite3VXPrintf(StrAccum*, u32, const char*, va_list);
+SQLITE_PRIVATE void sqlite3XPrintf(StrAccum*, u32, const char*, ...);
SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3*,const char*, ...);
SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
+SQLITE_PRIVATE char *sqlite3MAppendf(sqlite3*,char*,const char*,...);
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
SQLITE_PRIVATE void sqlite3DebugPrintf(const char*, ...);
#endif
@@ -15904,17 +13076,19 @@ SQLITE_PRIVATE void *sqlite3TestTextToPtr(const char*);
#endif
#if defined(SQLITE_DEBUG)
+SQLITE_PRIVATE TreeView *sqlite3TreeViewPush(TreeView*,u8);
+SQLITE_PRIVATE void sqlite3TreeViewPop(TreeView*);
+SQLITE_PRIVATE void sqlite3TreeViewLine(TreeView*, const char*, ...);
+SQLITE_PRIVATE void sqlite3TreeViewItem(TreeView*, const char*, u8);
SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView*, const Expr*, u8);
SQLITE_PRIVATE void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*);
SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView*, const Select*, u8);
-SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView*, const With*, u8);
#endif
-SQLITE_PRIVATE void sqlite3SetString(char **, sqlite3*, const char*);
+SQLITE_PRIVATE void sqlite3SetString(char **, sqlite3*, const char*, ...);
SQLITE_PRIVATE void sqlite3ErrorMsg(Parse*, const char*, ...);
-SQLITE_PRIVATE void sqlite3Dequote(char*);
-SQLITE_PRIVATE void sqlite3TokenInit(Token*,char*);
+SQLITE_PRIVATE int sqlite3Dequote(char*);
SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char*, int);
SQLITE_PRIVATE int sqlite3RunParser(Parse*, const char*, char **);
SQLITE_PRIVATE void sqlite3FinishCoding(Parse*);
@@ -15923,20 +13097,15 @@ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse*,int);
SQLITE_PRIVATE int sqlite3GetTempRange(Parse*,int);
SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse*,int,int);
SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse*);
-#ifdef SQLITE_DEBUG
-SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse*,int,int);
-#endif
SQLITE_PRIVATE Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int);
SQLITE_PRIVATE Expr *sqlite3Expr(sqlite3*,int,const char*);
SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*);
SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*, const Token*);
-SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*);
SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*);
SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*);
SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*);
SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
-SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int);
SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);
SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*);
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*);
@@ -15947,24 +13116,18 @@ SQLITE_PRIVATE void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3*);
SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3*,int);
SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3*);
+SQLITE_PRIVATE void sqlite3BeginParse(Parse*,int);
SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3*);
-SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*);
-SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
-SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*);
SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*);
SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *, int);
SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*);
SQLITE_PRIVATE i16 sqlite3ColumnOfIndex(Index*, i16);
SQLITE_PRIVATE void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int);
-#if SQLITE_ENABLE_HIDDEN_COLUMNS
-SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table*, Column*);
-#else
-# define sqlite3ColumnPropertiesFromName(T,C) /* no-op */
-#endif
-SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token*,Token*);
+SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token*);
SQLITE_PRIVATE void sqlite3AddNotNull(Parse*, int);
SQLITE_PRIVATE void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*);
+SQLITE_PRIVATE void sqlite3AddColumnType(Parse*,Token*);
SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,ExprSpan*);
SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*);
SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*);
@@ -15981,14 +13144,11 @@ SQLITE_PRIVATE int sqlite3FaultSim(int);
SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32);
SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec*, u32);
-SQLITE_PRIVATE int sqlite3BitvecTestNotNull(Bitvec*, u32);
SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec*, u32);
SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec*, u32, void*);
SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec*);
SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec*);
-#ifndef SQLITE_OMIT_BUILTIN_TEST
SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int,int*);
-#endif
SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int);
SQLITE_PRIVATE void sqlite3RowSetClear(RowSet*);
@@ -15996,7 +13156,7 @@ SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet*, i64);
SQLITE_PRIVATE int sqlite3RowSetTest(RowSet*, int iBatch, i64);
SQLITE_PRIVATE int sqlite3RowSetNext(RowSet*, i64*);
-SQLITE_PRIVATE void sqlite3CreateView(Parse*,Token*,Token*,Token*,ExprList*,Select*,int,int);
+SQLITE_PRIVATE void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse*,Table*);
@@ -16026,7 +13186,6 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*)
SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
Token*, Select*, Expr*, IdList*);
SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *);
-SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*);
SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *, struct SrcList_item *);
SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList*);
SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*);
@@ -16038,7 +13197,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*
SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int);
SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*);
SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
- Expr*,ExprList*,u32,Expr*,Expr*);
+ Expr*,ExprList*,u16,Expr*,Expr*);
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*);
SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*);
SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int);
@@ -16050,19 +13209,14 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int);
SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*);
-SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo*);
+SQLITE_PRIVATE u64 sqlite3WhereOutputRowCount(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo*, int*);
-#define ONEPASS_OFF 0 /* Use of ONEPASS not allowed */
-#define ONEPASS_SINGLE 1 /* ONEPASS valid for a single row update */
-#define ONEPASS_MULTI 2 /* ONEPASS is valid for multiple rows */
-SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int);
SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
-SQLITE_PRIVATE void sqlite3ExprCodeGetColumnToReg(Parse*, Table*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse*, int, int, int);
@@ -16072,19 +13226,16 @@ SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse*, int, int);
SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse*);
SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse*, int, int);
SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int);
-SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, Expr*, int);
SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int);
SQLITE_PRIVATE void sqlite3ExprCodeAtInit(Parse*, Expr*, int, u8);
SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int);
SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse*, Expr*, int);
-SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8);
+SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, u8);
#define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */
#define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */
-#define SQLITE_ECEL_REF 0x04 /* Use ExprList.u.x.iOrderByCol */
SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
-SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int);
SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3*,const char*, const char*);
SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*);
SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *);
@@ -16101,10 +13252,8 @@ SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr*, SrcList*);
SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*);
-#ifndef SQLITE_OMIT_BUILTIN_TEST
SQLITE_PRIVATE void sqlite3PrngSaveState(void);
SQLITE_PRIVATE void sqlite3PrngRestoreState(void);
-#endif
SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*,int);
SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int);
SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb);
@@ -16118,22 +13267,18 @@ SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8);
SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int);
-#ifdef SQLITE_ENABLE_CURSOR_HINTS
-SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*);
-#endif
SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr*, int*);
SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*);
SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
SQLITE_PRIVATE int sqlite3IsRowid(const char*);
-SQLITE_PRIVATE void sqlite3GenerateRowDelete(
- Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int);
-SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int);
+SQLITE_PRIVATE void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8);
+SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*);
SQLITE_PRIVATE int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int);
SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse*,int);
SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int,
- u8,u8,int,int*,int*);
+ u8,u8,int,int*);
SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int);
-SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, u8, int, u8*, int*, int*);
+SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, u8*, int*, int*);
SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int);
SQLITE_PRIVATE void sqlite3MultiWrite(Parse*);
SQLITE_PRIVATE void sqlite3MayAbort(Parse*);
@@ -16150,11 +13295,11 @@ SQLITE_PRIVATE void sqlite3SelectSetName(Select*,const char*);
#else
# define sqlite3SelectSetName(A,B)
#endif
-SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int);
-SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8);
-SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void);
+SQLITE_PRIVATE void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*);
+SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,u8);
+SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3*);
SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void);
-SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*);
+SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void);
SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*);
SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3*);
SQLITE_PRIVATE void sqlite3ChangeCookie(Parse*, int);
@@ -16185,7 +13330,6 @@ SQLITE_PRIVATE void sqlite3DeleteTrigger(sqlite3*, Trigger*);
SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
SQLITE_PRIVATE u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int);
# define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p))
-# define sqlite3IsToplevel(p) ((p)->pToplevel==0)
#else
# define sqlite3TriggersExist(B,C,D,E,F) 0
# define sqlite3DeleteTrigger(A,B)
@@ -16195,7 +13339,6 @@ SQLITE_PRIVATE u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Tab
# define sqlite3CodeRowTriggerDirect(A,B,C,D,E,F)
# define sqlite3TriggerList(X, Y) 0
# define sqlite3ParseToplevel(p) p
-# define sqlite3IsToplevel(p) 1
# define sqlite3TriggerColmask(A,B,C,D,E,F,G) 0
#endif
@@ -16233,11 +13376,7 @@ SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst,LogEst);
#ifndef SQLITE_OMIT_VIRTUALTABLE
SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double);
#endif
-#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
- defined(SQLITE_ENABLE_STAT3_OR_STAT4) || \
- defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst);
-#endif
/*
** Routines to read and write variable-length integers. These used to
@@ -16263,7 +13402,7 @@ SQLITE_PRIVATE int sqlite3VarintLen(u64 v);
#define putVarint sqlite3PutVarint
-SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3*, Index*);
+SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *, Index *);
SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int);
SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2);
SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
@@ -16272,7 +13411,6 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8);
SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*);
SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...);
SQLITE_PRIVATE void sqlite3Error(sqlite3*,int);
-SQLITE_PRIVATE void sqlite3SystemError(sqlite3*,int);
SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
SQLITE_PRIVATE u8 sqlite3HexToInt(int h);
SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
@@ -16305,7 +13443,7 @@ SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z,u8);
SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8);
SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8);
-SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
+SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
void(*)(void*));
SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value*);
SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*);
@@ -16315,12 +13453,11 @@ SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value
SQLITE_PRIVATE void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
#ifndef SQLITE_AMALGAMATION
SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[];
-SQLITE_PRIVATE const char sqlite3StrBINARY[];
SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[];
SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[];
SQLITE_PRIVATE const Token sqlite3IntTokens[];
SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config;
-SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions;
+SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
#ifndef SQLITE_OMIT_WSD
SQLITE_PRIVATE int sqlite3PendingByte;
#endif
@@ -16334,10 +13471,8 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*);
SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *, Expr *, int, int);
SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*);
-SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p);
SQLITE_PRIVATE int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);
SQLITE_PRIVATE int sqlite3ResolveExprNames(NameContext*, Expr*);
-SQLITE_PRIVATE int sqlite3ResolveExprListNames(NameContext*, ExprList*);
SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
SQLITE_PRIVATE void sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*);
SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
@@ -16355,6 +13490,7 @@ SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3*,Index*);
SQLITE_PRIVATE void sqlite3DefaultRowEst(Index*);
SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3*, int);
SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);
+SQLITE_PRIVATE void sqlite3MinimumFileFormat(Parse*, int, int);
SQLITE_PRIVATE void sqlite3SchemaClear(void *);
SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *, Btree *);
SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *);
@@ -16365,13 +13501,11 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*);
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo*);
#endif
-SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
+SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
void (*)(sqlite3_context*,int,sqlite3_value **),
void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*),
FuncDestructor *pDestructor
);
-SQLITE_PRIVATE void sqlite3OomFault(sqlite3*);
-SQLITE_PRIVATE void sqlite3OomClear(sqlite3*);
SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int);
SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *);
@@ -16428,7 +13562,7 @@ SQLITE_PRIVATE int sqlite3Utf8To8(unsigned char*);
# define sqlite3VtabRollback(X)
# define sqlite3VtabCommit(X)
# define sqlite3VtabInSync(db) 0
-# define sqlite3VtabLock(X)
+# define sqlite3VtabLock(X)
# define sqlite3VtabUnlock(X)
# define sqlite3VtabUnlockList(X)
# define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK
@@ -16447,8 +13581,6 @@ SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*);
SQLITE_PRIVATE VTable *sqlite3GetVTable(sqlite3*, Table*);
# define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
#endif
-SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse*,Module*);
-SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3*,Module*);
SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*);
SQLITE_PRIVATE void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*, int);
SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse*, Token*);
@@ -16486,7 +13618,7 @@ SQLITE_PRIVATE void sqlite3WithPush(Parse*, With*, u8);
** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign
** key functionality is available. If OMIT_TRIGGER is defined but
** OMIT_FOREIGN_KEY is not, only some of the functions are no-oped. In
-** this case foreign keys are parsed, but no other functionality is
+** this case foreign keys are parsed, but no other functionality is
** provided (enforcement of FK constraints requires the triggers sub-system).
*/
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
@@ -16547,14 +13679,19 @@ SQLITE_PRIVATE void sqlite3EndBenignMalloc(void);
#define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */
SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, u32, int*);
-SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
-SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *);
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
+SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *);
SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *);
+SQLITE_PRIVATE int sqlite3JournalExists(sqlite3_file *p);
+#else
+ #define sqlite3JournalSize(pVfs) ((pVfs)->szOsFile)
+ #define sqlite3JournalExists(p) 1
#endif
-SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p);
SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *);
+SQLITE_PRIVATE int sqlite3MemJournalSize(void);
+SQLITE_PRIVATE int sqlite3IsMemJournal(sqlite3_file *);
SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p);
#if SQLITE_MAX_EXPR_DEPTH>0
@@ -16585,7 +13722,7 @@ SQLITE_PRIVATE void sqlite3ParserTrace(FILE*, char *);
/*
** If the SQLITE_ENABLE IOTRACE exists then the global variable
** sqlite3IoTrace is a pointer to a printf-like routine used to
-** print I/O tracing messages.
+** print I/O tracing messages.
*/
#ifdef SQLITE_ENABLE_IOTRACE
# define IOTRACE(A) if( sqlite3IoTrace ){ sqlite3IoTrace A; }
@@ -16619,7 +13756,7 @@ SQLITE_API SQLITE_EXTERN void (SQLITE_CDECL *sqlite3IoTrace)(const char*,...);
** that allocations that might have been satisfied by lookaside are not
** passed back to non-lookaside free() routines. Asserts such as the
** example above are placed on the non-lookaside free() routines to verify
-** this constraint.
+** this constraint.
**
** All of this is no-op for a production build. It only comes into
** play when the SQLITE_MEMDEBUG compile-time option is used.
@@ -16646,10 +13783,6 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*);
SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread*, void**);
#endif
-#if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)
-SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3*);
-#endif
-
#endif /* _SQLITEINT_H_ */
/************** End of sqliteInt.h *******************************************/
@@ -16668,7 +13801,6 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3*);
**
** This file contains definitions of global variables and constants.
*/
-/* #include "sqliteInt.h" */
/* An array to map all upper-case characters into their corresponding
** lower-case character.
@@ -16726,7 +13858,6 @@ SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = {
** isxdigit() 0x08
** toupper() 0x20
** SQLite identifier character 0x40
-** Quote character 0x80
**
** Bit 0x20 is set if the mapped character requires translation to upper
** case. i.e. if the character is a lower-case ASCII character.
@@ -16752,7 +13883,7 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 08..0f ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10..17 ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18..1f ........ */
- 0x01, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x80, /* 20..27 !"#$%&' */
+ 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, /* 20..27 !"#$%&' */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28..2f ()*+,-./ */
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, /* 30..37 01234567 */
0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 38..3f 89:;<=>? */
@@ -16760,8 +13891,8 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02, /* 40..47 @ABCDEFG */
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 48..4f HIJKLMNO */
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 50..57 PQRSTUVW */
- 0x02, 0x02, 0x02, 0x80, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */
- 0x80, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */
+ 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */
+ 0x00, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 68..6f hijklmno */
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 70..77 pqrstuvw */
0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, /* 78..7f xyz{|}~. */
@@ -16816,18 +13947,6 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
# define SQLITE_SORTER_PMASZ 250
#endif
-/* Statement journals spill to disk when their size exceeds the following
-** threashold (in bytes). 0 means that statement journals are created and
-** written to disk immediately (the default behavior for SQLite versions
-** before 3.12.0). -1 means always keep the entire statement journal in
-** memory. (The statement journal is also always held entirely in memory
-** if journal_mode=MEMORY or if temp_store=MEMORY, regardless of this
-** setting.)
-*/
-#ifndef SQLITE_STMTJRNL_SPILL
-# define SQLITE_STMTJRNL_SPILL (64*1024)
-#endif
-
/*
** The following singleton contains the global configuration for
** the SQLite library.
@@ -16842,7 +13961,6 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, /* neverCorrupt */
128, /* szLookaside */
500, /* nLookaside */
- SQLITE_STMTJRNL_SPILL, /* nStmtSpill */
{0,0,0,0,0,0,0,0}, /* m */
{0,0,0,0,0,0,0,0,0}, /* mutex */
{0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */
@@ -16856,7 +13974,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, /* nScratch */
(void*)0, /* pPage */
0, /* szPage */
- SQLITE_DEFAULT_PCACHE_INITSZ, /* nPage */
+ 0, /* nPage */
0, /* mxParserStack */
0, /* sharedCacheEnabled */
SQLITE_SORTER_PMASZ, /* szPma */
@@ -16889,7 +14007,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
** database connections. After initialization, this table is
** read-only.
*/
-SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions;
+SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
/*
** Constant tokens for values 0 and 1.
@@ -16922,7 +14040,6 @@ SQLITE_PRIVATE const Token sqlite3IntTokens[] = {
SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;
#endif
-/* #include "opcodes.h" */
/*
** Properties of opcodes. The OPFLG_INITIALIZER macro is
** created by mkopcodeh.awk during compilation. Data is obtained
@@ -16931,11 +14048,6 @@ SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;
*/
SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
-/*
-** Name of the default collating sequence
-*/
-SQLITE_PRIVATE const char sqlite3StrBINARY[] = "BINARY";
-
/************** End of global.c **********************************************/
/************** Begin file ctime.c *******************************************/
/*
@@ -16956,7 +14068,6 @@ SQLITE_PRIVATE const char sqlite3StrBINARY[] = "BINARY";
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
-/* #include "sqliteInt.h" */
/*
** An array of names of all compile-time options. This array should
@@ -17003,9 +14114,6 @@ static const char * const azCompileOpt[] = {
#if SQLITE_DISABLE_LFS
"DISABLE_LFS",
#endif
-#if SQLITE_ENABLE_8_3_NAMES
- "ENABLE_8_3_NAMES",
-#endif
#if SQLITE_ENABLE_API_ARMOR
"ENABLE_API_ARMOR",
#endif
@@ -17039,18 +14147,12 @@ static const char * const azCompileOpt[] = {
#if SQLITE_ENABLE_FTS4
"ENABLE_FTS4",
#endif
-#if SQLITE_ENABLE_FTS5
- "ENABLE_FTS5",
-#endif
#if SQLITE_ENABLE_ICU
"ENABLE_ICU",
#endif
#if SQLITE_ENABLE_IOTRACE
"ENABLE_IOTRACE",
#endif
-#if SQLITE_ENABLE_JSON1
- "ENABLE_JSON1",
-#endif
#if SQLITE_ENABLE_LOAD_EXTENSION
"ENABLE_LOAD_EXTENSION",
#endif
@@ -17101,9 +14203,6 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_INT64_TYPE
"INT64_TYPE",
#endif
-#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
- "LIKE_DOESNT_MATCH_BLOBS",
-#endif
#if SQLITE_LOCK_TRACE
"LOCK_TRACE",
#endif
@@ -17398,7 +14497,6 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N){
** This module implements the sqlite3_status() interface and related
** functionality.
*/
-/* #include "sqliteInt.h" */
/************** Include vdbeInt.h in the middle of status.c ******************/
/************** Begin file vdbeInt.h *****************************************/
/*
@@ -17430,17 +14528,6 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N){
#endif
/*
-** VDBE_DISPLAY_P4 is true or false depending on whether or not the
-** "explain" P4 display logic is enabled.
-*/
-#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
- || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
-# define VDBE_DISPLAY_P4 1
-#else
-# define VDBE_DISPLAY_P4 0
-#endif
-
-/*
** SQL is translated into a sequence of instructions to be
** executed by a virtual machine. Each instruction is an instance
** of the following structure.
@@ -17461,55 +14548,42 @@ typedef struct Explain Explain;
/* Elements of the linked list at Vdbe.pAuxData */
typedef struct AuxData AuxData;
-/* Types of VDBE cursors */
-#define CURTYPE_BTREE 0
-#define CURTYPE_SORTER 1
-#define CURTYPE_VTAB 2
-#define CURTYPE_PSEUDO 3
-
/*
-** A VdbeCursor is an superclass (a wrapper) for various cursor objects:
+** A cursor is a pointer into a single BTree within a database file.
+** The cursor can seek to a BTree entry with a particular key, or
+** loop over all entries of the Btree. You can also insert new BTree
+** entries or retrieve the key or data from the entry that the cursor
+** is currently pointing to.
**
-** * A b-tree cursor
-** - In the main database or in an ephemeral database
-** - On either an index or a table
-** * A sorter
-** * A virtual table
-** * A one-row "pseudotable" stored in a single register
+** Cursors can also point to virtual tables, sorters, or "pseudo-tables".
+** A pseudo-table is a single-row table implemented by registers.
+**
+** Every cursor that the virtual machine has open is represented by an
+** instance of the following structure.
*/
-typedef struct VdbeCursor VdbeCursor;
struct VdbeCursor {
- u8 eCurType; /* One of the CURTYPE_* values above */
- i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
- u8 nullRow; /* True if pointing to a row with no data */
- u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
- u8 isTable; /* True for rowid tables. False for indexes */
+ BtCursor *pCursor; /* The cursor structure of the backend */
+ Btree *pBt; /* Separate file holding temporary table */
+ KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
+ int seekResult; /* Result of previous sqlite3BtreeMoveto() */
+ int pseudoTableReg; /* Register holding pseudotable content. */
+ i16 nField; /* Number of fields in the header */
+ u16 nHdrParsed; /* Number of header fields parsed so far */
#ifdef SQLITE_DEBUG
u8 seekOp; /* Most recent seek operation on this cursor */
- u8 wrFlag; /* The wrFlag argument to sqlite3BtreeCursor() */
#endif
+ i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
+ u8 nullRow; /* True if pointing to a row with no data */
+ u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
Bool isEphemeral:1; /* True for an ephemeral table */
Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
- Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */
+ Bool isTable:1; /* True if a table requiring integer keys */
+ Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */
Pgno pgnoRoot; /* Root page of the open btree cursor */
- i16 nField; /* Number of fields in the header */
- u16 nHdrParsed; /* Number of header fields parsed so far */
- union {
- BtCursor *pCursor; /* CURTYPE_BTREE. Btree cursor */
- sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB. Vtab cursor */
- int pseudoTableReg; /* CURTYPE_PSEUDO. Reg holding content. */
- VdbeSorter *pSorter; /* CURTYPE_SORTER. Sorter object */
- } uc;
- Btree *pBt; /* Separate file holding temporary table */
- KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
- int seekResult; /* Result of previous sqlite3BtreeMoveto() */
+ sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
i64 seqCount; /* Sequence counter */
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
- VdbeCursor *pAltCursor; /* Associated index cursor from which to read */
- int *aAltMap; /* Mapping from table to index column numbers */
-#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
- u64 maskUsed; /* Mask of columns used by this cursor */
-#endif
+ VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */
/* Cached information about the header for the data record that the
** cursor is currently pointing to. Only valid if cacheStatus matches
@@ -17531,6 +14605,7 @@ struct VdbeCursor {
** static element declared in the structure. nField total array slots for
** aType[] and nField+1 array slots for aOffset[] */
};
+typedef struct VdbeCursor VdbeCursor;
/*
** When a sub-program is executed (OP_Program), a structure of this type
@@ -17564,7 +14639,6 @@ struct VdbeFrame {
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
void *token; /* Copy of SubProgram.token */
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
- AuxData *pAuxData; /* Linked list of auxdata allocations */
int nCursor; /* Number of entries in apCsr */
int pc; /* Program Counter in parent (calling) frame */
int nOp; /* Size of aOp array */
@@ -17599,7 +14673,6 @@ struct Mem {
} u;
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
- u8 eSubtype; /* Subtype for this value */
int n; /* Number of characters in string value, excluding '\0' */
char *z; /* String or BLOB value */
/* ShallowCopy only needs to copy the information above */
@@ -17614,12 +14687,6 @@ struct Mem {
#endif
};
-/*
-** Size of struct Mem not including the Mem.zMalloc member or anything that
-** follows.
-*/
-#define MEMCELLSIZE offsetof(Mem,zMalloc)
-
/* One or more of the following flags are set to indicate the validOK
** representations of the value stored in the Mem struct.
**
@@ -17642,7 +14709,7 @@ struct Mem {
#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
#define MEM_Undefined 0x0080 /* Value is undefined */
#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */
-#define MEM_TypeMask 0x81ff /* Mask of type bits */
+#define MEM_TypeMask 0x01ff /* Mask of type bits */
/* Whenever Mem contains a valid string or blob representation, one of
@@ -17656,18 +14723,11 @@ 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 */
-#define MEM_Subtype 0x8000 /* Mem.eSubtype is valid */
#ifdef SQLITE_OMIT_INCRBLOB
#undef MEM_Zero
#define MEM_Zero 0x0000
#endif
-/* Return TRUE if Mem X contains dynamically allocated content - anything
-** that needs to be deallocated to avoid a leak.
-*/
-#define VdbeMemDynamic(X) \
- (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0)
-
/*
** Clear any existing type flags from a Mem and replace them with f
*/
@@ -17711,16 +14771,14 @@ struct AuxData {
** (Mem) which are only defined there.
*/
struct sqlite3_context {
- Mem *pOut; /* The return value is stored here */
- FuncDef *pFunc; /* Pointer to function information */
- Mem *pMem; /* Memory cell used to store aggregate context */
- Vdbe *pVdbe; /* The VM that owns this context */
- int iOp; /* Instruction number of OP_Function */
- int isError; /* Error code returned by the function. */
- u8 skipFlag; /* Skip accumulator loading if true */
- u8 fErrorOrAux; /* isError!=0 or pVdbe->pAuxData modified */
- u8 argc; /* Number of arguments */
- sqlite3_value *argv[1]; /* Argument set */
+ Mem *pOut; /* The return value is stored here */
+ FuncDef *pFunc; /* Pointer to function information */
+ Mem *pMem; /* Memory cell used to store aggregate context */
+ Vdbe *pVdbe; /* The VM that owns this context */
+ int iOp; /* Instruction number of OP_Function */
+ int isError; /* Error code returned by the function. */
+ u8 skipFlag; /* Skip accumulator loading if true */
+ u8 fErrorOrAux; /* isError!=0 or pVdbe->pAuxData modified */
};
/*
@@ -17784,16 +14842,16 @@ struct Vdbe {
#endif
u16 nResColumn; /* Number of columns in one row of the result set */
u8 errorAction; /* Recovery action to do in case of an error */
- bft expired:1; /* True if the VM needs to be recompiled */
- bft doingRerun:1; /* True if rerunning after an auto-reprepare */
u8 minWriteFileFormat; /* Minimum file format for writable database files */
bft explain:2; /* True if EXPLAIN present on SQL command */
bft changeCntOn:1; /* True to update the change-counter */
+ bft expired:1; /* True if the VM needs to be recompiled */
bft runOnlyOnce:1; /* Automatically expire on reset */
bft usesStmtJournal:1; /* True if uses a statement journal */
bft readOnly:1; /* True for statements that do not write */
bft bIsReader:1; /* True for statements that read */
bft isPrepareV2:1; /* True if prepared with prepare_v2() */
+ bft doingRerun:1; /* True if rerunning after an auto-reprepare */
int nChange; /* Number of db changes made since last reset */
yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
yDbMask lockMask; /* Subset of btreeMask that requires a lock */
@@ -17832,41 +14890,20 @@ struct Vdbe {
#define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */
/*
-** Structure used to store the context required by the
-** sqlite3_preupdate_*() API functions.
-*/
-struct PreUpdate {
- Vdbe *v;
- VdbeCursor *pCsr; /* Cursor to read old values from */
- int op; /* One of SQLITE_INSERT, UPDATE, DELETE */
- u8 *aRecord; /* old.* database record */
- KeyInfo keyinfo;
- UnpackedRecord *pUnpacked; /* Unpacked version of aRecord[] */
- UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */
- int iNewReg; /* Register for new.* values */
- i64 iKey1; /* First key value passed to hook */
- i64 iKey2; /* Second key value passed to hook */
- int iPKey; /* If not negative index of IPK column */
- Mem *aNew; /* Array of new.* values */
-};
-
-/*
** Function prototypes
*/
-SQLITE_PRIVATE void sqlite3VdbeError(Vdbe*, const char *, ...);
SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
void sqliteVdbePopStack(Vdbe*,int);
-SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor**, int*);
+SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor*);
SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*);
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, Op*);
#endif
SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32);
-SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8);
-SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int, u32*);
+SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int);
SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
-SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3*, AuxData**, int, int);
+SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe*, int, int);
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*);
@@ -17902,6 +14939,8 @@ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*);
SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem*,u8,u8);
SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*);
SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p);
+#define VdbeMemDynamic(X) \
+ (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0)
SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
SQLITE_PRIVATE const char *sqlite3OpcodeName(int);
SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
@@ -17909,9 +14948,6 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int n);
SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int);
SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*);
SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
-SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int);
-#endif
SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p);
SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *);
@@ -17923,15 +14959,11 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
-#if !defined(SQLITE_OMIT_SHARED_CACHE)
-SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe*);
-#else
-# define sqlite3VdbeEnter(X)
-#endif
-
#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
+SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe*);
#else
+# define sqlite3VdbeEnter(X)
# define sqlite3VdbeLeave(X)
#endif
@@ -17969,15 +15001,15 @@ SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *);
/*
** Variables in which to record status information.
*/
+typedef struct sqlite3StatType sqlite3StatType;
+static SQLITE_WSD struct sqlite3StatType {
#if SQLITE_PTRSIZE>4
-typedef sqlite3_int64 sqlite3StatValueType;
+ sqlite3_int64 nowValue[10]; /* Current value */
+ sqlite3_int64 mxValue[10]; /* Maximum value */
#else
-typedef u32 sqlite3StatValueType;
+ u32 nowValue[10]; /* Current value */
+ u32 mxValue[10]; /* Maximum value */
#endif
-typedef struct sqlite3StatType sqlite3StatType;
-static SQLITE_WSD struct sqlite3StatType {
- sqlite3StatValueType nowValue[10]; /* Current value */
- sqlite3StatValueType mxValue[10]; /* Maximum value */
} sqlite3Stat = { {0,}, {0,} };
/*
@@ -18058,24 +15090,18 @@ SQLITE_PRIVATE void sqlite3StatusDown(int op, int N){
}
/*
-** Adjust the highwater mark if necessary.
-** The caller must hold the appropriate mutex.
+** Set the value of a status to X. The highwater mark is adjusted if
+** necessary. The caller must hold the appropriate mutex.
*/
-SQLITE_PRIVATE void sqlite3StatusHighwater(int op, int X){
- sqlite3StatValueType newValue;
+SQLITE_PRIVATE void sqlite3StatusSet(int op, int X){
wsdStatInit;
- assert( X>=0 );
- newValue = (sqlite3StatValueType)X;
assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
assert( op>=0 && op<ArraySize(statMutex) );
assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
: sqlite3MallocMutex()) );
- assert( op==SQLITE_STATUS_MALLOC_SIZE
- || op==SQLITE_STATUS_PAGECACHE_SIZE
- || op==SQLITE_STATUS_SCRATCH_SIZE
- || op==SQLITE_STATUS_PARSER_STACK );
- if( newValue>wsdStat.mxValue[op] ){
- wsdStat.mxValue[op] = newValue;
+ wsdStat.nowValue[op] = X;
+ if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
+ wsdStat.mxValue[op] = wsdStat.nowValue[op];
}
}
@@ -18208,10 +15234,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
+ pSchema->idxHash.count
+ pSchema->fkeyHash.count
);
- nByte += sqlite3_msize(pSchema->tblHash.ht);
- nByte += sqlite3_msize(pSchema->trigHash.ht);
- nByte += sqlite3_msize(pSchema->idxHash.ht);
- nByte += sqlite3_msize(pSchema->fkeyHash.ht);
+ nByte += sqlite3MallocSize(pSchema->tblHash.ht);
+ nByte += sqlite3MallocSize(pSchema->trigHash.ht);
+ nByte += sqlite3MallocSize(pSchema->idxHash.ht);
+ nByte += sqlite3MallocSize(pSchema->fkeyHash.ht);
for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
@@ -18342,22 +15368,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
** Willmann-Bell, Inc
** Richmond, Virginia (USA)
*/
-/* #include "sqliteInt.h" */
/* #include <stdlib.h> */
/* #include <assert.h> */
#include <time.h>
#ifndef SQLITE_OMIT_DATETIME_FUNCS
-/*
-** The MSVC CRT on Windows CE may not have a localtime() function.
-** So declare a substitute. The substitute function itself is
-** defined in "os_win.c".
-*/
-#if !defined(SQLITE_OMIT_LOCALTIME) && defined(_WIN32_WCE) && \
- (!defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API)
-struct tm *__cdecl localtime(const time_t *);
-#endif
/*
** A structure for holding a single date and time.
@@ -18373,54 +15389,38 @@ struct DateTime {
char validHMS; /* True (1) if h,m,s are valid */
char validJD; /* True (1) if iJD is valid */
char validTZ; /* True (1) if tz is valid */
- char tzSet; /* Timezone was set explicitly */
};
/*
-** Convert zDate into one or more integers according to the conversion
-** specifier zFormat.
-**
-** zFormat[] contains 4 characters for each integer converted, except for
-** the last integer which is specified by three characters. The meaning
-** of a four-character format specifiers ABCD is:
-**
-** A: number of digits to convert. Always "2" or "4".
-** B: minimum value. Always "0" or "1".
-** C: maximum value, decoded as:
-** a: 12
-** b: 14
-** c: 24
-** d: 31
-** e: 59
-** f: 9999
-** D: the separator character, or \000 to indicate this is the
-** last number to convert.
+** Convert zDate into one or more integers. Additional arguments
+** come in groups of 5 as follows:
**
-** Example: To translate an ISO-8601 date YYYY-MM-DD, the format would
-** be "40f-21a-20c". The "40f-" indicates the 4-digit year followed by "-".
-** The "21a-" indicates the 2-digit month followed by "-". The "20c" indicates
-** the 2-digit day which is the last integer in the set.
+** N number of digits in the integer
+** min minimum allowed value of the integer
+** max maximum allowed value of the integer
+** nextC first character after the integer
+** pVal where to write the integers value.
**
+** Conversions continue until one with nextC==0 is encountered.
** The function returns the number of successful conversions.
*/
-static int getDigits(const char *zDate, const char *zFormat, ...){
- /* The aMx[] array translates the 3rd character of each format
- ** spec into a max size: a b c d e f */
- static const u16 aMx[] = { 12, 14, 24, 31, 59, 9999 };
+static int getDigits(const char *zDate, ...){
va_list ap;
+ int val;
+ int N;
+ int min;
+ int max;
+ int nextC;
+ int *pVal;
int cnt = 0;
- char nextC;
- va_start(ap, zFormat);
+ va_start(ap, zDate);
do{
- char N = zFormat[0] - '0';
- char min = zFormat[1] - '0';
- int val = 0;
- u16 max;
-
- assert( zFormat[2]>='a' && zFormat[2]<='f' );
- max = aMx[zFormat[2] - 'a'];
- nextC = zFormat[3];
+ N = va_arg(ap, int);
+ min = va_arg(ap, int);
+ max = va_arg(ap, int);
+ nextC = va_arg(ap, int);
+ pVal = va_arg(ap, int*);
val = 0;
while( N-- ){
if( !sqlite3Isdigit(*zDate) ){
@@ -18429,13 +15429,12 @@ static int getDigits(const char *zDate, const char *zFormat, ...){
val = val*10 + *zDate - '0';
zDate++;
}
- if( val<(int)min || val>(int)max || (nextC!=0 && nextC!=*zDate) ){
+ if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){
goto end_getDigits;
}
- *va_arg(ap,int*) = val;
+ *pVal = val;
zDate++;
cnt++;
- zFormat += 4;
}while( nextC );
end_getDigits:
va_end(ap);
@@ -18476,14 +15475,13 @@ static int parseTimezone(const char *zDate, DateTime *p){
return c!=0;
}
zDate++;
- if( getDigits(zDate, "20b:20e", &nHr, &nMn)!=2 ){
+ if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){
return 1;
}
zDate += 5;
p->tz = sgn*(nMn + nHr*60);
zulu_time:
while( sqlite3Isspace(*zDate) ){ zDate++; }
- p->tzSet = 1;
return *zDate!=0;
}
@@ -18497,13 +15495,13 @@ zulu_time:
static int parseHhMmSs(const char *zDate, DateTime *p){
int h, m, s;
double ms = 0.0;
- if( getDigits(zDate, "20c:20e", &h, &m)!=2 ){
+ if( getDigits(zDate, 2, 0, 24, ':', &h, 2, 0, 59, 0, &m)!=2 ){
return 1;
}
zDate += 5;
if( *zDate==':' ){
zDate++;
- if( getDigits(zDate, "20e", &s)!=1 ){
+ if( getDigits(zDate, 2, 0, 59, 0, &s)!=1 ){
return 1;
}
zDate += 2;
@@ -18591,7 +15589,7 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){
}else{
neg = 0;
}
- if( getDigits(zDate, "40f-21a-21d", &Y, &M, &D)!=3 ){
+ if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){
return 1;
}
zDate += 10;
@@ -18681,7 +15679,7 @@ static void computeYMD(DateTime *p){
A = Z + 1 + A - (A/4);
B = A + 1524;
C = (int)((B - 122.1)/365.25);
- D = (36525*(C&32767))/100;
+ D = (36525*C)/100;
E = (int)((B-D)/30.6001);
X1 = (int)(30.6001*E);
p->D = B - D - X1;
@@ -18726,7 +15724,6 @@ static void clearYMD_HMS_TZ(DateTime *p){
p->validTZ = 0;
}
-#ifndef SQLITE_OMIT_LOCALTIME
/*
** On recent Windows platforms, the localtime_s() function is available
** as part of the "Secure CRT". It is essentially equivalent to
@@ -18745,6 +15742,7 @@ static void clearYMD_HMS_TZ(DateTime *p){
#define HAVE_LOCALTIME_S 1
#endif
+#ifndef SQLITE_OMIT_LOCALTIME
/*
** The following routine implements the rough equivalent of localtime_r()
** using whatever operating-system specific localtime facility that
@@ -18916,18 +15914,13 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
}
#ifndef SQLITE_OMIT_LOCALTIME
else if( strcmp(z, "utc")==0 ){
- if( p->tzSet==0 ){
- sqlite3_int64 c1;
- computeJD(p);
- c1 = localtimeOffset(p, pCtx, &rc);
- if( rc==SQLITE_OK ){
- p->iJD -= c1;
- clearYMD_HMS_TZ(p);
- p->iJD += c1 - localtimeOffset(p, pCtx, &rc);
- }
- p->tzSet = 1;
- }else{
- rc = SQLITE_OK;
+ sqlite3_int64 c1;
+ computeJD(p);
+ c1 = localtimeOffset(p, pCtx, &rc);
+ if( rc==SQLITE_OK ){
+ p->iJD -= c1;
+ clearYMD_HMS_TZ(p);
+ p->iJD += c1 - localtimeOffset(p, pCtx, &rc);
}
}
#endif
@@ -19275,7 +16268,7 @@ static void strftimeFunc(
sqlite3_result_error_toobig(context);
return;
}else{
- z = sqlite3DbMallocRawNN(db, (int)n);
+ z = sqlite3DbMallocRaw(db, (int)n);
if( z==0 ){
sqlite3_result_error_nomem(context);
return;
@@ -19444,23 +16437,29 @@ static void currentTimeFunc(
** external linkage.
*/
SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
- static FuncDef aDateTimeFuncs[] = {
+ static SQLITE_WSD FuncDef aDateTimeFuncs[] = {
#ifndef SQLITE_OMIT_DATETIME_FUNCS
- DFUNCTION(julianday, -1, 0, 0, juliandayFunc ),
- DFUNCTION(date, -1, 0, 0, dateFunc ),
- DFUNCTION(time, -1, 0, 0, timeFunc ),
- DFUNCTION(datetime, -1, 0, 0, datetimeFunc ),
- DFUNCTION(strftime, -1, 0, 0, strftimeFunc ),
- DFUNCTION(current_time, 0, 0, 0, ctimeFunc ),
- DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
- DFUNCTION(current_date, 0, 0, 0, cdateFunc ),
+ FUNCTION(julianday, -1, 0, 0, juliandayFunc ),
+ FUNCTION(date, -1, 0, 0, dateFunc ),
+ FUNCTION(time, -1, 0, 0, timeFunc ),
+ FUNCTION(datetime, -1, 0, 0, datetimeFunc ),
+ FUNCTION(strftime, -1, 0, 0, strftimeFunc ),
+ FUNCTION(current_time, 0, 0, 0, ctimeFunc ),
+ FUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
+ FUNCTION(current_date, 0, 0, 0, cdateFunc ),
#else
STR_FUNCTION(current_time, 0, "%H:%M:%S", 0, currentTimeFunc),
STR_FUNCTION(current_date, 0, "%Y-%m-%d", 0, currentTimeFunc),
STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc),
#endif
};
- sqlite3InsertBuiltinFuncs(aDateTimeFuncs, ArraySize(aDateTimeFuncs));
+ int i;
+ FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
+ FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aDateTimeFuncs);
+
+ for(i=0; i<ArraySize(aDateTimeFuncs); i++){
+ sqlite3FuncDefInsert(pHash, &aFunc[i]);
+ }
}
/************** End of date.c ************************************************/
@@ -19481,39 +16480,16 @@ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
** architectures.
*/
#define _SQLITE_OS_C_ 1
-/* #include "sqliteInt.h" */
#undef _SQLITE_OS_C_
/*
-** If we compile with the SQLITE_TEST macro set, then the following block
-** of code will give us the ability to simulate a disk I/O error. This
-** is used for testing the I/O recovery logic.
-*/
-#if defined(SQLITE_TEST)
-SQLITE_API int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */
-SQLITE_API int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */
-SQLITE_API int sqlite3_io_error_pending = 0; /* Count down to first I/O error */
-SQLITE_API int sqlite3_io_error_persist = 0; /* True if I/O errors persist */
-SQLITE_API int sqlite3_io_error_benign = 0; /* True if errors are benign */
-SQLITE_API int sqlite3_diskfull_pending = 0;
-SQLITE_API int sqlite3_diskfull = 0;
-#endif /* defined(SQLITE_TEST) */
-
-/*
-** When testing, also keep a count of the number of open files.
-*/
-#if defined(SQLITE_TEST)
-SQLITE_API int sqlite3_open_file_count = 0;
-#endif /* defined(SQLITE_TEST) */
-
-/*
** The default SQLite sqlite3_vfs implementations do not allocate
** memory (actually, os_unix.c allocates a small amount of memory
** from within OsOpen()), but some third-party implementations may.
** So we test the effects of a malloc() failing and the sqlite3OsXXX()
** function returning SQLITE_IOERR_NOMEM using the DO_OS_MALLOC_TEST macro.
**
-** The following functions are instrumented for malloc() failure
+** The following functions are instrumented for malloc() failure
** testing:
**
** sqlite3OsRead()
@@ -19533,9 +16509,9 @@ SQLITE_API int sqlite3_open_file_count = 0;
#if defined(SQLITE_TEST)
SQLITE_API int sqlite3_memdebug_vfs_oom_test = 1;
#define DO_OS_MALLOC_TEST(x) \
- if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3JournalIsInMemory(x))) { \
+ if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3IsMemJournal(x))) { \
void *pTstAlloc = sqlite3Malloc(10); \
- if (!pTstAlloc) return SQLITE_IOERR_NOMEM_BKPT; \
+ if (!pTstAlloc) return SQLITE_IOERR_NOMEM; \
sqlite3_free(pTstAlloc); \
}
#else
@@ -19548,11 +16524,13 @@ SQLITE_API int sqlite3_memdebug_vfs_oom_test = 1;
** of this would be completely automatic if SQLite were coded using
** C++ instead of plain old C.
*/
-SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file *pId){
+SQLITE_PRIVATE int sqlite3OsClose(sqlite3_file *pId){
+ int rc = SQLITE_OK;
if( pId->pMethods ){
- pId->pMethods->xClose(pId);
+ rc = pId->pMethods->xClose(pId);
pId->pMethods = 0;
}
+ return rc;
}
SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){
DO_OS_MALLOC_TEST(id);
@@ -19597,8 +16575,8 @@ SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
#ifdef SQLITE_TEST
if( op!=SQLITE_FCNTL_COMMIT_PHASETWO ){
/* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
- ** is using a regular VFS, it is called after the corresponding
- ** transaction has been committed. Injecting a fault at this point
+ ** is using a regular VFS, it is called after the corresponding
+ ** transaction has been committed. Injecting a fault at this point
** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM
** but the transaction is committed anyway.
**
@@ -19667,10 +16645,10 @@ SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){
** VFS methods.
*/
SQLITE_PRIVATE int sqlite3OsOpen(
- sqlite3_vfs *pVfs,
- const char *zPath,
- sqlite3_file *pFile,
- int flags,
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ sqlite3_file *pFile,
+ int flags,
int *pFlagsOut
){
int rc;
@@ -19689,18 +16667,18 @@ SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dir
return pVfs->xDelete(pVfs, zPath, dirSync);
}
SQLITE_PRIVATE int sqlite3OsAccess(
- sqlite3_vfs *pVfs,
- const char *zPath,
- int flags,
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int flags,
int *pResOut
){
DO_OS_MALLOC_TEST(0);
return pVfs->xAccess(pVfs, zPath, flags, pResOut);
}
SQLITE_PRIVATE int sqlite3OsFullPathname(
- sqlite3_vfs *pVfs,
- const char *zPath,
- int nPathOut,
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int nPathOut,
char *zPathOut
){
DO_OS_MALLOC_TEST(0);
@@ -19727,9 +16705,6 @@ SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufO
SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
return pVfs->xSleep(pVfs, nMicro);
}
-SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs *pVfs){
- return pVfs->xGetLastError ? pVfs->xGetLastError(pVfs, 0, 0) : 0;
-}
SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
int rc;
/* IMPLEMENTATION-OF: R-49045-42493 SQLite will use the xCurrentTimeInt64()
@@ -19749,13 +16724,13 @@ SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p
}
SQLITE_PRIVATE int sqlite3OsOpenMalloc(
- sqlite3_vfs *pVfs,
- const char *zFile,
- sqlite3_file **ppFile,
+ sqlite3_vfs *pVfs,
+ const char *zFile,
+ sqlite3_file **ppFile,
int flags,
int *pOutFlags
){
- int rc;
+ int rc = SQLITE_NOMEM;
sqlite3_file *pFile;
pFile = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile);
if( pFile ){
@@ -19765,15 +16740,15 @@ SQLITE_PRIVATE int sqlite3OsOpenMalloc(
}else{
*ppFile = pFile;
}
- }else{
- rc = SQLITE_NOMEM_BKPT;
}
return rc;
}
-SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *pFile){
+SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *pFile){
+ int rc = SQLITE_OK;
assert( pFile );
- sqlite3OsClose(pFile);
+ rc = sqlite3OsClose(pFile);
sqlite3_free(pFile);
+ return rc;
}
/*
@@ -19784,7 +16759,7 @@ SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *pFile){
*/
SQLITE_PRIVATE int sqlite3OsInit(void){
void *p = sqlite3_malloc(10);
- if( p==0 ) return SQLITE_NOMEM_BKPT;
+ if( p==0 ) return SQLITE_NOMEM;
sqlite3_free(p);
return sqlite3_os_init();
}
@@ -19911,7 +16886,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
** during a hash table resize is a benign fault.
*/
-/* #include "sqliteInt.h" */
#ifndef SQLITE_OMIT_BUILTIN_TEST
@@ -19993,7 +16967,6 @@ SQLITE_PRIVATE void sqlite3EndBenignMalloc(void){
** are merely placeholders. Real drivers must be substituted using
** sqlite3_config() before SQLite will operate.
*/
-/* #include "sqliteInt.h" */
/*
** This version of the memory allocator is the default. It is
@@ -20080,7 +17053,6 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){
** be necessary when compiling for Delphi,
** for example.
*/
-/* #include "sqliteInt.h" */
/*
** This version of the memory allocator is the default. It is
@@ -20211,11 +17183,10 @@ static void sqlite3MemFree(void *pPrior){
*/
static int sqlite3MemSize(void *pPrior){
#ifdef SQLITE_MALLOCSIZE
- assert( pPrior!=0 );
- return (int)SQLITE_MALLOCSIZE(pPrior);
+ return pPrior ? (int)SQLITE_MALLOCSIZE(pPrior) : 0;
#else
sqlite3_int64 *p;
- assert( pPrior!=0 );
+ if( pPrior==0 ) return 0;
p = (sqlite3_int64*)pPrior;
p--;
return (int)p[0];
@@ -20357,7 +17328,6 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){
** This file contains implementations of the low-level memory allocation
** routines specified in the sqlite3_mem_methods object.
*/
-/* #include "sqliteInt.h" */
/*
** This version of the memory allocator is used only if the
@@ -20892,7 +17862,6 @@ SQLITE_PRIVATE int sqlite3MemdebugMallocCount(){
** This version of the memory allocation subsystem is included
** in the build only if SQLITE_ENABLE_MEMSYS3 is defined.
*/
-/* #include "sqliteInt.h" */
/*
** This version of the memory allocator is only built into the library
@@ -21345,7 +18314,7 @@ static void memsys3FreeUnsafe(void *pOld){
*/
static int memsys3Size(void *p){
Mem3Block *pBlock;
- assert( p!=0 );
+ if( p==0 ) return 0;
pBlock = (Mem3Block*)p;
assert( (pBlock[-1].u.hdr.size4x&1)!=0 );
return (pBlock[-1].u.hdr.size4x&~3)*2 - 4;
@@ -21584,7 +18553,7 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){
**
** This memory allocator uses the following algorithm:
**
-** 1. All memory allocation sizes are rounded up to a power of 2.
+** 1. All memory allocations sizes are rounded up to a power of 2.
**
** 2. If two adjacent free blocks are the halves of a larger block,
** then the two blocks are coalesced into the single larger block.
@@ -21607,7 +18576,6 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){
** The sqlite3_status() logic tracks the maximum values of n and M so
** that an application can, at any time, verify this constraint.
*/
-/* #include "sqliteInt.h" */
/*
** This version of the memory allocator is used only when
@@ -21661,7 +18629,6 @@ static SQLITE_WSD struct Mem5Global {
*/
sqlite3_mutex *mutex;
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
/*
** Performance statistics
*/
@@ -21673,12 +18640,11 @@ static SQLITE_WSD struct Mem5Global {
u32 maxOut; /* Maximum instantaneous currentOut */
u32 maxCount; /* Maximum instantaneous currentCount */
u32 maxRequest; /* Largest allocation (exclusive of internal frag) */
-#endif
/*
** Lists of free blocks. aiFreelist[0] is a list of free blocks of
** size mem5.szAtom. aiFreelist[1] holds blocks of size szAtom*2.
- ** aiFreelist[2] holds free blocks of size szAtom*4. And so forth.
+ ** and so forth.
*/
int aiFreelist[LOGMAX+1];
@@ -21744,7 +18710,9 @@ static void memsys5Link(int i, int iLogsize){
}
/*
-** Obtain or release the mutex needed to access global data structures.
+** If the STATIC_MEM mutex is not already held, obtain it now. The mutex
+** will already be held (obtained by code in malloc.c) if
+** sqlite3GlobalConfig.bMemStat is true.
*/
static void memsys5Enter(void){
sqlite3_mutex_enter(mem5.mutex);
@@ -21754,15 +18722,17 @@ static void memsys5Leave(void){
}
/*
-** Return the size of an outstanding allocation, in bytes.
-** This only works for chunks that are currently checked out.
+** Return the size of an outstanding allocation, in bytes. The
+** size returned omits the 8-byte header overhead. This only
+** works for chunks that are currently checked out.
*/
static int memsys5Size(void *p){
- int iSize, i;
- assert( p!=0 );
- i = (int)(((u8 *)p-mem5.zPool)/mem5.szAtom);
- assert( i>=0 && i<mem5.nBlock );
- iSize = mem5.szAtom * (1 << (mem5.aCtrl[i]&CTRL_LOGSIZE));
+ int iSize = 0;
+ if( p ){
+ int i = (int)(((u8 *)p-mem5.zPool)/mem5.szAtom);
+ assert( i>=0 && i<mem5.nBlock );
+ iSize = mem5.szAtom * (1 << (mem5.aCtrl[i]&CTRL_LOGSIZE));
+ }
return iSize;
}
@@ -21785,20 +18755,21 @@ static void *memsys5MallocUnsafe(int nByte){
/* nByte must be a positive */
assert( nByte>0 );
- /* No more than 1GiB per allocation */
- if( nByte > 0x40000000 ) return 0;
-
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
/* Keep track of the maximum allocation request. Even unfulfilled
** requests are counted */
if( (u32)nByte>mem5.maxRequest ){
mem5.maxRequest = nByte;
}
-#endif
+ /* Abort if the requested allocation size is larger than the largest
+ ** power of two that we can represent using 32-bit signed integers.
+ */
+ if( nByte > 0x40000000 ){
+ return 0;
+ }
/* Round nByte up to the next valid power of two */
- for(iFullSz=mem5.szAtom,iLogsize=0; iFullSz<nByte; iFullSz*=2,iLogsize++){}
+ for(iFullSz=mem5.szAtom, iLogsize=0; iFullSz<nByte; iFullSz *= 2, iLogsize++){}
/* Make sure mem5.aiFreelist[iLogsize] contains at least one free
** block. If not, then split a block of the next larger power of
@@ -21822,7 +18793,6 @@ static void *memsys5MallocUnsafe(int nByte){
}
mem5.aCtrl[i] = iLogsize;
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
/* Update allocator performance statistics. */
mem5.nAlloc++;
mem5.totalAlloc += iFullSz;
@@ -21831,7 +18801,6 @@ static void *memsys5MallocUnsafe(int nByte){
mem5.currentOut += iFullSz;
if( mem5.maxCount<mem5.currentCount ) mem5.maxCount = mem5.currentCount;
if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut;
-#endif
#ifdef SQLITE_DEBUG
/* Make sure the allocated memory does not assume that it is set to zero
@@ -21866,26 +18835,23 @@ static void memsys5FreeUnsafe(void *pOld){
mem5.aCtrl[iBlock] |= CTRL_FREE;
mem5.aCtrl[iBlock+size-1] |= CTRL_FREE;
-
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
assert( mem5.currentCount>0 );
assert( mem5.currentOut>=(size*mem5.szAtom) );
mem5.currentCount--;
mem5.currentOut -= size*mem5.szAtom;
assert( mem5.currentOut>0 || mem5.currentCount==0 );
assert( mem5.currentCount>0 || mem5.currentOut==0 );
-#endif
mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize;
while( ALWAYS(iLogsize<LOGMAX) ){
int iBuddy;
if( (iBlock>>iLogsize) & 1 ){
iBuddy = iBlock - size;
- assert( iBuddy>=0 );
}else{
iBuddy = iBlock + size;
- if( iBuddy>=mem5.nBlock ) break;
}
+ assert( iBuddy>=0 );
+ if( (iBuddy+(1<<iLogsize))>mem5.nBlock ) break;
if( mem5.aCtrl[iBuddy]!=(CTRL_FREE | iLogsize) ) break;
memsys5Unlink(iBuddy, iLogsize);
iLogsize++;
@@ -21960,11 +18926,13 @@ static void *memsys5Realloc(void *pPrior, int nBytes){
if( nBytes<=nOld ){
return pPrior;
}
- p = memsys5Malloc(nBytes);
+ memsys5Enter();
+ p = memsys5MallocUnsafe(nBytes);
if( p ){
memcpy(p, pPrior, nOld);
- memsys5Free(pPrior);
+ memsys5FreeUnsafe(pPrior);
}
+ memsys5Leave();
return p;
}
@@ -22151,7 +19119,6 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void){
**
** This file contains code that is common across all mutex implementations.
*/
-/* #include "sqliteInt.h" */
#if defined(SQLITE_DEBUG) && !defined(SQLITE_MUTEX_OMIT)
/*
@@ -22160,7 +19127,7 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void){
** allocate a mutex while the system is uninitialized.
*/
static SQLITE_WSD int mutexIsInit = 0;
-#endif /* SQLITE_DEBUG && !defined(SQLITE_MUTEX_OMIT) */
+#endif /* SQLITE_DEBUG */
#ifndef SQLITE_MUTEX_OMIT
@@ -22183,18 +19150,11 @@ SQLITE_PRIVATE int sqlite3MutexInit(void){
}else{
pFrom = sqlite3NoopMutex();
}
- pTo->xMutexInit = pFrom->xMutexInit;
- pTo->xMutexEnd = pFrom->xMutexEnd;
- pTo->xMutexFree = pFrom->xMutexFree;
- pTo->xMutexEnter = pFrom->xMutexEnter;
- pTo->xMutexTry = pFrom->xMutexTry;
- pTo->xMutexLeave = pFrom->xMutexLeave;
- pTo->xMutexHeld = pFrom->xMutexHeld;
- pTo->xMutexNotheld = pFrom->xMutexNotheld;
- sqlite3MemoryBarrier();
+ memcpy(pTo, pFrom, offsetof(sqlite3_mutex_methods, xMutexAlloc));
+ memcpy(&pTo->xMutexFree, &pFrom->xMutexFree,
+ sizeof(*pTo) - offsetof(sqlite3_mutex_methods, xMutexFree));
pTo->xMutexAlloc = pFrom->xMutexAlloc;
}
- assert( sqlite3GlobalConfig.mutex.xMutexInit );
rc = sqlite3GlobalConfig.mutex.xMutexInit();
#ifdef SQLITE_DEBUG
@@ -22229,7 +19189,6 @@ SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int id){
if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0;
if( id>SQLITE_MUTEX_RECURSIVE && sqlite3MutexInit() ) return 0;
#endif
- assert( sqlite3GlobalConfig.mutex.xMutexAlloc );
return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
}
@@ -22238,7 +19197,6 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int id){
return 0;
}
assert( GLOBAL(int, mutexIsInit) );
- assert( sqlite3GlobalConfig.mutex.xMutexAlloc );
return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
}
@@ -22247,7 +19205,6 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int id){
*/
SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex *p){
if( p ){
- assert( sqlite3GlobalConfig.mutex.xMutexFree );
sqlite3GlobalConfig.mutex.xMutexFree(p);
}
}
@@ -22258,7 +19215,6 @@ SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex *p){
*/
SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex *p){
if( p ){
- assert( sqlite3GlobalConfig.mutex.xMutexEnter );
sqlite3GlobalConfig.mutex.xMutexEnter(p);
}
}
@@ -22270,7 +19226,6 @@ SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex *p){
SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex *p){
int rc = SQLITE_OK;
if( p ){
- assert( sqlite3GlobalConfig.mutex.xMutexTry );
return sqlite3GlobalConfig.mutex.xMutexTry(p);
}
return rc;
@@ -22284,7 +19239,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex *p){
*/
SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex *p){
if( p ){
- assert( sqlite3GlobalConfig.mutex.xMutexLeave );
sqlite3GlobalConfig.mutex.xMutexLeave(p);
}
}
@@ -22295,11 +19249,9 @@ SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex *p){
** intended for use inside assert() statements.
*/
SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex *p){
- assert( p==0 || sqlite3GlobalConfig.mutex.xMutexHeld );
return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p);
}
SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex *p){
- assert( p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld );
return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p);
}
#endif
@@ -22335,7 +19287,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex *p){
** that does error checking on mutexes to make sure they are being
** called correctly.
*/
-/* #include "sqliteInt.h" */
#ifndef SQLITE_MUTEX_OMIT
@@ -22417,7 +19368,7 @@ static int debugMutexEnd(void){ return SQLITE_OK; }
** that means that a mutex could not be allocated.
*/
static sqlite3_mutex *debugMutexAlloc(int id){
- static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_VFS3 - 1];
+ static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_APP3 - 1];
sqlite3_debug_mutex *pNew = 0;
switch( id ){
case SQLITE_MUTEX_FAST:
@@ -22539,7 +19490,6 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
*************************************************************************
** This file contains the C functions that implement mutexes for pthreads
*/
-/* #include "sqliteInt.h" */
/*
** The code in this file is only used if we are compiling threadsafe
@@ -22578,9 +19528,7 @@ struct sqlite3_mutex {
#endif
};
#if SQLITE_MUTEX_NREF
-#define SQLITE3_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER,0,0,(pthread_t)0,0}
-#elif defined(SQLITE_ENABLE_API_ARMOR)
-#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0 }
+#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, 0, (pthread_t)0, 0 }
#else
#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
#endif
@@ -22611,19 +19559,6 @@ static int pthreadMutexNotheld(sqlite3_mutex *p){
#endif
/*
-** Try to provide a memory barrier operation, needed for initialization
-** and also for the implementation of xShmBarrier in the VFS in cases
-** where SQLite is compiled without mutexes.
-*/
-SQLITE_PRIVATE void sqlite3MemoryBarrier(void){
-#if defined(SQLITE_MEMORY_BARRIER)
- SQLITE_MEMORY_BARRIER;
-#elif defined(__GNUC__) && GCC_VERSION>=4001000
- __sync_synchronize();
-#endif
-}
-
-/*
** Initialize and deinitialize the mutex subsystem.
*/
static int pthreadMutexInit(void){ return SQLITE_OK; }
@@ -22648,9 +19583,6 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
** <li> SQLITE_MUTEX_STATIC_APP1
** <li> SQLITE_MUTEX_STATIC_APP2
** <li> SQLITE_MUTEX_STATIC_APP3
-** <li> SQLITE_MUTEX_STATIC_VFS1
-** <li> SQLITE_MUTEX_STATIC_VFS2
-** <li> SQLITE_MUTEX_STATIC_VFS3
** </ul>
**
** The first two constants cause sqlite3_mutex_alloc() to create
@@ -22687,9 +19619,6 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER
};
sqlite3_mutex *p;
@@ -22929,7 +19858,6 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
*************************************************************************
** This file contains the C functions that implement mutexes for Win32.
*/
-/* #include "sqliteInt.h" */
#if SQLITE_OS_WIN
/*
@@ -22974,8 +19902,8 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
*/
#ifdef SQLITE_PERFORMANCE_TRACE
-/*
-** hwtime.h contains inline assembler code for implementing
+/*
+** hwtime.h contains inline assembler code for implementing
** high-performance timing routines.
*/
/************** Include hwtime.h in the middle of os_common.h ****************/
@@ -23085,14 +20013,14 @@ static sqlite_uint64 g_elapsed;
** of code will give us the ability to simulate a disk I/O error. This
** is used for testing the I/O recovery logic.
*/
-#if defined(SQLITE_TEST)
-SQLITE_API extern int sqlite3_io_error_hit;
-SQLITE_API extern int sqlite3_io_error_hardhit;
-SQLITE_API extern int sqlite3_io_error_pending;
-SQLITE_API extern int sqlite3_io_error_persist;
-SQLITE_API extern int sqlite3_io_error_benign;
-SQLITE_API extern int sqlite3_diskfull_pending;
-SQLITE_API extern int sqlite3_diskfull;
+#ifdef SQLITE_TEST
+SQLITE_API int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */
+SQLITE_API int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */
+SQLITE_API int sqlite3_io_error_pending = 0; /* Count down to first I/O error */
+SQLITE_API int sqlite3_io_error_persist = 0; /* True if I/O errors persist */
+SQLITE_API int sqlite3_io_error_benign = 0; /* True if errors are benign */
+SQLITE_API int sqlite3_diskfull_pending = 0;
+SQLITE_API int sqlite3_diskfull = 0;
#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
#define SimulateIOError(CODE) \
if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
@@ -23118,17 +20046,17 @@ static void local_ioerr(){
#define SimulateIOErrorBenign(X)
#define SimulateIOError(A)
#define SimulateDiskfullError(A)
-#endif /* defined(SQLITE_TEST) */
+#endif
/*
** When testing, keep a count of the number of open files.
*/
-#if defined(SQLITE_TEST)
-SQLITE_API extern int sqlite3_open_file_count;
+#ifdef SQLITE_TEST
+SQLITE_API int sqlite3_open_file_count = 0;
#define OpenCounter(X) sqlite3_open_file_count+=(X)
#else
#define OpenCounter(X)
-#endif /* defined(SQLITE_TEST) */
+#endif
#endif /* !defined(_OS_COMMON_H_) */
@@ -23286,24 +20214,6 @@ static int winMutexNotheld(sqlite3_mutex *p){
#endif
/*
-** Try to provide a memory barrier operation, needed for initialization
-** and also for the xShmBarrier method of the VFS in cases when SQLite is
-** compiled without mutexes (SQLITE_THREADSAFE=0).
-*/
-SQLITE_PRIVATE void sqlite3MemoryBarrier(void){
-#if defined(SQLITE_MEMORY_BARRIER)
- SQLITE_MEMORY_BARRIER;
-#elif defined(__GNUC__)
- __sync_synchronize();
-#elif !defined(SQLITE_DISABLE_INTRINSIC) && \
- defined(_MSC_VER) && _MSC_VER>=1300
- _ReadWriteBarrier();
-#elif defined(MemoryBarrier)
- MemoryBarrier();
-#endif
-}
-
-/*
** Initialize and deinitialize the mutex subsystem.
*/
static sqlite3_mutex winMutex_staticMutexes[] = {
@@ -23315,9 +20225,6 @@ static sqlite3_mutex winMutex_staticMutexes[] = {
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER
};
@@ -23389,9 +20296,6 @@ static int winMutexEnd(void){
** <li> SQLITE_MUTEX_STATIC_APP1
** <li> SQLITE_MUTEX_STATIC_APP2
** <li> SQLITE_MUTEX_STATIC_APP3
-** <li> SQLITE_MUTEX_STATIC_VFS1
-** <li> SQLITE_MUTEX_STATIC_VFS2
-** <li> SQLITE_MUTEX_STATIC_VFS3
** </ul>
**
** The first two constants cause sqlite3_mutex_alloc() to create
@@ -23623,7 +20527,6 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
**
** Memory allocation functions used throughout sqlite.
*/
-/* #include "sqliteInt.h" */
/* #include <stdarg.h> */
/*
@@ -23656,7 +20559,16 @@ typedef struct ScratchFreeslot {
*/
static SQLITE_WSD struct Mem0Global {
sqlite3_mutex *mutex; /* Mutex to serialize access */
- sqlite3_int64 alarmThreshold; /* The soft heap limit */
+
+ /*
+ ** The alarm callback and its arguments. The mem0.mutex lock will
+ ** be held while the callback is running. Recursive calls into
+ ** the memory subsystem are allowed, but no new callbacks will be
+ ** issued.
+ */
+ sqlite3_int64 alarmThreshold;
+ void (*alarmCallback)(void*, sqlite3_int64,int);
+ void *alarmArg;
/*
** Pointers to the end of sqlite3GlobalConfig.pScratch memory
@@ -23673,7 +20585,7 @@ static SQLITE_WSD struct Mem0Global {
** sqlite3_soft_heap_limit() setting.
*/
int nearlyFull;
-} mem0 = { 0, 0, 0, 0, 0, 0 };
+} mem0 = { 0, 0, 0, 0, 0, 0, 0, 0 };
#define mem0 GLOBAL(struct Mem0Global, mem0)
@@ -23684,21 +20596,50 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void){
return mem0.mutex;
}
+/*
+** This routine runs when the memory allocator sees that the
+** total memory allocation is about to exceed the soft heap
+** limit.
+*/
+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
+){
+ sqlite3_int64 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. It used to set an alarm callback
-** that was invoked when memory usage grew too large. Now it is a
-** no-op.
+** Deprecated external interface. Internal/core SQLite code
+** should call sqlite3MemoryAlarm.
*/
SQLITE_API int SQLITE_STDCALL sqlite3_memory_alarm(
void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
void *pArg,
sqlite3_int64 iThreshold
){
- (void)xCallback;
- (void)pArg;
- (void)iThreshold;
- return SQLITE_OK;
+ return sqlite3MemoryAlarm(xCallback, pArg, iThreshold);
}
#endif
@@ -23709,21 +20650,19 @@ SQLITE_API int SQLITE_STDCALL sqlite3_memory_alarm(
SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 n){
sqlite3_int64 priorLimit;
sqlite3_int64 excess;
- sqlite3_int64 nUsed;
#ifndef SQLITE_OMIT_AUTOINIT
int rc = sqlite3_initialize();
if( rc ) return -1;
#endif
sqlite3_mutex_enter(mem0.mutex);
priorLimit = mem0.alarmThreshold;
- if( n<0 ){
- sqlite3_mutex_leave(mem0.mutex);
- return priorLimit;
- }
- mem0.alarmThreshold = n;
- nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
- mem0.nearlyFull = (n>0 && n<=nUsed);
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;
@@ -23742,7 +20681,9 @@ SQLITE_PRIVATE int sqlite3MallocInit(void){
sqlite3MemSetDefault();
}
memset(&mem0, 0, sizeof(mem0));
- mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
+ if( sqlite3GlobalConfig.bCoreMutex ){
+ mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
+ }
if( sqlite3GlobalConfig.pScratch && sqlite3GlobalConfig.szScratch>=100
&& sqlite3GlobalConfig.nScratch>0 ){
int i, n, sz;
@@ -23766,9 +20707,10 @@ SQLITE_PRIVATE int sqlite3MallocInit(void){
sqlite3GlobalConfig.nScratch = 0;
}
if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512
- || sqlite3GlobalConfig.nPage<=0 ){
+ || sqlite3GlobalConfig.nPage<1 ){
sqlite3GlobalConfig.pPage = 0;
sqlite3GlobalConfig.szPage = 0;
+ sqlite3GlobalConfig.nPage = 0;
}
rc = sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData);
if( rc!=SQLITE_OK ) memset(&mem0, 0, sizeof(mem0));
@@ -23798,8 +20740,10 @@ SQLITE_PRIVATE void sqlite3MallocEnd(void){
** Return the amount of memory currently checked out.
*/
SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void){
- sqlite3_int64 res, mx;
- sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &res, &mx, 0);
+ int n, mx;
+ sqlite3_int64 res;
+ sqlite3_status(SQLITE_STATUS_MEMORY_USED, &n, &mx, 0);
+ res = (sqlite3_int64)n; /* Work around bug in Borland C. Ticket #3216 */
return res;
}
@@ -23809,19 +20753,30 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void){
** or since the most recent reset.
*/
SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag){
- sqlite3_int64 res, mx;
- sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &res, &mx, resetFlag);
- return mx;
+ int n, mx;
+ sqlite3_int64 res;
+ sqlite3_status(SQLITE_STATUS_MEMORY_USED, &n, &mx, resetFlag);
+ res = (sqlite3_int64)mx; /* Work around bug in Borland C. Ticket #3216 */
+ return res;
}
/*
** Trigger the alarm
*/
static void sqlite3MallocAlarm(int nByte){
- if( mem0.alarmThreshold<=0 ) return;
+ void (*xCallback)(void*,sqlite3_int64,int);
+ sqlite3_int64 nowUsed;
+ void *pArg;
+ if( mem0.alarmCallback==0 ) return;
+ xCallback = mem0.alarmCallback;
+ nowUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
+ pArg = mem0.alarmArg;
+ mem0.alarmCallback = 0;
sqlite3_mutex_leave(mem0.mutex);
- sqlite3_release_memory(nByte);
+ xCallback(pArg, nowUsed, nByte);
sqlite3_mutex_enter(mem0.mutex);
+ mem0.alarmCallback = xCallback;
+ mem0.alarmArg = pArg;
}
/*
@@ -23833,8 +20788,8 @@ static int mallocWithAlarm(int n, void **pp){
void *p;
assert( sqlite3_mutex_held(mem0.mutex) );
nFull = sqlite3GlobalConfig.m.xRoundup(n);
- sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, n);
- if( mem0.alarmThreshold>0 ){
+ sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n);
+ if( mem0.alarmCallback!=0 ){
sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
if( nUsed >= mem0.alarmThreshold - nFull ){
mem0.nearlyFull = 1;
@@ -23845,7 +20800,7 @@ static int mallocWithAlarm(int n, void **pp){
}
p = sqlite3GlobalConfig.m.xMalloc(nFull);
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
- if( p==0 && mem0.alarmThreshold>0 ){
+ if( p==0 && mem0.alarmCallback ){
sqlite3MallocAlarm(nFull);
p = sqlite3GlobalConfig.m.xMalloc(nFull);
}
@@ -23925,7 +20880,7 @@ SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){
assert( n>0 );
sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusHighwater(SQLITE_STATUS_SCRATCH_SIZE, n);
+ sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n);
if( mem0.nScratchFree && sqlite3GlobalConfig.szScratch>=n ){
p = mem0.pScratchFree;
mem0.pScratchFree = mem0.pScratchFree->pNext;
@@ -23969,7 +20924,7 @@ SQLITE_PRIVATE void sqlite3ScratchFree(void *p){
scratchAllocOut--;
#endif
- if( SQLITE_WITHIN(p, sqlite3GlobalConfig.pScratch, mem0.pScratchEnd) ){
+ if( p>=sqlite3GlobalConfig.pScratch && p<mem0.pScratchEnd ){
/* Release memory from the SQLITE_CONFIG_SCRATCH allocation */
ScratchFreeslot *pSlot;
pSlot = (ScratchFreeslot*)p;
@@ -24005,7 +20960,7 @@ SQLITE_PRIVATE void sqlite3ScratchFree(void *p){
*/
#ifndef SQLITE_OMIT_LOOKASIDE
static int isLookaside(sqlite3 *db, void *p){
- return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pEnd);
+ return p>=db->lookaside.pStart && p<db->lookaside.pEnd;
}
#else
#define isLookaside(A,B) 0
@@ -24020,27 +20975,25 @@ SQLITE_PRIVATE int sqlite3MallocSize(void *p){
return sqlite3GlobalConfig.m.xSize(p);
}
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
- assert( p!=0 );
- if( db==0 || !isLookaside(db,p) ){
-#if SQLITE_DEBUG
- if( db==0 ){
- assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
- assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
+ if( db==0 ){
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
+ return sqlite3MallocSize(p);
+ }else{
+ assert( sqlite3_mutex_held(db->mutex) );
+ if( isLookaside(db, p) ){
+ return db->lookaside.sz;
}else{
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ return sqlite3GlobalConfig.m.xSize(p);
}
-#endif
- return sqlite3GlobalConfig.m.xSize(p);
- }else{
- assert( sqlite3_mutex_held(db->mutex) );
- return db->lookaside.sz;
}
}
SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void *p){
assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
- return p ? sqlite3GlobalConfig.m.xSize(p) : 0;
+ return (sqlite3_uint64)sqlite3GlobalConfig.m.xSize(p);
}
/*
@@ -24128,14 +21081,14 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){
pNew = pOld;
}else if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
+ sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
nDiff = nNew - nOld;
if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
mem0.alarmThreshold-nDiff ){
sqlite3MallocAlarm(nDiff);
}
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
- if( pNew==0 && mem0.alarmThreshold>0 ){
+ if( pNew==0 && mem0.alarmCallback ){
sqlite3MallocAlarm((int)nBytes);
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
}
@@ -24186,31 +21139,16 @@ SQLITE_PRIVATE void *sqlite3MallocZero(u64 n){
** the mallocFailed flag in the connection pointer.
*/
SQLITE_PRIVATE void *sqlite3DbMallocZero(sqlite3 *db, u64 n){
- void *p;
- testcase( db==0 );
- p = sqlite3DbMallocRaw(db, n);
- if( p ) memset(p, 0, (size_t)n);
- return p;
-}
-
-
-/* Finish the work of sqlite3DbMallocRawNN for the unusual and
-** slower case when the allocation cannot be fulfilled using lookaside.
-*/
-static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){
- void *p;
- assert( db!=0 );
- p = sqlite3Malloc(n);
- if( !p ) sqlite3OomFault(db);
- sqlite3MemdebugSetType(p,
- (db->lookaside.bDisable==0) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP);
+ void *p = sqlite3DbMallocRaw(db, n);
+ if( p ){
+ memset(p, 0, (size_t)n);
+ }
return p;
}
/*
-** Allocate memory, either lookaside (if possible) or heap.
-** If the allocation fails, set the mallocFailed flag in
-** the connection pointer.
+** Allocate and zero memory. If the allocation fails, make
+** the mallocFailed flag in the connection pointer.
**
** If db!=0 and db->mallocFailed is true (indicating a prior malloc
** failure on the same database connection) then always return 0.
@@ -24225,73 +21163,64 @@ static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){
**
** In other words, if a subsequent malloc (ex: "b") worked, it is assumed
** that all prior mallocs (ex: "a") worked too.
-**
-** The sqlite3MallocRawNN() variant guarantees that the "db" parameter is
-** not a NULL pointer.
*/
SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3 *db, u64 n){
void *p;
- if( db ) return sqlite3DbMallocRawNN(db, n);
- p = sqlite3Malloc(n);
- sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
- return p;
-}
-SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){
+ assert( db==0 || sqlite3_mutex_held(db->mutex) );
+ assert( db==0 || db->pnBytesFreed==0 );
#ifndef SQLITE_OMIT_LOOKASIDE
- LookasideSlot *pBuf;
- assert( db!=0 );
- assert( sqlite3_mutex_held(db->mutex) );
- assert( db->pnBytesFreed==0 );
- if( db->lookaside.bDisable==0 ){
- assert( db->mallocFailed==0 );
- 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;
+ if( db ){
+ LookasideSlot *pBuf;
+ if( db->mallocFailed ){
+ return 0;
+ }
+ if( db->lookaside.bEnabled ){
+ if( n>db->lookaside.sz ){
+ db->lookaside.anStat[1]++;
+ }else if( (pBuf = db->lookaside.pFree)==0 ){
+ db->lookaside.anStat[2]++;
+ }else{
+ db->lookaside.pFree = pBuf->pNext;
+ db->lookaside.nOut++;
+ db->lookaside.anStat[0]++;
+ if( db->lookaside.nOut>db->lookaside.mxOut ){
+ db->lookaside.mxOut = db->lookaside.nOut;
+ }
+ return (void*)pBuf;
}
- return (void*)pBuf;
}
- }else if( db->mallocFailed ){
- return 0;
}
#else
- assert( db!=0 );
- assert( sqlite3_mutex_held(db->mutex) );
- assert( db->pnBytesFreed==0 );
- if( db->mallocFailed ){
+ if( db && db->mallocFailed ){
return 0;
}
#endif
- return dbMallocRawFinish(db, n);
+ p = sqlite3Malloc(n);
+ if( !p && db ){
+ db->mallocFailed = 1;
+ }
+ sqlite3MemdebugSetType(p,
+ (db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP);
+ return p;
}
-/* Forward declaration */
-static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n);
-
/*
** Resize the block of memory pointed to by p to n bytes. If the
** resize fails, set the mallocFailed flag in the connection object.
*/
SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){
- assert( db!=0 );
- if( p==0 ) return sqlite3DbMallocRawNN(db, n);
- assert( sqlite3_mutex_held(db->mutex) );
- if( isLookaside(db,p) && n<=db->lookaside.sz ) return p;
- return dbReallocFinish(db, p, n);
-}
-static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){
void *pNew = 0;
assert( db!=0 );
- assert( p!=0 );
+ assert( sqlite3_mutex_held(db->mutex) );
if( db->mallocFailed==0 ){
+ if( p==0 ){
+ return sqlite3DbMallocRaw(db, n);
+ }
if( isLookaside(db, p) ){
- pNew = sqlite3DbMallocRawNN(db, n);
+ if( n<=db->lookaside.sz ){
+ return p;
+ }
+ pNew = sqlite3DbMallocRaw(db, n);
if( pNew ){
memcpy(pNew, p, db->lookaside.sz);
sqlite3DbFree(db, p);
@@ -24302,10 +21231,10 @@ static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
pNew = sqlite3_realloc64(p, n);
if( !pNew ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
}
sqlite3MemdebugSetType(pNew,
- (db->lookaside.bDisable==0 ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
+ (db->lookaside.bEnabled ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
}
}
return pNew;
@@ -24347,12 +21276,11 @@ SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){
}
SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
char *zNew;
- assert( db!=0 );
if( z==0 ){
return 0;
}
assert( (n&0x7fffffff)==n );
- zNew = sqlite3DbMallocRawNN(db, n+1);
+ zNew = sqlite3DbMallocRaw(db, n+1);
if( zNew ){
memcpy(zNew, z, (size_t)n);
zNew[n] = 0;
@@ -24361,52 +21289,28 @@ SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
}
/*
-** Free any prior content in *pz and replace it with a copy of zNew.
+** Create a string from the zFromat argument and the va_list that follows.
+** Store the string in memory obtained from sqliteMalloc() and make *pz
+** point to that string.
*/
-SQLITE_PRIVATE void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){
- sqlite3DbFree(db, *pz);
- *pz = sqlite3DbStrDup(db, zNew);
-}
-
-/*
-** Call this routine to record the fact that an OOM (out-of-memory) error
-** has happened. This routine will set db->mallocFailed, and also
-** temporarily disable the lookaside memory allocator and interrupt
-** any running VDBEs.
-*/
-SQLITE_PRIVATE void sqlite3OomFault(sqlite3 *db){
- if( db->mallocFailed==0 && db->bBenignMalloc==0 ){
- db->mallocFailed = 1;
- if( db->nVdbeExec>0 ){
- db->u1.isInterrupted = 1;
- }
- db->lookaside.bDisable++;
- }
-}
+SQLITE_PRIVATE void sqlite3SetString(char **pz, sqlite3 *db, const char *zFormat, ...){
+ va_list ap;
+ char *z;
-/*
-** This routine reactivates the memory allocator and clears the
-** db->mallocFailed flag as necessary.
-**
-** The memory allocator is not restarted if there are running
-** VDBEs.
-*/
-SQLITE_PRIVATE void sqlite3OomClear(sqlite3 *db){
- if( db->mallocFailed && db->nVdbeExec==0 ){
- db->mallocFailed = 0;
- db->u1.isInterrupted = 0;
- assert( db->lookaside.bDisable>0 );
- db->lookaside.bDisable--;
- }
+ va_start(ap, zFormat);
+ z = sqlite3VMPrintf(db, zFormat, ap);
+ va_end(ap);
+ sqlite3DbFree(db, *pz);
+ *pz = z;
}
/*
** Take actions at the end of an API call to indicate an OOM error
*/
static SQLITE_NOINLINE int apiOomError(sqlite3 *db){
- sqlite3OomClear(db);
+ db->mallocFailed = 0;
sqlite3Error(db, SQLITE_NOMEM);
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
/*
@@ -24418,16 +21322,17 @@ static SQLITE_NOINLINE int apiOomError(sqlite3 *db){
** function. However, if a malloc() failure has occurred since the previous
** invocation SQLITE_NOMEM is returned instead.
**
-** If an OOM as occurred, then the connection error-code (the value
-** returned by sqlite3_errcode()) is set to SQLITE_NOMEM.
+** If the first argument, db, is not NULL and a malloc() error has occurred,
+** then the connection error-code (the value returned by sqlite3_errcode())
+** is set to SQLITE_NOMEM.
*/
SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){
- /* If the db handle must hold the connection handle mutex here.
- ** Otherwise the read (and possible write) of db->mallocFailed
+ /* If the db handle is not NULL, then we must hold the connection handle
+ ** mutex here. Otherwise the read (and possible write) of db->mallocFailed
** is unsafe, as is the call to sqlite3Error().
*/
- assert( db!=0 );
- assert( sqlite3_mutex_held(db->mutex) );
+ assert( !db || sqlite3_mutex_held(db->mutex) );
+ if( db==0 ) return rc & 0xff;
if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){
return apiOomError(db);
}
@@ -24438,41 +21343,43 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){
/************** Begin file printf.c ******************************************/
/*
** The "printf" code that follows dates from the 1980's. It is in
-** the public domain.
+** the public domain. The original comments are included here for
+** completeness. They are very out-of-date but might be useful as
+** an historical reference. Most of the "enhancements" have been backed
+** out so that the functionality is now the same as standard printf().
**
**************************************************************************
**
** This file contains code for a set of "printf"-like routines. These
** routines format strings much like the printf() from the standard C
** library, though the implementation here has enhancements to support
-** SQLite.
+** SQLlite.
*/
-/* #include "sqliteInt.h" */
/*
** Conversion types fall into various categories as defined by the
** following enumeration.
*/
-#define etRADIX 0 /* Integer types. %d, %x, %o, and so forth */
-#define etFLOAT 1 /* Floating point. %f */
-#define etEXP 2 /* Exponentional notation. %e and %E */
-#define etGENERIC 3 /* Floating or exponential, depending on exponent. %g */
-#define etSIZE 4 /* Return number of characters processed so far. %n */
-#define etSTRING 5 /* Strings. %s */
-#define etDYNSTRING 6 /* Dynamically allocated strings. %z */
-#define etPERCENT 7 /* Percent symbol. %% */
-#define etCHARX 8 /* Characters. %c */
+#define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */
+#define etFLOAT 2 /* Floating point. %f */
+#define etEXP 3 /* Exponentional notation. %e and %E */
+#define etGENERIC 4 /* Floating or exponential, depending on exponent. %g */
+#define etSIZE 5 /* Return number of characters processed so far. %n */
+#define etSTRING 6 /* Strings. %s */
+#define etDYNSTRING 7 /* Dynamically allocated strings. %z */
+#define etPERCENT 8 /* Percent symbol. %% */
+#define etCHARX 9 /* Characters. %c */
/* The rest are extensions, not normally found in printf() */
-#define etSQLESCAPE 9 /* Strings with '\'' doubled. %q */
-#define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '',
+#define etSQLESCAPE 10 /* Strings with '\'' doubled. %q */
+#define etSQLESCAPE2 11 /* Strings with '\'' doubled and enclosed in '',
NULL pointers replaced by SQL NULL. %Q */
-#define etTOKEN 11 /* a pointer to a Token structure */
-#define etSRCLIST 12 /* a pointer to a SrcList */
-#define etPOINTER 13 /* The %p conversion */
-#define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */
-#define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */
+#define etTOKEN 12 /* a pointer to a Token structure */
+#define etSRCLIST 13 /* a pointer to a SrcList */
+#define etPOINTER 14 /* The %p conversion */
+#define etSQLESCAPE3 15 /* %w -> Strings with '\"' doubled */
+#define etORDINAL 16 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */
-#define etINVALID 16 /* Any unrecognized conversion type */
+#define etINVALID 0 /* Any unrecognized conversion type */
/*
@@ -24609,6 +21516,7 @@ static char *getTextArg(PrintfArguments *p){
*/
SQLITE_PRIVATE void sqlite3VXPrintf(
StrAccum *pAccum, /* Accumulate results here */
+ u32 bFlags, /* SQLITE_PRINTF_* flags */
const char *fmt, /* Format string */
va_list ap /* arguments */
){
@@ -24627,7 +21535,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
etByte flag_long; /* True if "l" flag is present */
etByte flag_longlong; /* True if the "ll" flag is present */
etByte done; /* Loop termination flag */
- etByte xtype = etINVALID; /* Conversion paradigm */
+ etByte xtype = 0; /* Conversion paradigm */
u8 bArgList; /* True for SQLITE_PRINTF_SQLFUNC */
u8 useIntern; /* Ok to use internal conversions (ex: %T) */
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
@@ -24648,11 +21556,11 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
char buf[etBUFSIZE]; /* Conversion buffer */
bufpt = 0;
- if( pAccum->printfFlags ){
- if( (bArgList = (pAccum->printfFlags & SQLITE_PRINTF_SQLFUNC))!=0 ){
+ if( bFlags ){
+ if( (bArgList = (bFlags & SQLITE_PRINTF_SQLFUNC))!=0 ){
pArgList = va_arg(ap, PrintfArguments*);
}
- useIntern = pAccum->printfFlags & SQLITE_PRINTF_INTERNAL;
+ useIntern = bFlags & SQLITE_PRINTF_INTERNAL;
}else{
bArgList = useIntern = 0;
}
@@ -24707,12 +21615,6 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
testcase( wx>0x7fffffff );
width = wx & 0x7fffffff;
}
- assert( width>=0 );
-#ifdef SQLITE_PRINTF_PRECISION_LIMIT
- if( width>SQLITE_PRINTF_PRECISION_LIMIT ){
- width = SQLITE_PRINTF_PRECISION_LIMIT;
- }
-#endif
/* Get the precision */
if( c=='.' ){
@@ -24739,14 +21641,6 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
}else{
precision = -1;
}
- assert( precision>=(-1) );
-#ifdef SQLITE_PRINTF_PRECISION_LIMIT
- if( precision>SQLITE_PRINTF_PRECISION_LIMIT ){
- precision = SQLITE_PRINTF_PRECISION_LIMIT;
- }
-#endif
-
-
/* Get the conversion type modifier */
if( c=='l' ){
flag_long = 1;
@@ -24919,16 +21813,21 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
if( realvalue>0.0 ){
LONGDOUBLE_TYPE scale = 1.0;
while( realvalue>=1e100*scale && exp<=350 ){ scale *= 1e100;exp+=100;}
- while( realvalue>=1e10*scale && exp<=350 ){ scale *= 1e10; exp+=10; }
+ while( realvalue>=1e64*scale && exp<=350 ){ scale *= 1e64; exp+=64; }
+ while( realvalue>=1e8*scale && exp<=350 ){ scale *= 1e8; exp+=8; }
while( realvalue>=10.0*scale && exp<=350 ){ scale *= 10.0; exp++; }
realvalue /= scale;
while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; }
while( realvalue<1.0 ){ realvalue *= 10.0; exp--; }
if( exp>350 ){
- bufpt = buf;
- buf[0] = prefix;
- memcpy(buf+(prefix!=0),"Inf",4);
- length = 3+(prefix!=0);
+ if( prefix=='-' ){
+ bufpt = "-Inf";
+ }else if( prefix=='+' ){
+ bufpt = "+Inf";
+ }else{
+ bufpt = "Inf";
+ }
+ length = sqlite3Strlen30(bufpt);
break;
}
}
@@ -25077,13 +21976,12 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
case etDYNSTRING:
if( bArgList ){
bufpt = getTextArg(pArgList);
- xtype = etSTRING;
}else{
bufpt = va_arg(ap,char*);
}
if( bufpt==0 ){
bufpt = "";
- }else if( xtype==etDYNSTRING ){
+ }else if( xtype==etDYNSTRING && !bArgList ){
zExtra = bufpt;
}
if( precision>=0 ){
@@ -25092,9 +21990,9 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
length = sqlite3Strlen30(bufpt);
}
break;
- case etSQLESCAPE: /* Escape ' characters */
- case etSQLESCAPE2: /* Escape ' and enclose in '...' */
- case etSQLESCAPE3: { /* Escape " characters */
+ case etSQLESCAPE:
+ case etSQLESCAPE2:
+ case etSQLESCAPE3: {
int i, j, k, n, isnull;
int needQuote;
char ch;
@@ -25113,7 +22011,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
if( ch==q ) n++;
}
needQuote = !isnull && xtype==etSQLESCAPE2;
- n += i + 3;
+ n += i + 1 + needQuote*2;
if( n>etBUFSIZE ){
bufpt = zExtra = sqlite3Malloc( n );
if( bufpt==0 ){
@@ -25177,7 +22075,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
if( width>0 && flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
if( zExtra ){
- sqlite3DbFree(pAccum->db, zExtra);
+ sqlite3_free(zExtra);
zExtra = 0;
}
}/* End for loop over the format string */
@@ -25203,9 +22101,8 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
setStrAccumError(p, STRACCUM_TOOBIG);
return N;
}else{
- char *zOld = isMalloced(p) ? p->zText : 0;
+ char *zOld = (p->zText==p->zBase ? 0 : p->zText);
i64 szNew = p->nChar;
- assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) );
szNew += N + 1;
if( szNew+p->nChar<=p->mxAlloc ){
/* Force exponential buffer size growth as long as it does not overflow,
@@ -25226,10 +22123,9 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
}
if( zNew ){
assert( p->zText!=0 || p->nChar==0 );
- if( !isMalloced(p) && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
+ if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
p->zText = zNew;
p->nAlloc = sqlite3DbMallocSize(p->db, zNew);
- p->printfFlags |= SQLITE_PRINTF_MALLOCED;
}else{
sqlite3StrAccumReset(p);
setStrAccumError(p, STRACCUM_NOMEM);
@@ -25247,7 +22143,6 @@ SQLITE_PRIVATE void sqlite3AppendChar(StrAccum *p, int N, char c){
if( p->nChar+(i64)N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){
return;
}
- assert( (p->zText==p->zBase)==!isMalloced(p) );
while( (N--)>0 ) p->zText[p->nChar++] = c;
}
@@ -25265,7 +22160,6 @@ static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){
memcpy(&p->zText[p->nChar], z, N);
p->nChar += N;
}
- assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) );
}
/*
@@ -25301,13 +22195,11 @@ SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){
*/
SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){
if( p->zText ){
- assert( (p->zText==p->zBase)==!isMalloced(p) );
p->zText[p->nChar] = 0;
- if( p->mxAlloc>0 && !isMalloced(p) ){
+ if( p->mxAlloc>0 && p->zText==p->zBase ){
p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
if( p->zText ){
memcpy(p->zText, p->zBase, p->nChar+1);
- p->printfFlags |= SQLITE_PRINTF_MALLOCED;
}else{
setStrAccumError(p, STRACCUM_NOMEM);
}
@@ -25320,10 +22212,8 @@ SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){
** Reset an StrAccum string. Reclaim all malloced memory.
*/
SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){
- assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) );
- if( isMalloced(p) ){
+ if( p->zText!=p->zBase ){
sqlite3DbFree(p->db, p->zText);
- p->printfFlags &= ~SQLITE_PRINTF_MALLOCED;
}
p->zText = 0;
}
@@ -25349,7 +22239,6 @@ SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, i
p->nAlloc = n;
p->mxAlloc = mx;
p->accError = 0;
- p->printfFlags = 0;
}
/*
@@ -25363,11 +22252,10 @@ SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list a
assert( db!=0 );
sqlite3StrAccumInit(&acc, db, zBase, sizeof(zBase),
db->aLimit[SQLITE_LIMIT_LENGTH]);
- acc.printfFlags = SQLITE_PRINTF_INTERNAL;
- sqlite3VXPrintf(&acc, zFormat, ap);
+ sqlite3VXPrintf(&acc, SQLITE_PRINTF_INTERNAL, zFormat, ap);
z = sqlite3StrAccumFinish(&acc);
if( acc.accError==STRACCUM_NOMEM ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
}
return z;
}
@@ -25386,6 +22274,24 @@ SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){
}
/*
+** Like sqlite3MPrintf(), but call sqlite3DbFree() on zStr after formatting
+** the string and before returning. This routine is intended to be used
+** to modify an existing string. For example:
+**
+** x = sqlite3MPrintf(db, x, "prefix %s suffix", x);
+**
+*/
+SQLITE_PRIVATE char *sqlite3MAppendf(sqlite3 *db, char *zStr, const char *zFormat, ...){
+ va_list ap;
+ char *z;
+ va_start(ap, zFormat);
+ z = sqlite3VMPrintf(db, zFormat, ap);
+ va_end(ap);
+ sqlite3DbFree(db, zStr);
+ return z;
+}
+
+/*
** Print into memory obtained from sqlite3_malloc(). Omit the internal
** %-conversion extensions.
*/
@@ -25404,7 +22310,7 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char *zFormat, va_list ap
if( sqlite3_initialize() ) return 0;
#endif
sqlite3StrAccumInit(&acc, 0, zBase, sizeof(zBase), SQLITE_MAX_LENGTH);
- sqlite3VXPrintf(&acc, zFormat, ap);
+ sqlite3VXPrintf(&acc, 0, zFormat, ap);
z = sqlite3StrAccumFinish(&acc);
return z;
}
@@ -25449,7 +22355,7 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int n, char *zBuf, const char
}
#endif
sqlite3StrAccumInit(&acc, 0, zBuf, n, 0);
- sqlite3VXPrintf(&acc, zFormat, ap);
+ sqlite3VXPrintf(&acc, 0, zFormat, ap);
return sqlite3StrAccumFinish(&acc);
}
SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
@@ -25469,18 +22375,13 @@ SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int n, char *zBuf, const char *zF
** sqlite3_log() must render into a static buffer. It cannot dynamically
** allocate memory because it might be called while the memory allocator
** mutex is held.
-**
-** sqlite3VXPrintf() might ask for *temporary* memory allocations for
-** certain format characters (%q) or for very large precisions or widths.
-** Care must be taken that any sqlite3_log() calls that occur while the
-** memory mutex is held do not use these mechanisms.
*/
static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){
StrAccum acc; /* String accumulator */
char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */
sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0);
- sqlite3VXPrintf(&acc, zFormat, ap);
+ sqlite3VXPrintf(&acc, 0, zFormat, ap);
sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode,
sqlite3StrAccumFinish(&acc));
}
@@ -25509,7 +22410,7 @@ SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){
char zBuf[500];
sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
va_start(ap,zFormat);
- sqlite3VXPrintf(&acc, zFormat, ap);
+ sqlite3VXPrintf(&acc, 0, zFormat, ap);
va_end(ap);
sqlite3StrAccumFinish(&acc);
fprintf(stdout,"%s", zBuf);
@@ -25517,47 +22418,22 @@ SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){
}
#endif
-
-/*
-** variable-argument wrapper around sqlite3VXPrintf(). The bFlags argument
-** can contain the bit SQLITE_PRINTF_INTERNAL enable internal formats.
-*/
-SQLITE_PRIVATE void sqlite3XPrintf(StrAccum *p, const char *zFormat, ...){
- va_list ap;
- va_start(ap,zFormat);
- sqlite3VXPrintf(p, zFormat, ap);
- va_end(ap);
-}
-
-/************** End of printf.c **********************************************/
-/************** Begin file treeview.c ****************************************/
-/*
-** 2015-06-08
-**
-** 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.
-**
-*************************************************************************
+#ifdef SQLITE_DEBUG
+/*************************************************************************
+** Routines for implementing the "TreeView" display of hierarchical
+** data structures for debugging.
**
-** This file contains C code to implement the TreeView debugging routines.
-** These routines print a parse tree to standard output for debugging and
-** analysis.
+** The main entry points (coded elsewhere) are:
+** sqlite3TreeViewExpr(0, pExpr, 0);
+** sqlite3TreeViewExprList(0, pList, 0, 0);
+** sqlite3TreeViewSelect(0, pSelect, 0);
+** Insert calls to those routines while debugging in order to display
+** a diagram of Expr, ExprList, and Select objects.
**
-** The interfaces in this file is only available when compiling
-** with SQLITE_DEBUG.
*/
-/* #include "sqliteInt.h" */
-#ifdef SQLITE_DEBUG
-
-/*
-** Add a new subitem to the tree. The moreToFollow flag indicates that this
-** is not the last item in the tree.
-*/
-static TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){
+/* Add a new subitem to the tree. The moreToFollow flag indicates that this
+** is not the last item in the tree. */
+SQLITE_PRIVATE TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){
if( p==0 ){
p = sqlite3_malloc64( sizeof(*p) );
if( p==0 ) return 0;
@@ -25569,21 +22445,15 @@ static TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){
if( p->iLevel<sizeof(p->bLine) ) p->bLine[p->iLevel] = moreToFollow;
return p;
}
-
-/*
-** Finished with one layer of the tree
-*/
-static void sqlite3TreeViewPop(TreeView *p){
+/* Finished with one layer of the tree */
+SQLITE_PRIVATE void sqlite3TreeViewPop(TreeView *p){
if( p==0 ) return;
p->iLevel--;
if( p->iLevel<0 ) sqlite3_free(p);
}
-
-/*
-** Generate a single line of output for the tree, with a prefix that contains
-** all the appropriate tree lines
-*/
-static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
+/* Generate a single line of output for the tree, with a prefix that contains
+** all the appropriate tree lines */
+SQLITE_PRIVATE void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
va_list ap;
int i;
StrAccum acc;
@@ -25596,436 +22466,31 @@ static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
sqlite3StrAccumAppend(&acc, p->bLine[i] ? "|-- " : "'-- ", 4);
}
va_start(ap, zFormat);
- sqlite3VXPrintf(&acc, zFormat, ap);
+ sqlite3VXPrintf(&acc, 0, zFormat, ap);
va_end(ap);
if( zBuf[acc.nChar-1]!='\n' ) sqlite3StrAccumAppend(&acc, "\n", 1);
sqlite3StrAccumFinish(&acc);
fprintf(stdout,"%s", zBuf);
fflush(stdout);
}
-
-/*
-** Shorthand for starting a new tree item that consists of a single label
-*/
-static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){
- p = sqlite3TreeViewPush(p, moreFollows);
+/* Shorthand for starting a new tree item that consists of a single label */
+SQLITE_PRIVATE void sqlite3TreeViewItem(TreeView *p, const char *zLabel, u8 moreToFollow){
+ p = sqlite3TreeViewPush(p, moreToFollow);
sqlite3TreeViewLine(p, "%s", zLabel);
}
+#endif /* SQLITE_DEBUG */
/*
-** Generate a human-readable description of a WITH clause.
-*/
-SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
- int i;
- if( pWith==0 ) return;
- if( pWith->nCte==0 ) return;
- if( pWith->pOuter ){
- sqlite3TreeViewLine(pView, "WITH (0x%p, pOuter=0x%p)",pWith,pWith->pOuter);
- }else{
- sqlite3TreeViewLine(pView, "WITH (0x%p)", pWith);
- }
- if( pWith->nCte>0 ){
- pView = sqlite3TreeViewPush(pView, 1);
- for(i=0; i<pWith->nCte; i++){
- StrAccum x;
- char zLine[1000];
- const struct Cte *pCte = &pWith->a[i];
- sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
- sqlite3XPrintf(&x, "%s", pCte->zName);
- if( pCte->pCols && pCte->pCols->nExpr>0 ){
- char cSep = '(';
- int j;
- for(j=0; j<pCte->pCols->nExpr; j++){
- sqlite3XPrintf(&x, "%c%s", cSep, pCte->pCols->a[j].zName);
- cSep = ',';
- }
- sqlite3XPrintf(&x, ")");
- }
- sqlite3XPrintf(&x, " AS");
- sqlite3StrAccumFinish(&x);
- sqlite3TreeViewItem(pView, zLine, i<pWith->nCte-1);
- sqlite3TreeViewSelect(pView, pCte->pSelect, 0);
- sqlite3TreeViewPop(pView);
- }
- sqlite3TreeViewPop(pView);
- }
-}
-
-
-/*
-** Generate a human-readable description of a the Select object.
-*/
-SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
- int n = 0;
- int cnt = 0;
- pView = sqlite3TreeViewPush(pView, moreToFollow);
- if( p->pWith ){
- sqlite3TreeViewWith(pView, p->pWith, 1);
- cnt = 1;
- sqlite3TreeViewPush(pView, 1);
- }
- do{
- sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x nSelectRow=%d",
- ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
- ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags,
- (int)p->nSelectRow
- );
- if( cnt++ ) sqlite3TreeViewPop(pView);
- if( p->pPrior ){
- n = 1000;
- }else{
- n = 0;
- if( p->pSrc && p->pSrc->nSrc ) n++;
- if( p->pWhere ) n++;
- if( p->pGroupBy ) n++;
- if( p->pHaving ) n++;
- if( p->pOrderBy ) n++;
- if( p->pLimit ) n++;
- if( p->pOffset ) n++;
- }
- sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set");
- if( p->pSrc && p->pSrc->nSrc ){
- int i;
- pView = sqlite3TreeViewPush(pView, (n--)>0);
- sqlite3TreeViewLine(pView, "FROM");
- for(i=0; i<p->pSrc->nSrc; i++){
- struct SrcList_item *pItem = &p->pSrc->a[i];
- StrAccum x;
- char zLine[100];
- sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
- sqlite3XPrintf(&x, "{%d,*}", pItem->iCursor);
- if( pItem->zDatabase ){
- sqlite3XPrintf(&x, " %s.%s", pItem->zDatabase, pItem->zName);
- }else if( pItem->zName ){
- sqlite3XPrintf(&x, " %s", pItem->zName);
- }
- if( pItem->pTab ){
- sqlite3XPrintf(&x, " tabname=%Q", pItem->pTab->zName);
- }
- if( pItem->zAlias ){
- sqlite3XPrintf(&x, " (AS %s)", pItem->zAlias);
- }
- if( pItem->fg.jointype & JT_LEFT ){
- sqlite3XPrintf(&x, " LEFT-JOIN");
- }
- sqlite3StrAccumFinish(&x);
- sqlite3TreeViewItem(pView, zLine, i<p->pSrc->nSrc-1);
- if( pItem->pSelect ){
- sqlite3TreeViewSelect(pView, pItem->pSelect, 0);
- }
- if( pItem->fg.isTabFunc ){
- sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:");
- }
- sqlite3TreeViewPop(pView);
- }
- sqlite3TreeViewPop(pView);
- }
- if( p->pWhere ){
- sqlite3TreeViewItem(pView, "WHERE", (n--)>0);
- sqlite3TreeViewExpr(pView, p->pWhere, 0);
- sqlite3TreeViewPop(pView);
- }
- if( p->pGroupBy ){
- sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY");
- }
- if( p->pHaving ){
- sqlite3TreeViewItem(pView, "HAVING", (n--)>0);
- sqlite3TreeViewExpr(pView, p->pHaving, 0);
- sqlite3TreeViewPop(pView);
- }
- if( p->pOrderBy ){
- sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY");
- }
- if( p->pLimit ){
- sqlite3TreeViewItem(pView, "LIMIT", (n--)>0);
- sqlite3TreeViewExpr(pView, p->pLimit, 0);
- sqlite3TreeViewPop(pView);
- }
- if( p->pOffset ){
- sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
- sqlite3TreeViewExpr(pView, p->pOffset, 0);
- sqlite3TreeViewPop(pView);
- }
- if( p->pPrior ){
- const char *zOp = "UNION";
- switch( p->op ){
- case TK_ALL: zOp = "UNION ALL"; break;
- case TK_INTERSECT: zOp = "INTERSECT"; break;
- case TK_EXCEPT: zOp = "EXCEPT"; break;
- }
- sqlite3TreeViewItem(pView, zOp, 1);
- }
- p = p->pPrior;
- }while( p!=0 );
- sqlite3TreeViewPop(pView);
-}
-
-/*
-** Generate a human-readable explanation of an expression tree.
-*/
-SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
- const char *zBinOp = 0; /* Binary operator */
- const char *zUniOp = 0; /* Unary operator */
- char zFlgs[30];
- pView = sqlite3TreeViewPush(pView, moreToFollow);
- if( pExpr==0 ){
- sqlite3TreeViewLine(pView, "nil");
- sqlite3TreeViewPop(pView);
- return;
- }
- if( pExpr->flags ){
- sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x",pExpr->flags);
- }else{
- zFlgs[0] = 0;
- }
- switch( pExpr->op ){
- case TK_AGG_COLUMN: {
- sqlite3TreeViewLine(pView, "AGG{%d:%d}%s",
- pExpr->iTable, pExpr->iColumn, zFlgs);
- break;
- }
- case TK_COLUMN: {
- if( pExpr->iTable<0 ){
- /* This only happens when coding check constraints */
- sqlite3TreeViewLine(pView, "COLUMN(%d)%s", pExpr->iColumn, zFlgs);
- }else{
- sqlite3TreeViewLine(pView, "{%d:%d}%s",
- pExpr->iTable, pExpr->iColumn, zFlgs);
- }
- break;
- }
- case TK_INTEGER: {
- if( pExpr->flags & EP_IntValue ){
- sqlite3TreeViewLine(pView, "%d", pExpr->u.iValue);
- }else{
- sqlite3TreeViewLine(pView, "%s", pExpr->u.zToken);
- }
- break;
- }
-#ifndef SQLITE_OMIT_FLOATING_POINT
- case TK_FLOAT: {
- sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken);
- break;
- }
-#endif
- case TK_STRING: {
- sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken);
- break;
- }
- case TK_NULL: {
- sqlite3TreeViewLine(pView,"NULL");
- break;
- }
-#ifndef SQLITE_OMIT_BLOB_LITERAL
- case TK_BLOB: {
- sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken);
- break;
- }
-#endif
- case TK_VARIABLE: {
- sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)",
- pExpr->u.zToken, pExpr->iColumn);
- break;
- }
- case TK_REGISTER: {
- sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable);
- break;
- }
- case TK_ID: {
- sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken);
- break;
- }
-#ifndef SQLITE_OMIT_CAST
- case TK_CAST: {
- /* Expressions of the form: CAST(pLeft AS token) */
- sqlite3TreeViewLine(pView,"CAST %Q", pExpr->u.zToken);
- sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
- break;
- }
-#endif /* SQLITE_OMIT_CAST */
- case TK_LT: zBinOp = "LT"; break;
- case TK_LE: zBinOp = "LE"; break;
- case TK_GT: zBinOp = "GT"; break;
- case TK_GE: zBinOp = "GE"; break;
- case TK_NE: zBinOp = "NE"; break;
- case TK_EQ: zBinOp = "EQ"; break;
- case TK_IS: zBinOp = "IS"; break;
- case TK_ISNOT: zBinOp = "ISNOT"; break;
- case TK_AND: zBinOp = "AND"; break;
- case TK_OR: zBinOp = "OR"; break;
- case TK_PLUS: zBinOp = "ADD"; break;
- case TK_STAR: zBinOp = "MUL"; break;
- case TK_MINUS: zBinOp = "SUB"; break;
- case TK_REM: zBinOp = "REM"; break;
- case TK_BITAND: zBinOp = "BITAND"; break;
- case TK_BITOR: zBinOp = "BITOR"; break;
- case TK_SLASH: zBinOp = "DIV"; break;
- case TK_LSHIFT: zBinOp = "LSHIFT"; break;
- case TK_RSHIFT: zBinOp = "RSHIFT"; break;
- case TK_CONCAT: zBinOp = "CONCAT"; break;
- case TK_DOT: zBinOp = "DOT"; break;
-
- case TK_UMINUS: zUniOp = "UMINUS"; break;
- case TK_UPLUS: zUniOp = "UPLUS"; break;
- case TK_BITNOT: zUniOp = "BITNOT"; break;
- case TK_NOT: zUniOp = "NOT"; break;
- case TK_ISNULL: zUniOp = "ISNULL"; break;
- case TK_NOTNULL: zUniOp = "NOTNULL"; break;
-
- case TK_SPAN: {
- sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken);
- sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
- break;
- }
-
- case TK_COLLATE: {
- sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken);
- sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
- break;
- }
-
- case TK_AGG_FUNCTION:
- case TK_FUNCTION: {
- ExprList *pFarg; /* List of function arguments */
- if( ExprHasProperty(pExpr, EP_TokenOnly) ){
- pFarg = 0;
- }else{
- pFarg = pExpr->x.pList;
- }
- if( pExpr->op==TK_AGG_FUNCTION ){
- sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q",
- pExpr->op2, pExpr->u.zToken);
- }else{
- sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken);
- }
- if( pFarg ){
- sqlite3TreeViewExprList(pView, pFarg, 0, 0);
- }
- break;
- }
-#ifndef SQLITE_OMIT_SUBQUERY
- case TK_EXISTS: {
- sqlite3TreeViewLine(pView, "EXISTS-expr");
- sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
- break;
- }
- case TK_SELECT: {
- sqlite3TreeViewLine(pView, "SELECT-expr");
- sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
- break;
- }
- case TK_IN: {
- sqlite3TreeViewLine(pView, "IN");
- sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
- if( ExprHasProperty(pExpr, EP_xIsSelect) ){
- sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
- }else{
- sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0);
- }
- break;
- }
-#endif /* SQLITE_OMIT_SUBQUERY */
-
- /*
- ** x BETWEEN y AND z
- **
- ** This is equivalent to
- **
- ** x>=y AND x<=z
- **
- ** X is stored in pExpr->pLeft.
- ** Y is stored in pExpr->pList->a[0].pExpr.
- ** Z is stored in pExpr->pList->a[1].pExpr.
- */
- case TK_BETWEEN: {
- Expr *pX = pExpr->pLeft;
- Expr *pY = pExpr->x.pList->a[0].pExpr;
- Expr *pZ = pExpr->x.pList->a[1].pExpr;
- sqlite3TreeViewLine(pView, "BETWEEN");
- sqlite3TreeViewExpr(pView, pX, 1);
- sqlite3TreeViewExpr(pView, pY, 1);
- sqlite3TreeViewExpr(pView, pZ, 0);
- break;
- }
- case TK_TRIGGER: {
- /* If the opcode is TK_TRIGGER, then the expression is a reference
- ** to a column in the new.* or old.* pseudo-tables available to
- ** trigger programs. In this case Expr.iTable is set to 1 for the
- ** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn
- ** is set to the column of the pseudo-table to read, or to -1 to
- ** read the rowid field.
- */
- sqlite3TreeViewLine(pView, "%s(%d)",
- pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn);
- break;
- }
- case TK_CASE: {
- sqlite3TreeViewLine(pView, "CASE");
- sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
- sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0);
- break;
- }
-#ifndef SQLITE_OMIT_TRIGGER
- case TK_RAISE: {
- const char *zType = "unk";
- switch( pExpr->affinity ){
- case OE_Rollback: zType = "rollback"; break;
- case OE_Abort: zType = "abort"; break;
- case OE_Fail: zType = "fail"; break;
- case OE_Ignore: zType = "ignore"; break;
- }
- sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken);
- break;
- }
-#endif
- default: {
- sqlite3TreeViewLine(pView, "op=%d", pExpr->op);
- break;
- }
- }
- if( zBinOp ){
- sqlite3TreeViewLine(pView, "%s%s", zBinOp, zFlgs);
- sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
- sqlite3TreeViewExpr(pView, pExpr->pRight, 0);
- }else if( zUniOp ){
- sqlite3TreeViewLine(pView, "%s%s", zUniOp, zFlgs);
- sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
- }
- sqlite3TreeViewPop(pView);
-}
-
-/*
-** Generate a human-readable explanation of an expression list.
+** variable-argument wrapper around sqlite3VXPrintf().
*/
-SQLITE_PRIVATE void sqlite3TreeViewExprList(
- TreeView *pView,
- const ExprList *pList,
- u8 moreToFollow,
- const char *zLabel
-){
- int i;
- pView = sqlite3TreeViewPush(pView, moreToFollow);
- if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST";
- if( pList==0 ){
- sqlite3TreeViewLine(pView, "%s (empty)", zLabel);
- }else{
- sqlite3TreeViewLine(pView, "%s", zLabel);
- for(i=0; i<pList->nExpr; i++){
- int j = pList->a[i].u.x.iOrderByCol;
- if( j ){
- sqlite3TreeViewPush(pView, 0);
- sqlite3TreeViewLine(pView, "iOrderByCol=%d", j);
- }
- sqlite3TreeViewExpr(pView, pList->a[i].pExpr, i<pList->nExpr-1);
- if( j ) sqlite3TreeViewPop(pView);
- }
- }
- sqlite3TreeViewPop(pView);
+SQLITE_PRIVATE void sqlite3XPrintf(StrAccum *p, u32 bFlags, const char *zFormat, ...){
+ va_list ap;
+ va_start(ap,zFormat);
+ sqlite3VXPrintf(p, bFlags, zFormat, ap);
+ va_end(ap);
}
-#endif /* SQLITE_DEBUG */
-
-/************** End of treeview.c ********************************************/
+/************** End of printf.c **********************************************/
/************** Begin file random.c ******************************************/
/*
** 2001 September 15
@@ -26044,7 +22509,6 @@ SQLITE_PRIVATE void sqlite3TreeViewExprList(
** Random numbers are used by some of the database backends in order
** to generate random integer keys for tables or random filenames.
*/
-/* #include "sqliteInt.h" */
/* All threads share a single random number generator.
@@ -26191,9 +22655,7 @@ SQLITE_PRIVATE void sqlite3PrngRestoreState(void){
** of multiple cores can do so, while also allowing applications to stay
** single-threaded if desired.
*/
-/* #include "sqliteInt.h" */
#if SQLITE_OS_WIN
-/* # include "os_win.h" */
#endif
#if SQLITE_MAX_WORKER_THREADS>0
@@ -26229,14 +22691,10 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
*ppThread = 0;
p = sqlite3Malloc(sizeof(*p));
- if( p==0 ) return SQLITE_NOMEM_BKPT;
+ if( p==0 ) return SQLITE_NOMEM;
memset(p, 0, sizeof(*p));
p->xTask = xTask;
p->pIn = pIn;
- /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a
- ** function that returns SQLITE_ERROR when passed the argument 200, that
- ** forces worker threads to run sequentially and deterministically
- ** for testing purposes. */
if( sqlite3FaultSim(200) ){
rc = 1;
}else{
@@ -26255,7 +22713,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
int rc;
assert( ppOut!=0 );
- if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
+ if( NEVER(p==0) ) return SQLITE_NOMEM;
if( p->done ){
*ppOut = p->pOut;
rc = SQLITE_OK;
@@ -26320,13 +22778,8 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
assert( xTask!=0 );
*ppThread = 0;
p = sqlite3Malloc(sizeof(*p));
- if( p==0 ) return SQLITE_NOMEM_BKPT;
- /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a
- ** function that returns SQLITE_ERROR when passed the argument 200, that
- ** forces worker threads to run sequentially and deterministically
- ** (via the sqlite3FaultSim() term of the conditional) for testing
- ** purposes. */
- if( sqlite3GlobalConfig.bCoreMutex==0 || sqlite3FaultSim(200) ){
+ if( p==0 ) return SQLITE_NOMEM;
+ if( sqlite3GlobalConfig.bCoreMutex==0 ){
memset(p, 0, sizeof(*p));
}else{
p->xTask = xTask;
@@ -26352,9 +22805,9 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
BOOL bRc;
assert( ppOut!=0 );
- if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
+ if( NEVER(p==0) ) return SQLITE_NOMEM;
if( p->xTask==0 ){
- /* assert( p->id==GetCurrentThreadId() ); */
+ assert( p->id==GetCurrentThreadId() );
rc = WAIT_OBJECT_0;
assert( p->tid==0 );
}else{
@@ -26400,7 +22853,7 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
assert( xTask!=0 );
*ppThread = 0;
p = sqlite3Malloc(sizeof(*p));
- if( p==0 ) return SQLITE_NOMEM_BKPT;
+ if( p==0 ) return SQLITE_NOMEM;
if( (SQLITE_PTR_TO_INT(p)/17)&1 ){
p->xTask = xTask;
p->pIn = pIn;
@@ -26416,7 +22869,7 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
assert( ppOut!=0 );
- if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
+ if( NEVER(p==0) ) return SQLITE_NOMEM;
if( p->xTask ){
*ppOut = p->xTask(p->pIn);
}else{
@@ -26427,7 +22880,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
#if defined(SQLITE_TEST)
{
void *pTstAlloc = sqlite3Malloc(10);
- if (!pTstAlloc) return SQLITE_NOMEM_BKPT;
+ if (!pTstAlloc) return SQLITE_NOMEM;
sqlite3_free(pTstAlloc);
}
#endif
@@ -26476,17 +22929,15 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
** 0xfe 0xff big-endian utf-16 follows
**
*/
-/* #include "sqliteInt.h" */
/* #include <assert.h> */
-/* #include "vdbeInt.h" */
-#if !defined(SQLITE_AMALGAMATION) && SQLITE_BYTEORDER==0
+#ifndef SQLITE_AMALGAMATION
/*
** The following constant value is used by the SQLITE_BIGENDIAN and
** SQLITE_LITTLEENDIAN macros.
*/
SQLITE_PRIVATE const int sqlite3one = 1;
-#endif /* SQLITE_AMALGAMATION && SQLITE_BYTEORDER==0 */
+#endif /* SQLITE_AMALGAMATION */
/*
** This lookup table is used to help decode the first byte of
@@ -26674,7 +23125,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
rc = sqlite3VdbeMemMakeWriteable(pMem);
if( rc!=SQLITE_OK ){
assert( rc==SQLITE_NOMEM );
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
zIn = (u8*)pMem->z;
zTerm = &zIn[pMem->n&~1];
@@ -26716,7 +23167,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
zTerm = &zIn[pMem->n];
zOut = sqlite3DbMallocRaw(pMem->db, len);
if( !zOut ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
z = zOut;
@@ -26759,7 +23210,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
c = pMem->flags;
sqlite3VdbeMemRelease(pMem);
- pMem->flags = MEM_Str|MEM_Term|(c&(MEM_AffMask|MEM_Subtype));
+ pMem->flags = MEM_Str|MEM_Term|(c&MEM_AffMask);
pMem->enc = desiredEnc;
pMem->z = (char*)zOut;
pMem->zMalloc = pMem->z;
@@ -26991,7 +23442,6 @@ SQLITE_PRIVATE void sqlite3UtfSelfTest(void){
** strings, and stuff like that.
**
*/
-/* #include "sqliteInt.h" */
/* #include <stdarg.h> */
#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
# include <math.h>
@@ -27081,53 +23531,19 @@ SQLITE_PRIVATE int sqlite3IsNaN(double x){
** than 1GiB) the value returned might be less than the true string length.
*/
SQLITE_PRIVATE int sqlite3Strlen30(const char *z){
+ const char *z2 = z;
if( z==0 ) return 0;
- return 0x3fffffff & (int)strlen(z);
-}
-
-/*
-** Return the declared type of a column. Or return zDflt if the column
-** has no declared type.
-**
-** The column type is an extra string stored after the zero-terminator on
-** the column name if and only if the COLFLAG_HASTYPE flag is set.
-*/
-SQLITE_PRIVATE char *sqlite3ColumnType(Column *pCol, char *zDflt){
- if( (pCol->colFlags & COLFLAG_HASTYPE)==0 ) return zDflt;
- return pCol->zName + strlen(pCol->zName) + 1;
-}
-
-/*
-** Helper function for sqlite3Error() - called rarely. Broken out into
-** a separate routine to avoid unnecessary register saves on entry to
-** sqlite3Error().
-*/
-static SQLITE_NOINLINE void sqlite3ErrorFinish(sqlite3 *db, int err_code){
- if( db->pErr ) sqlite3ValueSetNull(db->pErr);
- sqlite3SystemError(db, err_code);
+ while( *z2 ){ z2++; }
+ return 0x3fffffff & (int)(z2 - z);
}
/*
** Set the current error code to err_code and clear any prior error message.
-** Also set iSysErrno (by calling sqlite3System) if the err_code indicates
-** that would be appropriate.
*/
SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code){
assert( db!=0 );
db->errCode = err_code;
- if( err_code || db->pErr ) sqlite3ErrorFinish(db, err_code);
-}
-
-/*
-** Load the sqlite3.iSysErrno field if that is an appropriate thing
-** to do based on the SQLite error code in rc.
-*/
-SQLITE_PRIVATE void sqlite3SystemError(sqlite3 *db, int rc){
- if( rc==SQLITE_IOERR_NOMEM ) return;
- rc &= 0xff;
- if( rc==SQLITE_CANTOPEN || rc==SQLITE_IOERR ){
- db->iSysErrno = sqlite3OsGetLastError(db->pVfs);
- }
+ if( db->pErr ) sqlite3ValueSetNull(db->pErr);
}
/*
@@ -27154,7 +23570,6 @@ SQLITE_PRIVATE void sqlite3SystemError(sqlite3 *db, int rc){
SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *zFormat, ...){
assert( db!=0 );
db->errCode = err_code;
- sqlite3SystemError(db, err_code);
if( zFormat==0 ){
sqlite3Error(db, err_code);
}else if( db->pErr || (db->pErr = sqlite3ValueNew(db))!=0 ){
@@ -27218,13 +23633,18 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
** brackets from around identifiers. For example: "[a-b-c]" becomes
** "a-b-c".
*/
-SQLITE_PRIVATE void sqlite3Dequote(char *z){
+SQLITE_PRIVATE int sqlite3Dequote(char *z){
char quote;
int i, j;
- if( z==0 ) return;
+ if( z==0 ) return -1;
quote = z[0];
- if( !sqlite3Isquote(quote) ) return;
- if( quote=='[' ) quote = ']';
+ switch( quote ){
+ case '\'': break;
+ case '"': break;
+ case '`': break; /* For MySQL compatibility */
+ case '[': quote = ']'; break; /* For MS SqlServer compatibility */
+ default: return -1;
+ }
for(i=1, j=0;; i++){
assert( z[i] );
if( z[i]==quote ){
@@ -27239,14 +23659,7 @@ SQLITE_PRIVATE void sqlite3Dequote(char *z){
}
}
z[j] = 0;
-}
-
-/*
-** Generate a Token object from a string
-*/
-SQLITE_PRIVATE void sqlite3TokenInit(Token *p, char *z){
- p->z = z;
- p->n = sqlite3Strlen30(z);
+ return j;
}
/* Convenient short-hand */
@@ -27263,25 +23676,16 @@ SQLITE_PRIVATE void sqlite3TokenInit(Token *p, char *z){
** independence" that SQLite uses internally when comparing identifiers.
*/
SQLITE_API int SQLITE_STDCALL sqlite3_stricmp(const char *zLeft, const char *zRight){
+ register unsigned char *a, *b;
if( zLeft==0 ){
return zRight ? -1 : 0;
}else if( zRight==0 ){
return 1;
}
- return sqlite3StrICmp(zLeft, zRight);
-}
-SQLITE_PRIVATE int sqlite3StrICmp(const char *zLeft, const char *zRight){
- unsigned char *a, *b;
- int c;
a = (unsigned char *)zLeft;
b = (unsigned char *)zRight;
- for(;;){
- c = (int)UpperToLower[*a] - (int)UpperToLower[*b];
- if( c || *a==0 ) break;
- a++;
- b++;
- }
- return c;
+ while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
+ return UpperToLower[*a] - UpperToLower[*b];
}
SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
register unsigned char *a, *b;
@@ -27331,7 +23735,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
int eValid = 1; /* True exponent is either not used or is well-formed */
double result;
int nDigits = 0;
- int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */
+ int nonNum = 0;
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
*pResult = 0.0; /* Default return value, in case of an error */
@@ -27344,7 +23748,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
for(i=3-enc; i<length && z[i]==0; i+=2){}
nonNum = i<length;
- zEnd = &z[i^1];
+ zEnd = z+i+enc-3;
z += (enc&1);
}
@@ -27360,6 +23764,9 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
z+=incr;
}
+ /* skip leading zeroes */
+ while( z<zEnd && z[0]=='0' ) z+=incr, nDigits++;
+
/* copy max significant digits to significand */
while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
s = s*10 + (*z - '0');
@@ -27376,13 +23783,12 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
z+=incr;
/* copy digits from after decimal to significand
** (decrease exponent by d to shift decimal right) */
- while( z<zEnd && sqlite3Isdigit(*z) ){
- if( s<((LARGEST_INT64-9)/10) ){
- s = s*10 + (*z - '0');
- d--;
- }
- z+=incr, nDigits++;
+ while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
+ s = s*10 + (*z - '0');
+ z+=incr, nDigits++, d--;
}
+ /* skip non-significant digits */
+ while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++;
}
if( z>=zEnd ) goto do_atof_calc;
@@ -27390,12 +23796,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
if( *z=='e' || *z=='E' ){
z+=incr;
eValid = 0;
-
- /* This branch is needed to avoid a (harmless) buffer overread. The
- ** special comment alerts the mutation tester that the correct answer
- ** is obtained even if the branch is omitted */
- if( z>=zEnd ) goto do_atof_calc; /*PREVENTS-HARMLESS-OVERREAD*/
-
+ if( z>=zEnd ) goto do_atof_calc;
/* get sign of exponent */
if( *z=='-' ){
esign = -1;
@@ -27412,7 +23813,9 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
}
/* skip trailing spaces */
- while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
+ if( nDigits && eValid ){
+ while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
+ }
do_atof_calc:
/* adjust exponent by d, and update sign */
@@ -27424,51 +23827,41 @@ do_atof_calc:
esign = 1;
}
- if( s==0 ) {
- /* In the IEEE 754 standard, zero is signed. */
- result = sign<0 ? -(double)0 : (double)0;
+ /* if 0 significand */
+ if( !s ) {
+ /* In the IEEE 754 standard, zero is signed.
+ ** Add the sign if we've seen at least one digit */
+ result = (sign<0 && nDigits) ? -(double)0 : (double)0;
} else {
- /* Attempt to reduce exponent.
- **
- ** Branches that are not required for the correct answer but which only
- ** help to obtain the correct answer faster are marked with special
- ** comments, as a hint to the mutation tester.
- */
- while( e>0 ){ /*OPTIMIZATION-IF-TRUE*/
- if( esign>0 ){
- if( s>=(LARGEST_INT64/10) ) break; /*OPTIMIZATION-IF-FALSE*/
- s *= 10;
- }else{
- if( s%10!=0 ) break; /*OPTIMIZATION-IF-FALSE*/
- s /= 10;
- }
- e--;
+ /* attempt to reduce exponent */
+ if( esign>0 ){
+ while( s<(LARGEST_INT64/10) && e>0 ) e--,s*=10;
+ }else{
+ while( !(s%10) && e>0 ) e--,s/=10;
}
/* adjust the sign of significand */
s = sign<0 ? -s : s;
- if( e==0 ){ /*OPTIMIZATION-IF-TRUE*/
- result = (double)s;
- }else{
+ /* if exponent, scale significand as appropriate
+ ** and store in result. */
+ if( e ){
LONGDOUBLE_TYPE scale = 1.0;
/* attempt to handle extremely small/large numbers better */
- if( e>307 ){ /*OPTIMIZATION-IF-TRUE*/
- if( e<342 ){ /*OPTIMIZATION-IF-TRUE*/
- while( e%308 ) { scale *= 1.0e+1; e -= 1; }
- if( esign<0 ){
- result = s / scale;
- result /= 1.0e+308;
- }else{
- result = s * scale;
- result *= 1.0e+308;
- }
- }else{ assert( e>=342 );
- if( esign<0 ){
- result = 0.0*s;
- }else{
- result = 1e308*1e308*s; /* Infinity */
- }
+ if( e>307 && e<342 ){
+ while( e%308 ) { scale *= 1.0e+1; e -= 1; }
+ if( esign<0 ){
+ result = s / scale;
+ result /= 1.0e+308;
+ }else{
+ result = s * scale;
+ result *= 1.0e+308;
+ }
+ }else if( e>=342 ){
+ if( esign<0 ){
+ result = 0.0*s;
+ }else{
+ result = 1e308*1e308*s; /* Infinity */
}
}else{
/* 1.0e+22 is the largest power of 10 than can be
@@ -27481,6 +23874,8 @@ do_atof_calc:
result = s * scale;
}
}
+ } else {
+ result = (double)s;
}
}
@@ -27488,7 +23883,7 @@ do_atof_calc:
*pResult = result;
/* return true if number and no extra non-whitespace chracters after */
- return z==zEnd && nDigits>0 && eValid && nonNum==0;
+ return z>=zEnd && nDigits>0 && eValid && nonNum==0;
#else
return !sqlite3Atoi64(z, pResult, length, enc);
#endif /* SQLITE_OMIT_FLOATING_POINT */
@@ -27550,7 +23945,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
int neg = 0; /* assume positive */
int i;
int c = 0;
- int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */
+ int nonNum = 0;
const char *zStart;
const char *zEnd = zNum + length;
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
@@ -27561,7 +23956,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
for(i=3-enc; i<length && zNum[i]==0; i+=2){}
nonNum = i<length;
- zEnd = &zNum[i^1];
+ zEnd = zNum+i+enc-3;
zNum += (enc&1);
}
while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr;
@@ -27588,11 +23983,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
testcase( i==18 );
testcase( i==19 );
testcase( i==20 );
- if( &zNum[i]<zEnd /* Extra bytes at the end */
- || (i==0 && zStart==zNum) /* No digits */
- || i>19*incr /* Too many digits */
- || nonNum /* UTF16 with high-order bytes non-zero */
- ){
+ if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19*incr || nonNum ){
/* zNum is empty or contains non-numeric text or is longer
** than 19 digits (thus guaranteeing that it is too large) */
return 1;
@@ -27634,6 +24025,7 @@ SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
#ifndef SQLITE_OMIT_HEX_INTEGER
if( z[0]=='0'
&& (z[1]=='x' || z[1]=='X')
+ && sqlite3Isxdigit(z[2])
){
u64 u = 0;
int i, k;
@@ -27880,8 +24272,7 @@ SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
/* a: p0<<28 | p2<<14 | p4 (unmasked) */
if (!(a&0x80))
{
- /* we can skip these cause they were (effectively) done above
- ** while calculating s */
+ /* we can skip these cause they were (effectively) done above in calc'ing s */
/* a &= (0x7f<<28)|(0x7f<<14)|(0x7f); */
/* b &= (0x7f<<14)|(0x7f); */
b = b<<7;
@@ -28102,8 +24493,11 @@ SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
** 64-bit integer.
*/
SQLITE_PRIVATE int sqlite3VarintLen(u64 v){
- int i;
- for(i=1; (v >>= 7)!=0; i++){ assert( i<10 ); }
+ int i = 0;
+ do{
+ i++;
+ v >>= 7;
+ }while( v!=0 && ALWAYS(i<9) );
return i;
}
@@ -28112,42 +24506,14 @@ SQLITE_PRIVATE int sqlite3VarintLen(u64 v){
** Read or write a four-byte big-endian integer value.
*/
SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){
-#if SQLITE_BYTEORDER==4321
- u32 x;
- memcpy(&x,p,4);
- return x;
-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
- && defined(__GNUC__) && GCC_VERSION>=4003000
- u32 x;
- memcpy(&x,p,4);
- return __builtin_bswap32(x);
-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
- && defined(_MSC_VER) && _MSC_VER>=1300
- u32 x;
- memcpy(&x,p,4);
- return _byteswap_ulong(x);
-#else
testcase( p[0]&0x80 );
return ((unsigned)p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
-#endif
}
SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){
-#if SQLITE_BYTEORDER==4321
- memcpy(p,&v,4);
-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
- && defined(__GNUC__) && GCC_VERSION>=4003000
- u32 x = __builtin_bswap32(v);
- memcpy(p,&x,4);
-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
- && defined(_MSC_VER) && _MSC_VER>=1300
- u32 x = _byteswap_ulong(v);
- memcpy(p,&x,4);
-#else
p[0] = (u8)(v>>24);
p[1] = (u8)(v>>16);
p[2] = (u8)(v>>8);
p[3] = (u8)v;
-#endif
}
@@ -28179,7 +24545,7 @@ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
char *zBlob;
int i;
- zBlob = (char *)sqlite3DbMallocRawNN(db, n/2 + 1);
+ zBlob = (char *)sqlite3DbMallocRaw(db, n/2 + 1);
n--;
if( zBlob ){
for(i=0; i<n; i+=2){
@@ -28395,7 +24761,7 @@ SQLITE_PRIVATE LogEst sqlite3LogEst(u64 x){
if( x<2 ) return 0;
while( x<8 ){ y -= 10; x <<= 1; }
}else{
- while( x>255 ){ y += 40; x >>= 4; } /*OPTIMIZATION-IF-TRUE*/
+ while( x>255 ){ y += 40; x >>= 4; }
while( x>15 ){ y += 10; x >>= 1; }
}
return a[x&7] + y - 10;
@@ -28418,32 +24784,21 @@ SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double x){
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
-#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
- defined(SQLITE_ENABLE_STAT3_OR_STAT4) || \
- defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
/*
** Convert a LogEst into an integer.
-**
-** Note that this routine is only used when one or more of various
-** non-standard compile-time options is enabled.
*/
SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){
u64 n;
+ if( x<10 ) return 1;
n = x%10;
x /= 10;
if( n>=5 ) n -= 2;
else if( n>=1 ) n -= 1;
-#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
- defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
- if( x>60 ) return (u64)LARGEST_INT64;
-#else
- /* If only SQLITE_ENABLE_STAT3_OR_STAT4 is on, then the largest input
- ** possible to this routine is 310, resulting in a maximum x of 31 */
- assert( x<=60 );
-#endif
- return x>=3 ? (n+8)<<(x-3) : (n+8)>>(3-x);
+ if( x>=3 ){
+ return x>60 ? (u64)LARGEST_INT64 : (n+8)<<(x-3);
+ }
+ return (n+8)>>(3-x);
}
-#endif /* defined SCANSTAT or STAT4 or ESTIMATED_ROWS */
/************** End of util.c ************************************************/
/************** Begin file hash.c ********************************************/
@@ -28461,7 +24816,6 @@ SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){
** This is the implementation of generic hash-tables
** used in SQLite.
*/
-/* #include "sqliteInt.h" */
/* #include <assert.h> */
/* Turn bulk memory into a hash table object by initializing the
@@ -28504,7 +24858,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash *pH){
static unsigned int strHash(const char *z){
unsigned int h = 0;
unsigned char c;
- while( (c = (unsigned char)*z++)!=0 ){ /*OPTIMIZATION-IF-TRUE*/
+ while( (c = (unsigned char)*z++)!=0 ){
h = (h<<3) ^ h ^ sqlite3UpperToLower[c];
}
return h;
@@ -28597,7 +24951,7 @@ static HashElem *findElementWithHash(
int count; /* Number of elements left to test */
unsigned int h; /* The computed hash */
- if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/
+ if( pH->ht ){
struct _ht *pEntry;
h = strHash(pKey) % pH->htsize;
pEntry = &pH->ht[h];
@@ -28718,178 +25072,172 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){
/************** End of hash.c ************************************************/
/************** Begin file opcodes.c *****************************************/
/* Automatically generated. Do not edit */
-/* See the tool/mkopcodec.tcl script for details. */
-#if !defined(SQLITE_OMIT_EXPLAIN) \
- || defined(VDBE_PROFILE) \
- || defined(SQLITE_DEBUG)
+/* See the mkopcodec.awk script for details. */
+#if !defined(SQLITE_OMIT_EXPLAIN) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
#if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS) || defined(SQLITE_DEBUG)
# define OpHelp(X) "\0" X
#else
# define OpHelp(X)
#endif
SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
- static const char *const azName[] = {
- /* 0 */ "Savepoint" OpHelp(""),
- /* 1 */ "AutoCommit" OpHelp(""),
- /* 2 */ "Transaction" OpHelp(""),
- /* 3 */ "SorterNext" OpHelp(""),
- /* 4 */ "PrevIfOpen" OpHelp(""),
- /* 5 */ "NextIfOpen" OpHelp(""),
- /* 6 */ "Prev" OpHelp(""),
- /* 7 */ "Next" OpHelp(""),
- /* 8 */ "Checkpoint" OpHelp(""),
- /* 9 */ "JournalMode" OpHelp(""),
- /* 10 */ "Vacuum" OpHelp(""),
- /* 11 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"),
- /* 12 */ "VUpdate" OpHelp("data=r[P3@P2]"),
- /* 13 */ "Goto" OpHelp(""),
- /* 14 */ "Gosub" OpHelp(""),
- /* 15 */ "InitCoroutine" OpHelp(""),
- /* 16 */ "Yield" OpHelp(""),
- /* 17 */ "MustBeInt" OpHelp(""),
- /* 18 */ "Jump" OpHelp(""),
- /* 19 */ "Not" OpHelp("r[P2]= !r[P1]"),
- /* 20 */ "Once" OpHelp(""),
- /* 21 */ "If" OpHelp(""),
- /* 22 */ "IfNot" OpHelp(""),
- /* 23 */ "SeekLT" OpHelp("key=r[P3@P4]"),
- /* 24 */ "SeekLE" OpHelp("key=r[P3@P4]"),
- /* 25 */ "SeekGE" OpHelp("key=r[P3@P4]"),
- /* 26 */ "SeekGT" OpHelp("key=r[P3@P4]"),
- /* 27 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
- /* 28 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
- /* 29 */ "NoConflict" OpHelp("key=r[P3@P4]"),
- /* 30 */ "NotFound" OpHelp("key=r[P3@P4]"),
- /* 31 */ "Found" OpHelp("key=r[P3@P4]"),
- /* 32 */ "NotExists" OpHelp("intkey=r[P3]"),
- /* 33 */ "Last" OpHelp(""),
- /* 34 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
- /* 35 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
- /* 36 */ "Ne" OpHelp("if r[P1]!=r[P3] goto P2"),
- /* 37 */ "Eq" OpHelp("if r[P1]==r[P3] goto P2"),
- /* 38 */ "Gt" OpHelp("if r[P1]>r[P3] goto P2"),
- /* 39 */ "Le" OpHelp("if r[P1]<=r[P3] goto P2"),
- /* 40 */ "Lt" OpHelp("if r[P1]<r[P3] goto P2"),
- /* 41 */ "Ge" OpHelp("if r[P1]>=r[P3] goto P2"),
- /* 42 */ "SorterSort" OpHelp(""),
- /* 43 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
- /* 44 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
- /* 45 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"),
- /* 46 */ "ShiftRight" OpHelp("r[P3]=r[P2]>>r[P1]"),
- /* 47 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"),
- /* 48 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"),
- /* 49 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"),
- /* 50 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
- /* 51 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
- /* 52 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
- /* 53 */ "Sort" OpHelp(""),
- /* 54 */ "BitNot" OpHelp("r[P1]= ~r[P1]"),
- /* 55 */ "Rewind" OpHelp(""),
- /* 56 */ "IdxLE" OpHelp("key=r[P3@P4]"),
- /* 57 */ "IdxGT" OpHelp("key=r[P3@P4]"),
- /* 58 */ "IdxLT" OpHelp("key=r[P3@P4]"),
- /* 59 */ "IdxGE" OpHelp("key=r[P3@P4]"),
- /* 60 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
- /* 61 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
- /* 62 */ "Program" OpHelp(""),
- /* 63 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
- /* 64 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
- /* 65 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]-=P3, goto P2"),
- /* 66 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
- /* 67 */ "IncrVacuum" OpHelp(""),
- /* 68 */ "VNext" OpHelp(""),
- /* 69 */ "Init" OpHelp("Start at P2"),
- /* 70 */ "Return" OpHelp(""),
- /* 71 */ "EndCoroutine" OpHelp(""),
- /* 72 */ "HaltIfNull" OpHelp("if r[P3]=null halt"),
- /* 73 */ "Halt" OpHelp(""),
- /* 74 */ "Integer" OpHelp("r[P2]=P1"),
- /* 75 */ "Int64" OpHelp("r[P2]=P4"),
- /* 76 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
- /* 77 */ "Null" OpHelp("r[P2..P3]=NULL"),
- /* 78 */ "SoftNull" OpHelp("r[P1]=NULL"),
- /* 79 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
- /* 80 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
- /* 81 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
- /* 82 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
- /* 83 */ "SCopy" OpHelp("r[P2]=r[P1]"),
- /* 84 */ "IntCopy" OpHelp("r[P2]=r[P1]"),
- /* 85 */ "ResultRow" OpHelp("output=r[P1@P2]"),
- /* 86 */ "CollSeq" OpHelp(""),
- /* 87 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"),
- /* 88 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"),
- /* 89 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
- /* 90 */ "RealAffinity" OpHelp(""),
- /* 91 */ "Cast" OpHelp("affinity(r[P1])"),
- /* 92 */ "Permutation" OpHelp(""),
- /* 93 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"),
- /* 94 */ "Column" OpHelp("r[P3]=PX"),
- /* 95 */ "Affinity" OpHelp("affinity(r[P1@P2])"),
- /* 96 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"),
- /* 97 */ "String8" OpHelp("r[P2]='P4'"),
- /* 98 */ "Count" OpHelp("r[P2]=count()"),
- /* 99 */ "ReadCookie" OpHelp(""),
- /* 100 */ "SetCookie" OpHelp(""),
- /* 101 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"),
- /* 102 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
- /* 103 */ "OpenWrite" OpHelp("root=P2 iDb=P3"),
- /* 104 */ "OpenAutoindex" OpHelp("nColumn=P2"),
- /* 105 */ "OpenEphemeral" OpHelp("nColumn=P2"),
- /* 106 */ "SorterOpen" OpHelp(""),
- /* 107 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
- /* 108 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
- /* 109 */ "Close" OpHelp(""),
- /* 110 */ "ColumnsUsed" OpHelp(""),
- /* 111 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
- /* 112 */ "NewRowid" OpHelp("r[P2]=rowid"),
- /* 113 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
- /* 114 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"),
- /* 115 */ "Delete" OpHelp(""),
- /* 116 */ "ResetCount" OpHelp(""),
- /* 117 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
- /* 118 */ "SorterData" OpHelp("r[P2]=data"),
- /* 119 */ "RowKey" OpHelp("r[P2]=key"),
- /* 120 */ "RowData" OpHelp("r[P2]=data"),
- /* 121 */ "Rowid" OpHelp("r[P2]=rowid"),
- /* 122 */ "NullRow" OpHelp(""),
- /* 123 */ "SorterInsert" OpHelp(""),
- /* 124 */ "IdxInsert" OpHelp("key=r[P2]"),
- /* 125 */ "IdxDelete" OpHelp("key=r[P2@P3]"),
- /* 126 */ "Seek" OpHelp("Move P3 to P1.rowid"),
- /* 127 */ "IdxRowid" OpHelp("r[P2]=rowid"),
- /* 128 */ "Destroy" OpHelp(""),
- /* 129 */ "Clear" OpHelp(""),
- /* 130 */ "ResetSorter" OpHelp(""),
- /* 131 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"),
- /* 132 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"),
- /* 133 */ "Real" OpHelp("r[P2]=P4"),
- /* 134 */ "ParseSchema" OpHelp(""),
- /* 135 */ "LoadAnalysis" OpHelp(""),
- /* 136 */ "DropTable" OpHelp(""),
- /* 137 */ "DropIndex" OpHelp(""),
- /* 138 */ "DropTrigger" OpHelp(""),
- /* 139 */ "IntegrityCk" OpHelp(""),
- /* 140 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
- /* 141 */ "Param" OpHelp(""),
- /* 142 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
- /* 143 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
- /* 144 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
- /* 145 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"),
- /* 146 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"),
- /* 147 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
- /* 148 */ "Expire" OpHelp(""),
- /* 149 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
- /* 150 */ "VBegin" OpHelp(""),
- /* 151 */ "VCreate" OpHelp(""),
- /* 152 */ "VDestroy" OpHelp(""),
- /* 153 */ "VOpen" OpHelp(""),
- /* 154 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
- /* 155 */ "VRename" OpHelp(""),
- /* 156 */ "Pagecount" OpHelp(""),
- /* 157 */ "MaxPgcnt" OpHelp(""),
- /* 158 */ "CursorHint" OpHelp(""),
- /* 159 */ "Noop" OpHelp(""),
- /* 160 */ "Explain" OpHelp(""),
+ static const char *const azName[] = { "?",
+ /* 1 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"),
+ /* 2 */ "Savepoint" OpHelp(""),
+ /* 3 */ "AutoCommit" OpHelp(""),
+ /* 4 */ "Transaction" OpHelp(""),
+ /* 5 */ "SorterNext" OpHelp(""),
+ /* 6 */ "PrevIfOpen" OpHelp(""),
+ /* 7 */ "NextIfOpen" OpHelp(""),
+ /* 8 */ "Prev" OpHelp(""),
+ /* 9 */ "Next" OpHelp(""),
+ /* 10 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"),
+ /* 11 */ "Checkpoint" OpHelp(""),
+ /* 12 */ "JournalMode" OpHelp(""),
+ /* 13 */ "Vacuum" OpHelp(""),
+ /* 14 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"),
+ /* 15 */ "VUpdate" OpHelp("data=r[P3@P2]"),
+ /* 16 */ "Goto" OpHelp(""),
+ /* 17 */ "Gosub" OpHelp(""),
+ /* 18 */ "Return" OpHelp(""),
+ /* 19 */ "Not" OpHelp("r[P2]= !r[P1]"),
+ /* 20 */ "InitCoroutine" OpHelp(""),
+ /* 21 */ "EndCoroutine" OpHelp(""),
+ /* 22 */ "Yield" OpHelp(""),
+ /* 23 */ "HaltIfNull" OpHelp("if r[P3]=null halt"),
+ /* 24 */ "Halt" OpHelp(""),
+ /* 25 */ "Integer" OpHelp("r[P2]=P1"),
+ /* 26 */ "Int64" OpHelp("r[P2]=P4"),
+ /* 27 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
+ /* 28 */ "Null" OpHelp("r[P2..P3]=NULL"),
+ /* 29 */ "SoftNull" OpHelp("r[P1]=NULL"),
+ /* 30 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
+ /* 31 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
+ /* 32 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
+ /* 33 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
+ /* 34 */ "SCopy" OpHelp("r[P2]=r[P1]"),
+ /* 35 */ "ResultRow" OpHelp("output=r[P1@P2]"),
+ /* 36 */ "CollSeq" OpHelp(""),
+ /* 37 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
+ /* 38 */ "MustBeInt" OpHelp(""),
+ /* 39 */ "RealAffinity" OpHelp(""),
+ /* 40 */ "Cast" OpHelp("affinity(r[P1])"),
+ /* 41 */ "Permutation" OpHelp(""),
+ /* 42 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"),
+ /* 43 */ "Jump" OpHelp(""),
+ /* 44 */ "Once" OpHelp(""),
+ /* 45 */ "If" OpHelp(""),
+ /* 46 */ "IfNot" OpHelp(""),
+ /* 47 */ "Column" OpHelp("r[P3]=PX"),
+ /* 48 */ "Affinity" OpHelp("affinity(r[P1@P2])"),
+ /* 49 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"),
+ /* 50 */ "Count" OpHelp("r[P2]=count()"),
+ /* 51 */ "ReadCookie" OpHelp(""),
+ /* 52 */ "SetCookie" OpHelp(""),
+ /* 53 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"),
+ /* 54 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
+ /* 55 */ "OpenWrite" OpHelp("root=P2 iDb=P3"),
+ /* 56 */ "OpenAutoindex" OpHelp("nColumn=P2"),
+ /* 57 */ "OpenEphemeral" OpHelp("nColumn=P2"),
+ /* 58 */ "SorterOpen" OpHelp(""),
+ /* 59 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
+ /* 60 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
+ /* 61 */ "Close" OpHelp(""),
+ /* 62 */ "SeekLT" OpHelp("key=r[P3@P4]"),
+ /* 63 */ "SeekLE" OpHelp("key=r[P3@P4]"),
+ /* 64 */ "SeekGE" OpHelp("key=r[P3@P4]"),
+ /* 65 */ "SeekGT" OpHelp("key=r[P3@P4]"),
+ /* 66 */ "Seek" OpHelp("intkey=r[P2]"),
+ /* 67 */ "NoConflict" OpHelp("key=r[P3@P4]"),
+ /* 68 */ "NotFound" OpHelp("key=r[P3@P4]"),
+ /* 69 */ "Found" OpHelp("key=r[P3@P4]"),
+ /* 70 */ "NotExists" OpHelp("intkey=r[P3]"),
+ /* 71 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
+ /* 72 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
+ /* 73 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
+ /* 74 */ "NewRowid" OpHelp("r[P2]=rowid"),
+ /* 75 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
+ /* 76 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
+ /* 77 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
+ /* 78 */ "Ne" OpHelp("if r[P1]!=r[P3] goto P2"),
+ /* 79 */ "Eq" OpHelp("if r[P1]==r[P3] goto P2"),
+ /* 80 */ "Gt" OpHelp("if r[P1]>r[P3] goto P2"),
+ /* 81 */ "Le" OpHelp("if r[P1]<=r[P3] goto P2"),
+ /* 82 */ "Lt" OpHelp("if r[P1]<r[P3] goto P2"),
+ /* 83 */ "Ge" OpHelp("if r[P1]>=r[P3] goto P2"),
+ /* 84 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"),
+ /* 85 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
+ /* 86 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
+ /* 87 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"),
+ /* 88 */ "ShiftRight" OpHelp("r[P3]=r[P2]>>r[P1]"),
+ /* 89 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"),
+ /* 90 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"),
+ /* 91 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"),
+ /* 92 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
+ /* 93 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
+ /* 94 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
+ /* 95 */ "Delete" OpHelp(""),
+ /* 96 */ "BitNot" OpHelp("r[P1]= ~r[P1]"),
+ /* 97 */ "String8" OpHelp("r[P2]='P4'"),
+ /* 98 */ "ResetCount" OpHelp(""),
+ /* 99 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
+ /* 100 */ "SorterData" OpHelp("r[P2]=data"),
+ /* 101 */ "RowKey" OpHelp("r[P2]=key"),
+ /* 102 */ "RowData" OpHelp("r[P2]=data"),
+ /* 103 */ "Rowid" OpHelp("r[P2]=rowid"),
+ /* 104 */ "NullRow" OpHelp(""),
+ /* 105 */ "Last" OpHelp(""),
+ /* 106 */ "SorterSort" OpHelp(""),
+ /* 107 */ "Sort" OpHelp(""),
+ /* 108 */ "Rewind" OpHelp(""),
+ /* 109 */ "SorterInsert" OpHelp(""),
+ /* 110 */ "IdxInsert" OpHelp("key=r[P2]"),
+ /* 111 */ "IdxDelete" OpHelp("key=r[P2@P3]"),
+ /* 112 */ "IdxRowid" OpHelp("r[P2]=rowid"),
+ /* 113 */ "IdxLE" OpHelp("key=r[P3@P4]"),
+ /* 114 */ "IdxGT" OpHelp("key=r[P3@P4]"),
+ /* 115 */ "IdxLT" OpHelp("key=r[P3@P4]"),
+ /* 116 */ "IdxGE" OpHelp("key=r[P3@P4]"),
+ /* 117 */ "Destroy" OpHelp(""),
+ /* 118 */ "Clear" OpHelp(""),
+ /* 119 */ "ResetSorter" OpHelp(""),
+ /* 120 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"),
+ /* 121 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"),
+ /* 122 */ "ParseSchema" OpHelp(""),
+ /* 123 */ "LoadAnalysis" OpHelp(""),
+ /* 124 */ "DropTable" OpHelp(""),
+ /* 125 */ "DropIndex" OpHelp(""),
+ /* 126 */ "DropTrigger" OpHelp(""),
+ /* 127 */ "IntegrityCk" OpHelp(""),
+ /* 128 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
+ /* 129 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
+ /* 130 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
+ /* 131 */ "Program" OpHelp(""),
+ /* 132 */ "Param" OpHelp(""),
+ /* 133 */ "Real" OpHelp("r[P2]=P4"),
+ /* 134 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
+ /* 135 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
+ /* 136 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
+ /* 137 */ "IfPos" OpHelp("if r[P1]>0 goto P2"),
+ /* 138 */ "IfNeg" OpHelp("r[P1]+=P3, if r[P1]<0 goto P2"),
+ /* 139 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]+=P3, goto P2"),
+ /* 140 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
+ /* 141 */ "JumpZeroIncr" OpHelp("if (r[P1]++)==0 ) goto P2"),
+ /* 142 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
+ /* 143 */ "IncrVacuum" OpHelp(""),
+ /* 144 */ "Expire" OpHelp(""),
+ /* 145 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
+ /* 146 */ "VBegin" OpHelp(""),
+ /* 147 */ "VCreate" OpHelp(""),
+ /* 148 */ "VDestroy" OpHelp(""),
+ /* 149 */ "VOpen" OpHelp(""),
+ /* 150 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
+ /* 151 */ "VNext" OpHelp(""),
+ /* 152 */ "VRename" OpHelp(""),
+ /* 153 */ "Pagecount" OpHelp(""),
+ /* 154 */ "MaxPgcnt" OpHelp(""),
+ /* 155 */ "Init" OpHelp("Start at P2"),
+ /* 156 */ "Noop" OpHelp(""),
+ /* 157 */ "Explain" OpHelp(""),
};
return azName[i];
}
@@ -28942,7 +25290,6 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
** * Definitions of sqlite3_vfs objects for all locking methods
** plus implementations of sqlite3_os_init() and sqlite3_os_end().
*/
-/* #include "sqliteInt.h" */
#if SQLITE_OS_UNIX /* This file is used on unix only */
/*
@@ -28970,19 +25317,6 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
# endif
#endif
-/* Use pread() and pwrite() if they are available */
-#if defined(__APPLE__)
-# define HAVE_PREAD 1
-# define HAVE_PWRITE 1
-#endif
-#if defined(HAVE_PREAD64) && defined(HAVE_PWRITE64)
-# undef USE_PREAD
-# define USE_PREAD64 1
-#elif defined(HAVE_PREAD) && defined(HAVE_PWRITE)
-# undef USE_PREAD64
-# define USE_PREAD 1
-#endif
-
/*
** standard include files.
*/
@@ -29061,11 +25395,6 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
*/
#define MAX_PATHNAME 512
-/*
-** Maximum supported symbolic links
-*/
-#define SQLITE_MAX_SYMLINKS 100
-
/* Always cast the getpid() return type for compatibility with
** kernel modules in VxWorks. */
#define osGetpid(X) (pid_t)getpid()
@@ -29175,6 +25504,8 @@ static pid_t randomnessPid = 0;
#define UNIXFILE_DELETE 0x20 /* Delete on close */
#define UNIXFILE_URI 0x40 /* Filename might have query parameters */
#define UNIXFILE_NOLOCK 0x80 /* Do no file locking */
+#define UNIXFILE_WARNED 0x0100 /* verifyDbFile() warnings issued */
+#define UNIXFILE_BLOCK 0x0200 /* Next SHM lock might block */
/*
** Include code that is common to all os_*.c files
@@ -29218,8 +25549,8 @@ static pid_t randomnessPid = 0;
*/
#ifdef SQLITE_PERFORMANCE_TRACE
-/*
-** hwtime.h contains inline assembler code for implementing
+/*
+** hwtime.h contains inline assembler code for implementing
** high-performance timing routines.
*/
/************** Include hwtime.h in the middle of os_common.h ****************/
@@ -29329,14 +25660,14 @@ static sqlite_uint64 g_elapsed;
** of code will give us the ability to simulate a disk I/O error. This
** is used for testing the I/O recovery logic.
*/
-#if defined(SQLITE_TEST)
-SQLITE_API extern int sqlite3_io_error_hit;
-SQLITE_API extern int sqlite3_io_error_hardhit;
-SQLITE_API extern int sqlite3_io_error_pending;
-SQLITE_API extern int sqlite3_io_error_persist;
-SQLITE_API extern int sqlite3_io_error_benign;
-SQLITE_API extern int sqlite3_diskfull_pending;
-SQLITE_API extern int sqlite3_diskfull;
+#ifdef SQLITE_TEST
+SQLITE_API int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */
+SQLITE_API int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */
+SQLITE_API int sqlite3_io_error_pending = 0; /* Count down to first I/O error */
+SQLITE_API int sqlite3_io_error_persist = 0; /* True if I/O errors persist */
+SQLITE_API int sqlite3_io_error_benign = 0; /* True if errors are benign */
+SQLITE_API int sqlite3_diskfull_pending = 0;
+SQLITE_API int sqlite3_diskfull = 0;
#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
#define SimulateIOError(CODE) \
if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
@@ -29362,17 +25693,17 @@ static void local_ioerr(){
#define SimulateIOErrorBenign(X)
#define SimulateIOError(A)
#define SimulateDiskfullError(A)
-#endif /* defined(SQLITE_TEST) */
+#endif
/*
** When testing, keep a count of the number of open files.
*/
-#if defined(SQLITE_TEST)
-SQLITE_API extern int sqlite3_open_file_count;
+#ifdef SQLITE_TEST
+SQLITE_API int sqlite3_open_file_count = 0;
#define OpenCounter(X) sqlite3_open_file_count+=(X)
#else
#define OpenCounter(X)
-#endif /* defined(SQLITE_TEST) */
+#endif
#endif /* !defined(_OS_COMMON_H_) */
@@ -29437,6 +25768,19 @@ static int posixOpen(const char *zFile, int flags, int mode){
return open(zFile, flags, mode);
}
+/*
+** On some systems, calls to fchown() will trigger a message in a security
+** log if they come from non-root processes. So avoid calling fchown() if
+** we are not running as root.
+*/
+static int posixFchown(int fd, uid_t uid, gid_t gid){
+#if OS_VXWORKS
+ return 0;
+#else
+ return geteuid() ? 0 : fchown(fd,uid,gid);
+#endif
+}
+
/* Forward reference */
static int openDirectory(const char*, int*);
static int unixGetpagesize(void);
@@ -29502,7 +25846,7 @@ static struct unix_syscall {
#else
{ "pread64", (sqlite3_syscall_ptr)0, 0 },
#endif
-#define osPread64 ((ssize_t(*)(int,void*,size_t,off64_t))aSyscall[10].pCurrent)
+#define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent)
{ "write", (sqlite3_syscall_ptr)write, 0 },
#define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)
@@ -29520,10 +25864,10 @@ static struct unix_syscall {
#else
{ "pwrite64", (sqlite3_syscall_ptr)0, 0 },
#endif
-#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_t))\
+#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\
aSyscall[13].pCurrent)
- { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 },
+ { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 },
#define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent)
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
@@ -29545,74 +25889,29 @@ static struct unix_syscall {
{ "rmdir", (sqlite3_syscall_ptr)rmdir, 0 },
#define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent)
-#if defined(HAVE_FCHOWN)
- { "fchown", (sqlite3_syscall_ptr)fchown, 0 },
-#else
- { "fchown", (sqlite3_syscall_ptr)0, 0 },
-#endif
+ { "fchown", (sqlite3_syscall_ptr)posixFchown, 0 },
#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
- { "geteuid", (sqlite3_syscall_ptr)geteuid, 0 },
-#define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent)
-
#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
- { "mmap", (sqlite3_syscall_ptr)mmap, 0 },
-#else
- { "mmap", (sqlite3_syscall_ptr)0, 0 },
-#endif
-#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent)
+ { "mmap", (sqlite3_syscall_ptr)mmap, 0 },
+#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[21].pCurrent)
-#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
{ "munmap", (sqlite3_syscall_ptr)munmap, 0 },
-#else
- { "munmap", (sqlite3_syscall_ptr)0, 0 },
-#endif
-#define osMunmap ((void*(*)(void*,size_t))aSyscall[23].pCurrent)
+#define osMunmap ((void*(*)(void*,size_t))aSyscall[22].pCurrent)
-#if HAVE_MREMAP && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
+#if HAVE_MREMAP
{ "mremap", (sqlite3_syscall_ptr)mremap, 0 },
#else
{ "mremap", (sqlite3_syscall_ptr)0, 0 },
#endif
-#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[24].pCurrent)
-
-#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
+#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
{ "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 },
-#else
- { "getpagesize", (sqlite3_syscall_ptr)0, 0 },
-#endif
-#define osGetpagesize ((int(*)(void))aSyscall[25].pCurrent)
-
-#if defined(HAVE_READLINK)
- { "readlink", (sqlite3_syscall_ptr)readlink, 0 },
-#else
- { "readlink", (sqlite3_syscall_ptr)0, 0 },
-#endif
-#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[26].pCurrent)
+#define osGetpagesize ((int(*)(void))aSyscall[24].pCurrent)
-#if defined(HAVE_LSTAT)
- { "lstat", (sqlite3_syscall_ptr)lstat, 0 },
-#else
- { "lstat", (sqlite3_syscall_ptr)0, 0 },
#endif
-#define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent)
}; /* End of the overrideable system calls */
-
-/*
-** On some systems, calls to fchown() will trigger a message in a security
-** log if they come from non-root processes. So avoid calling fchown() if
-** we are not running as root.
-*/
-static int robustFchown(int fd, uid_t uid, gid_t gid){
-#if defined(HAVE_FCHOWN)
- return osGeteuid() ? 0 : osFchown(fd,uid,gid);
-#else
- return 0;
-#endif
-}
-
/*
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
** "unix" VFSes. Return SQLITE_OK opon successfully updating the
@@ -29774,14 +26073,14 @@ static int robust_open(const char *z, int f, mode_t m){
** unixEnterLeave()
*/
static void unixEnterMutex(void){
- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
}
static void unixLeaveMutex(void){
- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
}
#ifdef SQLITE_DEBUG
static int unixMutexHeld(void) {
- return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
+ return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
}
#endif
@@ -29897,12 +26196,23 @@ static int robust_ftruncate(int h, sqlite3_int64 sz){
** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately.
*/
static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
- assert( (sqliteIOErr == SQLITE_IOERR_LOCK) ||
- (sqliteIOErr == SQLITE_IOERR_UNLOCK) ||
- (sqliteIOErr == SQLITE_IOERR_RDLOCK) ||
- (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) );
switch (posixError) {
- case EACCES:
+#if 0
+ /* At one point this code was not commented out. In theory, this branch
+ ** should never be hit, as this function should only be called after
+ ** a locking-related function (i.e. fcntl()) has returned non-zero with
+ ** the value of errno as the first argument. Since a system call has failed,
+ ** errno should be non-zero.
+ **
+ ** Despite this, if errno really is zero, we still don't want to return
+ ** SQLITE_OK. The system call failed, and *some* SQLite error should be
+ ** propagated back to the caller. Commenting this branch out means errno==0
+ ** will be handled by the "default:" case below.
+ */
+ case 0:
+ return SQLITE_OK;
+#endif
+
case EAGAIN:
case ETIMEDOUT:
case EBUSY:
@@ -29912,9 +26222,41 @@ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
* introspection, in which it actually means what it says */
return SQLITE_BUSY;
+ case EACCES:
+ /* EACCES is like EAGAIN during locking operations, but not any other time*/
+ if( (sqliteIOErr == SQLITE_IOERR_LOCK) ||
+ (sqliteIOErr == SQLITE_IOERR_UNLOCK) ||
+ (sqliteIOErr == SQLITE_IOERR_RDLOCK) ||
+ (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) ){
+ return SQLITE_BUSY;
+ }
+ /* else fall through */
case EPERM:
return SQLITE_PERM;
+#if EOPNOTSUPP!=ENOTSUP
+ case EOPNOTSUPP:
+ /* something went terribly awry, unless during file system support
+ * introspection, in which it actually means what it says */
+#endif
+#ifdef ENOTSUP
+ case ENOTSUP:
+ /* invalid fd, unless during file system support introspection, in which
+ * it actually means what it says */
+#endif
+ case EIO:
+ case EBADF:
+ case EINVAL:
+ case ENOTCONN:
+ case ENODEV:
+ case ENXIO:
+ case ENOENT:
+#ifdef ESTALE /* ESTALE is not defined on Interix systems */
+ case ESTALE:
+#endif
+ case ENOSYS:
+ /* these should force the client to close the file and reconnect */
+
default:
return sqliteIOErr;
}
@@ -30198,7 +26540,7 @@ static unixInodeInfo *inodeList = 0;
/*
**
-** This function - unixLogErrorAtLine(), is only ever called via the macro
+** This function - unixLogError_x(), is only ever called via the macro
** unixLogError().
**
** It is invoked after an error occurs in an OS function and errno has been
@@ -30367,7 +26709,7 @@ static int findInodeInfo(
rc = osFstat(fd, &statbuf);
if( rc!=0 ){
storeLastErrno(pFile, errno);
-#if defined(EOVERFLOW) && defined(SQLITE_DISABLE_LFS)
+#ifdef EOVERFLOW
if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS;
#endif
return SQLITE_IOERR;
@@ -30412,7 +26754,7 @@ static int findInodeInfo(
if( pInode==0 ){
pInode = sqlite3_malloc64( sizeof(*pInode) );
if( pInode==0 ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
memset(pInode, 0, sizeof(*pInode));
memcpy(&pInode->fileId, &fileId, sizeof(fileId));
@@ -30454,25 +26796,30 @@ static int fileHasMoved(unixFile *pFile){
static void verifyDbFile(unixFile *pFile){
struct stat buf;
int rc;
-
- /* These verifications occurs for the main database only */
- if( pFile->ctrlFlags & UNIXFILE_NOLOCK ) return;
-
+ if( pFile->ctrlFlags & UNIXFILE_WARNED ){
+ /* One or more of the following warnings have already been issued. Do not
+ ** repeat them so as not to clutter the error log */
+ return;
+ }
rc = osFstat(pFile->h, &buf);
if( rc!=0 ){
sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s", pFile->zPath);
+ pFile->ctrlFlags |= UNIXFILE_WARNED;
return;
}
- if( buf.st_nlink==0 ){
+ if( buf.st_nlink==0 && (pFile->ctrlFlags & UNIXFILE_DELETE)==0 ){
sqlite3_log(SQLITE_WARNING, "file unlinked while open: %s", pFile->zPath);
+ pFile->ctrlFlags |= UNIXFILE_WARNED;
return;
}
if( buf.st_nlink>1 ){
sqlite3_log(SQLITE_WARNING, "multiple links to file: %s", pFile->zPath);
+ pFile->ctrlFlags |= UNIXFILE_WARNED;
return;
}
if( fileHasMoved(pFile) ){
sqlite3_log(SQLITE_WARNING, "file renamed while open: %s", pFile->zPath);
+ pFile->ctrlFlags |= UNIXFILE_WARNED;
return;
}
}
@@ -30492,7 +26839,6 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
assert( pFile );
- assert( pFile->eFileLock<=SHARED_LOCK );
unixEnterMutex(); /* Because pFile->pInode is shared across threads */
/* Check if a thread in this process holds such a lock */
@@ -30549,7 +26895,9 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){
unixInodeInfo *pInode = pFile->pInode;
assert( unixMutexHeld() );
assert( pInode!=0 );
- if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){
+ if( ((pFile->ctrlFlags & UNIXFILE_EXCL)!=0 || pInode->bProcessLock)
+ && ((pFile->ctrlFlags & UNIXFILE_RDONLY)==0)
+ ){
if( pInode->bProcessLock==0 ){
struct flock lock;
assert( pInode->nLock==0 );
@@ -30599,7 +26947,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
** lock transitions in terms of the POSIX advisory shared and exclusive
** lock primitives (called read-locks and write-locks below, to avoid
** confusion with SQLite lock names). The algorithms are complicated
- ** slightly in order to be compatible with Windows95 systems simultaneously
+ ** slightly in order to be compatible with windows systems simultaneously
** accessing the same database file, in case that is ever required.
**
** Symbols defined in os.h indentify the 'pending byte' and the 'reserved
@@ -30607,14 +26955,8 @@ static int unixLock(sqlite3_file *id, int eFileLock){
** range', a range of 510 bytes at a well known offset.
**
** To obtain a SHARED lock, a read-lock is obtained on the 'pending
- ** byte'. If this is successful, 'shared byte range' is read-locked
- ** and the lock on the 'pending byte' released. (Legacy note: When
- ** SQLite was first developed, Windows95 systems were still very common,
- ** and Widnows95 lacks a shared-lock capability. So on Windows95, a
- ** single randomly selected by from the 'shared byte range' is locked.
- ** Windows95 is now pretty much extinct, but this work-around for the
- ** lack of shared-locks on Windows95 lives on, for backwards
- ** compatibility.)
+ ** byte'. If this is successful, a random byte from the 'shared byte
+ ** range' is read-locked and the lock on the 'pending byte' released.
**
** A process may only obtain a RESERVED lock after it has a SHARED lock.
** A RESERVED lock is implemented by grabbing a write-lock on the
@@ -30633,6 +26975,11 @@ static int unixLock(sqlite3_file *id, int eFileLock){
** range'. Since all other locks require a read-lock on one of the bytes
** within this range, this ensures that no other locks are held on the
** database.
+ **
+ ** The reason a single byte cannot be used instead of the 'shared byte
+ ** range' is that some versions of windows do not support read-locks. By
+ ** locking a random byte from a range, concurrent SHARED locks may exist
+ ** even if the locking primitive used is always a write-lock.
*/
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
@@ -30902,7 +27249,9 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
if( unixFileLock(pFile, &lock)==(-1) ){
tErrno = errno;
rc = SQLITE_IOERR_UNLOCK;
- storeLastErrno(pFile, tErrno);
+ if( IS_LOCK_ERROR(rc) ){
+ storeLastErrno(pFile, tErrno);
+ }
goto end_unlock;
}
lock.l_type = F_RDLCK;
@@ -30924,7 +27273,9 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
if( unixFileLock(pFile, &lock)==(-1) ){
tErrno = errno;
rc = SQLITE_IOERR_UNLOCK;
- storeLastErrno(pFile, tErrno);
+ if( IS_LOCK_ERROR(rc) ){
+ storeLastErrno(pFile, tErrno);
+ }
goto end_unlock;
}
}else
@@ -31175,7 +27526,17 @@ static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) {
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
assert( pFile );
- reserved = osAccess((const char*)pFile->lockingContext, 0)==0;
+
+ /* Check if a thread in this process holds such a lock */
+ if( pFile->eFileLock>SHARED_LOCK ){
+ /* Either this connection or some other connection in the same process
+ ** holds a lock on the file. No need to check further. */
+ reserved = 1;
+ }else{
+ /* The lock is held if and only if the lockfile exists */
+ const char *zLockFile = (const char*)pFile->lockingContext;
+ reserved = osAccess(zLockFile, 0)==0;
+ }
OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved));
*pResOut = reserved;
return rc;
@@ -31237,7 +27598,7 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) {
rc = SQLITE_BUSY;
} else {
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
- if( rc!=SQLITE_BUSY ){
+ if( IS_LOCK_ERROR(rc) ){
storeLastErrno(pFile, tErrno);
}
}
@@ -31284,12 +27645,14 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
/* To fully unlock the database, delete the lock file */
assert( eFileLock==NO_LOCK );
rc = osRmdir(zLockFile);
+ if( rc<0 && errno==ENOTDIR ) rc = osUnlink(zLockFile);
if( rc<0 ){
int tErrno = errno;
- if( tErrno==ENOENT ){
- rc = SQLITE_OK;
- }else{
+ rc = 0;
+ if( ENOENT != tErrno ){
rc = SQLITE_IOERR_UNLOCK;
+ }
+ if( IS_LOCK_ERROR(rc) ){
storeLastErrno(pFile, tErrno);
}
return rc;
@@ -31302,11 +27665,14 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
** Close a file. Make sure the lock has been released before closing.
*/
static int dotlockClose(sqlite3_file *id) {
- unixFile *pFile = (unixFile*)id;
- assert( id!=0 );
- dotlockUnlock(id, NO_LOCK);
- sqlite3_free(pFile->lockingContext);
- return closeUnixFile(id);
+ int rc = SQLITE_OK;
+ if( id ){
+ unixFile *pFile = (unixFile*)id;
+ dotlockUnlock(id, NO_LOCK);
+ sqlite3_free(pFile->lockingContext);
+ rc = closeUnixFile(id);
+ }
+ return rc;
}
/****************** End of the dot-file lock implementation *******************
******************************************************************************/
@@ -31372,8 +27738,10 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
int tErrno = errno;
/* unlock failed with an error */
lrc = SQLITE_IOERR_UNLOCK;
- storeLastErrno(pFile, tErrno);
- rc = lrc;
+ if( IS_LOCK_ERROR(lrc) ){
+ storeLastErrno(pFile, tErrno);
+ rc = lrc;
+ }
}
} else {
int tErrno = errno;
@@ -31506,9 +27874,12 @@ static int flockUnlock(sqlite3_file *id, int eFileLock) {
** Close a file.
*/
static int flockClose(sqlite3_file *id) {
- assert( id!=0 );
- flockUnlock(id, NO_LOCK);
- return closeUnixFile(id);
+ int rc = SQLITE_OK;
+ if( id ){
+ flockUnlock(id, NO_LOCK);
+ rc = closeUnixFile(id);
+ }
+ return rc;
}
#endif /* SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORK */
@@ -32133,22 +28504,23 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
*/
static int afpClose(sqlite3_file *id) {
int rc = SQLITE_OK;
- unixFile *pFile = (unixFile*)id;
- assert( id!=0 );
- afpUnlock(id, NO_LOCK);
- unixEnterMutex();
- if( pFile->pInode && pFile->pInode->nLock ){
- /* If there are outstanding locks, do not actually close the file just
- ** yet because that would clear those locks. Instead, add the file
- ** descriptor to pInode->aPending. It will be automatically closed when
- ** the last lock is cleared.
- */
- setPendingFd(pFile);
+ if( id ){
+ unixFile *pFile = (unixFile*)id;
+ afpUnlock(id, NO_LOCK);
+ unixEnterMutex();
+ if( pFile->pInode && pFile->pInode->nLock ){
+ /* If there are outstanding locks, do not actually close the file just
+ ** yet because that would clear those locks. Instead, add the file
+ ** descriptor to pInode->aPending. It will be automatically closed when
+ ** the last lock is cleared.
+ */
+ setPendingFd(pFile);
+ }
+ releaseInodeInfo(pFile);
+ sqlite3_free(pFile->lockingContext);
+ rc = closeUnixFile(id);
+ unixLeaveMutex();
}
- releaseInodeInfo(pFile);
- sqlite3_free(pFile->lockingContext);
- rc = closeUnixFile(id);
- unixLeaveMutex();
return rc;
}
@@ -32218,6 +28590,7 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
TIMER_START;
assert( cnt==(cnt&0x1ffff) );
assert( id->h>2 );
+ cnt &= 0x1ffff;
do{
#if defined(USE_PREAD)
got = osPread(id->h, pBuf, cnt, offset);
@@ -32227,9 +28600,13 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
SimulateIOError( got = -1 );
#else
newOffset = lseek(id->h, offset, SEEK_SET);
- SimulateIOError( newOffset = -1 );
- if( newOffset<0 ){
- storeLastErrno((unixFile*)id, errno);
+ SimulateIOError( newOffset-- );
+ if( newOffset!=offset ){
+ if( newOffset == -1 ){
+ storeLastErrno((unixFile*)id, errno);
+ }else{
+ storeLastErrno((unixFile*)id, 0);
+ }
return -1;
}
got = osRead(id->h, pBuf, cnt);
@@ -32280,7 +28657,7 @@ static int unixRead(
#endif
#if SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this read request as possible by transfering
+ /* Deal with as much of this read request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -32328,7 +28705,6 @@ static int seekAndWriteFd(
assert( nBuf==(nBuf&0x1ffff) );
assert( fd>2 );
- assert( piErrno!=0 );
nBuf &= 0x1ffff;
TIMER_START;
@@ -32339,10 +28715,11 @@ static int seekAndWriteFd(
#else
do{
i64 iSeek = lseek(fd, iOff, SEEK_SET);
- SimulateIOError( iSeek = -1 );
- if( iSeek<0 ){
- rc = -1;
- break;
+ SimulateIOError( iSeek-- );
+
+ if( iSeek!=iOff ){
+ if( piErrno ) *piErrno = (iSeek==-1 ? errno : 0);
+ return -1;
}
rc = osWrite(fd, pBuf, nBuf);
}while( rc<0 && errno==EINTR );
@@ -32351,7 +28728,7 @@ static int seekAndWriteFd(
TIMER_END;
OSTRACE(("WRITE %-3d %5d %7lld %llu\n", fd, rc, iOff, TIMER_ELAPSED));
- if( rc<0 ) *piErrno = errno;
+ if( rc<0 && piErrno ) *piErrno = errno;
return rc;
}
@@ -32414,8 +28791,8 @@ static int unixWrite(
}
#endif
-#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this write request as possible by transfering
+#if SQLITE_MAX_MMAP_SIZE>0
+ /* Deal with as much of this write request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -32430,8 +28807,8 @@ static int unixWrite(
}
}
#endif
-
- while( (wrote = seekAndWrite(pFile, offset, pBuf, amt))<amt && wrote>0 ){
+
+ while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){
amt -= wrote;
offset += wrote;
pBuf = &((char*)pBuf)[wrote];
@@ -32439,7 +28816,7 @@ static int unixWrite(
SimulateIOError(( wrote=(-1), amt=1 ));
SimulateDiskfullError(( wrote=0, amt=1 ));
- if( amt>wrote ){
+ if( amt>0 ){
if( wrote<0 && pFile->lastErrno!=ENOSPC ){
/* lastErrno set by seekAndWrite */
return SQLITE_IOERR_WRITE;
@@ -32535,15 +28912,10 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
#endif
/* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
- ** no-op. But go ahead and call fstat() to validate the file
- ** descriptor as we need a method to provoke a failure during
- ** coverate testing.
+ ** no-op
*/
#ifdef SQLITE_NO_SYNC
- {
- struct stat buf;
- rc = osFstat(fd, &buf);
- }
+ rc = SQLITE_OK;
#elif HAVE_FULLFSYNC
if( fullSync ){
rc = osFcntl(fd, F_FULLFSYNC, 0);
@@ -32609,20 +28981,16 @@ static int openDirectory(const char *zFilename, int *pFd){
char zDirname[MAX_PATHNAME+1];
sqlite3_snprintf(MAX_PATHNAME, zDirname, "%s", zFilename);
- for(ii=(int)strlen(zDirname); ii>0 && zDirname[ii]!='/'; ii--);
+ for(ii=(int)strlen(zDirname); ii>1 && zDirname[ii]!='/'; ii--);
if( ii>0 ){
zDirname[ii] = '\0';
- }else{
- if( zDirname[0]!='/' ) zDirname[0] = '.';
- zDirname[1] = 0;
- }
- fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0);
- if( fd>=0 ){
- OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
+ fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0);
+ if( fd>=0 ){
+ OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
+ }
}
*pFd = fd;
- if( fd>=0 ) return SQLITE_OK;
- return unixLogError(SQLITE_CANTOPEN_BKPT, "openDirectory", zDirname);
+ return (fd>=0?SQLITE_OK:unixLogError(SQLITE_CANTOPEN_BKPT, "open", zDirname));
}
/*
@@ -32675,11 +29043,10 @@ static int unixSync(sqlite3_file *id, int flags){
OSTRACE(("DIRSYNC %s (have_fullfsync=%d fullsync=%d)\n", pFile->zPath,
HAVE_FULLFSYNC, isFullsync));
rc = osOpenDirectory(pFile->zPath, &dirfd);
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK && dirfd>=0 ){
full_fsync(dirfd, 0, 0);
robust_close(pFile, dirfd, __LINE__);
- }else{
- assert( rc==SQLITE_CANTOPEN );
+ }else if( rc==SQLITE_CANTOPEN ){
rc = SQLITE_OK;
}
pFile->ctrlFlags &= ~UNIXFILE_DIRSYNC;
@@ -32811,14 +29178,18 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
int nWrite = 0; /* Number of bytes written by seekAndWrite */
i64 iWrite; /* Next offset to write to */
- iWrite = (buf.st_size/nBlk)*nBlk + nBlk - 1;
+ iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;
assert( iWrite>=buf.st_size );
+ assert( (iWrite/nBlk)==((buf.st_size+nBlk-1)/nBlk) );
assert( ((iWrite+1)%nBlk)==0 );
- for(/*no-op*/; iWrite<nSize+nBlk-1; iWrite+=nBlk ){
- if( iWrite>=nSize ) iWrite = nSize - 1;
+ for(/*no-op*/; iWrite<nSize; iWrite+=nBlk ){
nWrite = seekAndWrite(pFile, iWrite, "", 1);
if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
}
+ if( nWrite==0 || (nSize%nBlk) ){
+ nWrite = seekAndWrite(pFile, nSize-1, "", 1);
+ if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
+ }
#endif
}
}
@@ -32866,6 +29237,10 @@ static int unixGetTempname(int nBuf, char *zBuf);
static int unixFileControl(sqlite3_file *id, int op, void *pArg){
unixFile *pFile = (unixFile*)id;
switch( op ){
+ case SQLITE_FCNTL_WAL_BLOCK: {
+ /* pFile->ctrlFlags |= UNIXFILE_BLOCK; // Deferred feature */
+ return SQLITE_OK;
+ }
case SQLITE_FCNTL_LOCKSTATE: {
*(int*)pArg = pFile->eFileLock;
return SQLITE_OK;
@@ -33192,9 +29567,10 @@ static int unixShmSystemLock(
assert( n==1 || lockType!=F_RDLCK );
/* Locks are within range */
- assert( n>=1 && n<=SQLITE_SHM_NLOCK );
+ assert( n>=1 && n<SQLITE_SHM_NLOCK );
if( pShmNode->h>=0 ){
+ int lkType;
/* Initialize the locking parameters */
memset(&f, 0, sizeof(f));
f.l_type = lockType;
@@ -33202,8 +29578,10 @@ static int unixShmSystemLock(
f.l_start = ofst;
f.l_len = n;
- rc = osFcntl(pShmNode->h, F_SETLK, &f);
+ lkType = (pFile->ctrlFlags & UNIXFILE_BLOCK)!=0 ? F_SETLKW : F_SETLK;
+ rc = osFcntl(pShmNode->h, lkType, &f);
rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
+ pFile->ctrlFlags &= ~UNIXFILE_BLOCK;
}
/* Update the global lock state and do debug tracing */
@@ -33270,7 +29648,7 @@ static int unixShmRegionPerMap(void){
static void unixShmPurge(unixFile *pFd){
unixShmNode *p = pFd->pInode->pShmNode;
assert( unixMutexHeld() );
- if( p && ALWAYS(p->nRef==0) ){
+ if( p && p->nRef==0 ){
int nShmPerMap = unixShmRegionPerMap();
int i;
assert( p->pInode==pFd->pInode );
@@ -33337,7 +29715,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
/* Allocate space for the new unixShm object. */
p = sqlite3_malloc64( sizeof(*p) );
- if( p==0 ) return SQLITE_NOMEM_BKPT;
+ if( p==0 ) return SQLITE_NOMEM;
memset(p, 0, sizeof(*p));
assert( pDbFd->pShm==0 );
@@ -33357,7 +29735,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
** a new *-shm file is created, an attempt will be made to create it
** with the same permissions.
*/
- if( osFstat(pDbFd->h, &sStat) ){
+ if( osFstat(pDbFd->h, &sStat) && pInode->bProcessLock==0 ){
rc = SQLITE_IOERR_FSTAT;
goto shm_open_err;
}
@@ -33369,7 +29747,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
#endif
pShmNode = sqlite3_malloc64( sizeof(*pShmNode) + nShmFilename );
if( pShmNode==0 ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
goto shm_open_err;
}
memset(pShmNode, 0, sizeof(*pShmNode)+nShmFilename);
@@ -33385,12 +29763,10 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
pShmNode->h = -1;
pDbFd->pInode->pShmNode = pShmNode;
pShmNode->pInode = pDbFd->pInode;
- if( sqlite3GlobalConfig.bCoreMutex ){
- pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
- if( pShmNode->mutex==0 ){
- rc = SQLITE_NOMEM_BKPT;
- goto shm_open_err;
- }
+ pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ if( pShmNode->mutex==0 ){
+ rc = SQLITE_NOMEM;
+ goto shm_open_err;
}
if( pInode->bProcessLock==0 ){
@@ -33409,7 +29785,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
** is owned by the same user that owns the original database. Otherwise,
** the original owner will not be able to connect.
*/
- robustFchown(pShmNode->h, sStat.st_uid, sStat.st_gid);
+ osFchown(pShmNode->h, sStat.st_uid, sStat.st_gid);
/* Check to see if another process is holding the dead-man switch.
** If not, truncate the file to zero length.
@@ -33546,8 +29922,7 @@ static int unixShmMap(
/* Write to the last byte of each newly allocated or extended page */
assert( (nByte % pgsz)==0 );
for(iPg=(sStat.st_size/pgsz); iPg<(nByte/pgsz); iPg++){
- int x = 0;
- if( seekAndWriteFd(pShmNode->h, iPg*pgsz + pgsz-1, "", 1, &x)!=1 ){
+ if( seekAndWriteFd(pShmNode->h, iPg*pgsz + pgsz-1, "", 1, 0)!=1 ){
const char *zFile = pShmNode->zFilename;
rc = unixLogError(SQLITE_IOERR_SHMSIZE, "write", zFile);
goto shmpage_out;
@@ -33562,7 +29937,7 @@ static int unixShmMap(
pShmNode->apRegion, nReqRegion*sizeof(char *)
);
if( !apNew ){
- rc = SQLITE_IOERR_NOMEM_BKPT;
+ rc = SQLITE_IOERR_NOMEM;
goto shmpage_out;
}
pShmNode->apRegion = apNew;
@@ -33582,7 +29957,7 @@ static int unixShmMap(
}else{
pMem = sqlite3_malloc64(szRegion);
if( pMem==0 ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
goto shmpage_out;
}
memset(pMem, 0, szRegion);
@@ -33730,8 +30105,7 @@ static void unixShmBarrier(
sqlite3_file *fd /* Database file holding the shared memory */
){
UNUSED_PARAMETER(fd);
- sqlite3MemoryBarrier(); /* compiler-defined memory barrier */
- unixEnterMutex(); /* Also mutex, for redundancy */
+ unixEnterMutex();
unixLeaveMutex();
}
@@ -33841,9 +30215,7 @@ static void unixRemapfile(
assert( pFd->mmapSizeActual>=pFd->mmapSize );
assert( MAP_FAILED!=0 );
-#ifdef SQLITE_MMAP_READWRITE
if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
-#endif
if( pOrig ){
#if HAVE_MREMAP
@@ -33915,14 +30287,17 @@ static void unixRemapfile(
** recreated as a result of outstanding references) or an SQLite error
** code otherwise.
*/
-static int unixMapfile(unixFile *pFd, i64 nMap){
+static int unixMapfile(unixFile *pFd, i64 nByte){
+ i64 nMap = nByte;
+ int rc;
+
assert( nMap>=0 || pFd->nFetchOut==0 );
- assert( nMap>0 || (pFd->mmapSize==0 && pFd->pMapRegion==0) );
if( pFd->nFetchOut>0 ) return SQLITE_OK;
if( nMap<0 ){
struct stat statbuf; /* Low-level file information */
- if( osFstat(pFd->h, &statbuf) ){
+ rc = osFstat(pFd->h, &statbuf);
+ if( rc!=SQLITE_OK ){
return SQLITE_IOERR_FSTAT;
}
nMap = statbuf.st_size;
@@ -33931,9 +30306,12 @@ static int unixMapfile(unixFile *pFd, i64 nMap){
nMap = pFd->mmapSizeMax;
}
- assert( nMap>0 || (pFd->mmapSize==0 && pFd->pMapRegion==0) );
if( nMap!=pFd->mmapSize ){
- unixRemapfile(pFd, nMap);
+ if( nMap>0 ){
+ unixRemapfile(pFd, nMap);
+ }else{
+ unixUnmapfile(pFd);
+ }
}
return SQLITE_OK;
@@ -34360,7 +30738,7 @@ static int fillInUnixFile(
pNew->pId = vxworksFindFileId(zFilename);
if( pNew->pId==0 ){
ctrlFlags |= UNIXFILE_NOLOCK;
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}
#endif
@@ -34416,7 +30794,7 @@ static int fillInUnixFile(
afpLockingContext *pCtx;
pNew->lockingContext = pCtx = sqlite3_malloc64( sizeof(*pCtx) );
if( pCtx==0 ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}else{
/* NB: zFilename exists and remains valid until the file is closed
** according to requirement F11141. So we do not need to make a
@@ -34446,7 +30824,7 @@ static int fillInUnixFile(
nFilename = (int)strlen(zFilename) + 6;
zLockFile = (char *)sqlite3_malloc64(nFilename);
if( zLockFile==0 ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}else{
sqlite3_snprintf(nFilename, zLockFile, "%s" DOTLOCK_SUFFIX, zFilename);
}
@@ -34469,7 +30847,7 @@ static int fillInUnixFile(
if( zSemName[n]=='/' ) zSemName[n] = '_';
pNew->pInode->pSem = sem_open(zSemName, O_CREAT, 0666, 1);
if( pNew->pInode->pSem == SEM_FAILED ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
pNew->pInode->aSemName[0] = '\0';
}
}
@@ -34504,29 +30882,27 @@ static const char *unixTempFileDir(void){
static const char *azDirs[] = {
0,
0,
+ 0,
"/var/tmp",
"/usr/tmp",
"/tmp",
- "."
+ 0 /* List terminator */
};
- unsigned int i = 0;
+ unsigned int i;
struct stat buf;
- const char *zDir = sqlite3_temp_directory;
-
- if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR");
- if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
- while(1){
- if( zDir!=0
- && osStat(zDir, &buf)==0
- && S_ISDIR(buf.st_mode)
- && osAccess(zDir, 03)==0
- ){
- return zDir;
- }
- if( i>=sizeof(azDirs)/sizeof(azDirs[0]) ) break;
- zDir = azDirs[i++];
+ const char *zDir = 0;
+
+ azDirs[0] = sqlite3_temp_directory;
+ if( !azDirs[1] ) azDirs[1] = getenv("SQLITE_TMPDIR");
+ if( !azDirs[2] ) azDirs[2] = getenv("TMPDIR");
+ for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
+ if( zDir==0 ) continue;
+ if( osStat(zDir, &buf) ) continue;
+ if( !S_ISDIR(buf.st_mode) ) continue;
+ if( osAccess(zDir, 07) ) continue;
+ break;
}
- return 0;
+ return zDir;
}
/*
@@ -34535,26 +30911,38 @@ static const char *unixTempFileDir(void){
** pVfs->mxPathname bytes.
*/
static int unixGetTempname(int nBuf, char *zBuf){
+ static const unsigned char zChars[] =
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789";
+ unsigned int i, j;
const char *zDir;
- int iLimit = 0;
/* It's odd to simulate an io-error here, but really this is just
** using the io-error infrastructure to test that SQLite handles this
** function failing.
*/
- zBuf[0] = 0;
SimulateIOError( return SQLITE_IOERR );
zDir = unixTempFileDir();
- if( zDir==0 ) return SQLITE_IOERR_GETTEMPPATH;
+ if( zDir==0 ) zDir = ".";
+
+ /* Check that the output buffer is large enough for the temporary file
+ ** name. If it is not, return SQLITE_ERROR.
+ */
+ if( (strlen(zDir) + strlen(SQLITE_TEMP_FILE_PREFIX) + 18) >= (size_t)nBuf ){
+ return SQLITE_ERROR;
+ }
+
do{
- u64 r;
- sqlite3_randomness(sizeof(r), &r);
- assert( nBuf>2 );
- zBuf[nBuf-2] = 0;
- sqlite3_snprintf(nBuf, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX"%llx%c",
- zDir, r, 0);
- if( zBuf[nBuf-2]!=0 || (iLimit++)>10 ) return SQLITE_ERROR;
+ sqlite3_snprintf(nBuf-18, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX, zDir);
+ j = (int)strlen(zBuf);
+ sqlite3_randomness(15, &zBuf[j]);
+ for(i=0; i<15; i++, j++){
+ zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
+ }
+ zBuf[j] = 0;
+ zBuf[j+1] = 0;
}while( osAccess(zBuf,0)==0 );
return SQLITE_OK;
}
@@ -34676,19 +31064,16 @@ static int findCreateFileMode(
** used by the test_multiplex.c module.
*/
nDb = sqlite3Strlen30(zPath) - 1;
+#ifdef SQLITE_ENABLE_8_3_NAMES
+ while( nDb>0 && sqlite3Isalnum(zPath[nDb]) ) nDb--;
+ if( nDb==0 || zPath[nDb]!='-' ) return SQLITE_OK;
+#else
while( zPath[nDb]!='-' ){
-#ifndef SQLITE_ENABLE_8_3_NAMES
- /* In the normal case (8+3 filenames disabled) the journal filename
- ** is guaranteed to contain a '-' character. */
assert( nDb>0 );
- assert( sqlite3Isalnum(zPath[nDb]) );
-#else
- /* If 8+3 names are possible, then the journal file might not contain
- ** a '-' character. So check for that case and return early. */
- if( nDb==0 || zPath[nDb]=='.' ) return SQLITE_OK;
-#endif
+ assert( zPath[nDb]!='\n' );
nDb--;
}
+#endif
memcpy(zDb, zPath, nDb);
zDb[nDb] = '\0';
@@ -34816,7 +31201,7 @@ static int unixOpen(
}else{
pUnused = sqlite3_malloc64(sizeof(*pUnused));
if( !pUnused ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
}
p->pUnused = pUnused;
@@ -34829,7 +31214,7 @@ static int unixOpen(
}else if( !zName ){
/* If zName is NULL, the upper layer is requesting a temp file. */
assert(isDelete && !syncDir);
- rc = unixGetTempname(pVfs->mxPathname, zTmpname);
+ rc = unixGetTempname(MAX_PATHNAME+2, zTmpname);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -34862,8 +31247,7 @@ static int unixOpen(
}
fd = robust_open(zName, openFlags, openMode);
OSTRACE(("OPENX %-3d %s 0%o\n", fd, zName, openFlags));
- assert( !isExclusive || (openFlags & O_CREAT)!=0 );
- if( fd<0 && errno!=EISDIR && isReadWrite ){
+ if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
/* Failed to open the file for read/write access. Try read-only. */
flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
openFlags &= ~(O_RDWR|O_CREAT);
@@ -34882,7 +31266,7 @@ static int unixOpen(
** the same as the original database.
*/
if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
- robustFchown(fd, uid, gid);
+ osFchown(fd, uid, gid);
}
}
assert( fd>=0 );
@@ -34902,7 +31286,7 @@ static int unixOpen(
zPath = sqlite3_mprintf("%s", zName);
if( zPath==0 ){
robust_close(p, fd, __LINE__);
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
#else
osUnlink(zName);
@@ -34913,6 +31297,9 @@ static int unixOpen(
p->openFlags = openFlags;
}
#endif
+
+ noLock = eType!=SQLITE_OPEN_MAIN_DB;
+
#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
if( fstatfs(fd, &fsInfo) == -1 ){
@@ -34931,7 +31318,6 @@ static int unixOpen(
/* Set up appropriate ctrlFlags */
if( isDelete ) ctrlFlags |= UNIXFILE_DELETE;
if( isReadonly ) ctrlFlags |= UNIXFILE_RDONLY;
- noLock = eType!=SQLITE_OPEN_MAIN_DB;
if( noLock ) ctrlFlags |= UNIXFILE_NOLOCK;
if( syncDir ) ctrlFlags |= UNIXFILE_DIRSYNC;
if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI;
@@ -35008,12 +31394,16 @@ static int unixDelete(
int fd;
rc = osOpenDirectory(zPath, &fd);
if( rc==SQLITE_OK ){
- if( full_fsync(fd,0,0) ){
+#if OS_VXWORKS
+ if( fsync(fd)==-1 )
+#else
+ if( fsync(fd) )
+#endif
+ {
rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath);
}
robust_close(0, fd, __LINE__);
- }else{
- assert( rc==SQLITE_CANTOPEN );
+ }else if( rc==SQLITE_CANTOPEN ){
rc = SQLITE_OK;
}
}
@@ -35037,50 +31427,34 @@ static int unixAccess(
int flags, /* What do we want to learn about the zPath file? */
int *pResOut /* Write result boolean here */
){
+ int amode = 0;
UNUSED_PARAMETER(NotUsed);
SimulateIOError( return SQLITE_IOERR_ACCESS; );
- assert( pResOut!=0 );
-
- /* The spec says there are three possible values for flags. But only
- ** two of them are actually used */
- assert( flags==SQLITE_ACCESS_EXISTS || flags==SQLITE_ACCESS_READWRITE );
+ switch( flags ){
+ case SQLITE_ACCESS_EXISTS:
+ amode = F_OK;
+ break;
+ case SQLITE_ACCESS_READWRITE:
+ amode = W_OK|R_OK;
+ break;
+ case SQLITE_ACCESS_READ:
+ amode = R_OK;
+ break;
- if( flags==SQLITE_ACCESS_EXISTS ){
- struct stat buf;
- *pResOut = (0==osStat(zPath, &buf) && buf.st_size>0);
- }else{
- *pResOut = osAccess(zPath, W_OK|R_OK)==0;
+ default:
+ assert(!"Invalid flags argument");
}
- return SQLITE_OK;
-}
-
-/*
-**
-*/
-static int mkFullPathname(
- const char *zPath, /* Input path */
- char *zOut, /* Output buffer */
- int nOut /* Allocated size of buffer zOut */
-){
- int nPath = sqlite3Strlen30(zPath);
- int iOff = 0;
- if( zPath[0]!='/' ){
- if( osGetcwd(zOut, nOut-2)==0 ){
- return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
+ *pResOut = (osAccess(zPath, amode)==0);
+ if( flags==SQLITE_ACCESS_EXISTS && *pResOut ){
+ struct stat buf;
+ if( 0==osStat(zPath, &buf) && buf.st_size==0 ){
+ *pResOut = 0;
}
- iOff = sqlite3Strlen30(zOut);
- zOut[iOff++] = '/';
- }
- if( (iOff+nPath+1)>nOut ){
- /* SQLite assumes that xFullPathname() nul-terminates the output buffer
- ** even if it returns an error. */
- zOut[iOff] = '\0';
- return SQLITE_CANTOPEN_BKPT;
}
- sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath);
return SQLITE_OK;
}
+
/*
** Turn a relative pathname into a full pathname. The relative path
** is stored as a nul-terminated string in the buffer pointed to by
@@ -35096,17 +31470,6 @@ static int unixFullPathname(
int nOut, /* Size of output buffer in bytes */
char *zOut /* Output buffer */
){
-#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT)
- return mkFullPathname(zPath, zOut, nOut);
-#else
- int rc = SQLITE_OK;
- int nByte;
- int nLink = 1; /* Number of symbolic links followed so far */
- const char *zIn = zPath; /* Input path for each iteration of loop */
- char *zDel = 0;
-
- assert( pVfs->mxPathname==MAX_PATHNAME );
- UNUSED_PARAMETER(pVfs);
/* It's odd to simulate an io-error here, but really this is just
** using the io-error infrastructure to test that SQLite handles this
@@ -35115,62 +31478,21 @@ static int unixFullPathname(
*/
SimulateIOError( return SQLITE_ERROR );
- do {
-
- /* Call stat() on path zIn. Set bLink to true if the path is a symbolic
- ** link, or false otherwise. */
- int bLink = 0;
- struct stat buf;
- if( osLstat(zIn, &buf)!=0 ){
- if( errno!=ENOENT ){
- rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn);
- }
- }else{
- bLink = S_ISLNK(buf.st_mode);
- }
-
- if( bLink ){
- if( zDel==0 ){
- zDel = sqlite3_malloc(nOut);
- if( zDel==0 ) rc = SQLITE_NOMEM_BKPT;
- }else if( ++nLink>SQLITE_MAX_SYMLINKS ){
- rc = SQLITE_CANTOPEN_BKPT;
- }
-
- if( rc==SQLITE_OK ){
- nByte = osReadlink(zIn, zDel, nOut-1);
- if( nByte<0 ){
- rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn);
- }else{
- if( zDel[0]!='/' ){
- int n;
- for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--);
- if( nByte+n+1>nOut ){
- rc = SQLITE_CANTOPEN_BKPT;
- }else{
- memmove(&zDel[n], zDel, nByte+1);
- memcpy(zDel, zIn, n);
- nByte += n;
- }
- }
- zDel[nByte] = '\0';
- }
- }
-
- zIn = zDel;
- }
+ assert( pVfs->mxPathname==MAX_PATHNAME );
+ UNUSED_PARAMETER(pVfs);
- assert( rc!=SQLITE_OK || zIn!=zOut || zIn[0]=='/' );
- if( rc==SQLITE_OK && zIn!=zOut ){
- rc = mkFullPathname(zIn, zOut, nOut);
+ zOut[nOut-1] = '\0';
+ if( zPath[0]=='/' ){
+ sqlite3_snprintf(nOut, zOut, "%s", zPath);
+ }else{
+ int nCwd;
+ if( osGetcwd(zOut, nOut-1)==0 ){
+ return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
}
- if( bLink==0 ) break;
- zIn = zOut;
- }while( rc==SQLITE_OK );
-
- sqlite3_free(zDel);
- return rc;
-#endif /* HAVE_READLINK && HAVE_LSTAT */
+ nCwd = (int)strlen(zOut);
+ sqlite3_snprintf(nOut-nCwd, &zOut[nCwd], "/%s", zPath);
+ }
+ return SQLITE_OK;
}
@@ -35339,8 +31661,11 @@ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
*piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_nsec/1000000;
#else
struct timeval sNow;
- (void)gettimeofday(&sNow, 0); /* Cannot fail given valid arguments */
- *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
+ if( gettimeofday(&sNow, 0)==0 ){
+ *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
+ }else{
+ rc = SQLITE_ERROR;
+ }
#endif
#ifdef SQLITE_TEST
@@ -35352,7 +31677,6 @@ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
return rc;
}
-#ifndef SQLITE_OMIT_DEPRECATED
/*
** Find the current time (in Universal Coordinated Time). Write the
** current time and date as a Julian Day number into *prNow and
@@ -35366,21 +31690,19 @@ static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){
*prNow = i/86400000.0;
return rc;
}
-#else
-# define unixCurrentTime 0
-#endif
/*
-** The xGetLastError() method is designed to return a better
-** low-level error message when operating-system problems come up
-** during SQLite operation. Only the integer return code is currently
-** used.
+** We added the xGetLastError() method with the intention of providing
+** better low-level error messages when operating-system problems come up
+** during SQLite operation. But so far, none of that has been implemented
+** in the core. So this routine is never called. For now, it is merely
+** a place-holder.
*/
static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
UNUSED_PARAMETER(NotUsed);
UNUSED_PARAMETER(NotUsed2);
UNUSED_PARAMETER(NotUsed3);
- return errno;
+ return 0;
}
@@ -35635,7 +31957,7 @@ static int proxyCreateLockPath(const char *lockPath){
}
buf[i] = lockPath[i];
}
- OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n",lockPath,osGetpid(0)));
+ OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n", lockPath, osGetpid(0)));
return 0;
}
@@ -35671,7 +31993,7 @@ static int proxyCreateUnixFile(
}else{
pUnused = sqlite3_malloc64(sizeof(*pUnused));
if( !pUnused ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
}
if( fd<0 ){
@@ -35704,7 +32026,7 @@ static int proxyCreateUnixFile(
pNew = (unixFile *)sqlite3_malloc64(sizeof(*pNew));
if( pNew==NULL ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
goto end_create_proxy;
}
memset(pNew, 0, sizeof(unixFile));
@@ -36047,7 +32369,7 @@ static int proxyTakeConch(unixFile *pFile){
writeSize = PROXY_PATHINDEX + strlen(&writeBuffer[PROXY_PATHINDEX]);
robust_ftruncate(conchFile->h, writeSize);
rc = unixWrite((sqlite3_file *)conchFile, writeBuffer, writeSize, 0);
- full_fsync(conchFile->h,0,0);
+ fsync(conchFile->h);
/* If we created a new conch file (not just updated the contents of a
** valid conch file), try to match the permissions of the database
*/
@@ -36117,7 +32439,7 @@ static int proxyTakeConch(unixFile *pFile){
if( tempLockPath ){
pCtx->lockProxyPath = sqlite3DbStrDup(0, tempLockPath);
if( !pCtx->lockProxyPath ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}
}
}
@@ -36182,7 +32504,7 @@ static int proxyCreateConchPathname(char *dbPath, char **pConchPath){
** the name of the original database file. */
*pConchPath = conchPath = (char *)sqlite3_malloc64(len + 8);
if( conchPath==0 ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
memcpy(conchPath, dbPath, len+1);
@@ -36298,7 +32620,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
pCtx = sqlite3_malloc64( sizeof(*pCtx) );
if( pCtx==0 ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
memset(pCtx, 0, sizeof(*pCtx));
@@ -36334,7 +32656,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
if( rc==SQLITE_OK ){
pCtx->dbPath = sqlite3DbStrDup(0, dbPath);
if( pCtx->dbPath==NULL ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}
}
if( rc==SQLITE_OK ){
@@ -36520,7 +32842,7 @@ static int proxyUnlock(sqlite3_file *id, int eFileLock) {
** Close a file that uses proxy locks.
*/
static int proxyClose(sqlite3_file *id) {
- if( ALWAYS(id) ){
+ if( id ){
unixFile *pFile = (unixFile*)id;
proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
unixFile *lockProxy = pCtx->lockProxy;
@@ -36664,7 +32986,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
- assert( ArraySize(aSyscall)==28 );
+ assert( ArraySize(aSyscall)==25 );
/* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
@@ -36702,7 +33024,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
**
** This file contains code that is specific to Windows.
*/
-/* #include "sqliteInt.h" */
#if SQLITE_OS_WIN /* This file is used for Windows only */
/*
@@ -36747,8 +33068,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
*/
#ifdef SQLITE_PERFORMANCE_TRACE
-/*
-** hwtime.h contains inline assembler code for implementing
+/*
+** hwtime.h contains inline assembler code for implementing
** high-performance timing routines.
*/
/************** Include hwtime.h in the middle of os_common.h ****************/
@@ -36858,14 +33179,14 @@ static sqlite_uint64 g_elapsed;
** of code will give us the ability to simulate a disk I/O error. This
** is used for testing the I/O recovery logic.
*/
-#if defined(SQLITE_TEST)
-SQLITE_API extern int sqlite3_io_error_hit;
-SQLITE_API extern int sqlite3_io_error_hardhit;
-SQLITE_API extern int sqlite3_io_error_pending;
-SQLITE_API extern int sqlite3_io_error_persist;
-SQLITE_API extern int sqlite3_io_error_benign;
-SQLITE_API extern int sqlite3_diskfull_pending;
-SQLITE_API extern int sqlite3_diskfull;
+#ifdef SQLITE_TEST
+SQLITE_API int sqlite3_io_error_hit = 0; /* Total number of I/O Errors */
+SQLITE_API int sqlite3_io_error_hardhit = 0; /* Number of non-benign errors */
+SQLITE_API int sqlite3_io_error_pending = 0; /* Count down to first I/O error */
+SQLITE_API int sqlite3_io_error_persist = 0; /* True if I/O errors persist */
+SQLITE_API int sqlite3_io_error_benign = 0; /* True if errors are benign */
+SQLITE_API int sqlite3_diskfull_pending = 0;
+SQLITE_API int sqlite3_diskfull = 0;
#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
#define SimulateIOError(CODE) \
if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
@@ -36891,17 +33212,17 @@ static void local_ioerr(){
#define SimulateIOErrorBenign(X)
#define SimulateIOError(A)
#define SimulateDiskfullError(A)
-#endif /* defined(SQLITE_TEST) */
+#endif
/*
** When testing, keep a count of the number of open files.
*/
-#if defined(SQLITE_TEST)
-SQLITE_API extern int sqlite3_open_file_count;
+#ifdef SQLITE_TEST
+SQLITE_API int sqlite3_open_file_count = 0;
#define OpenCounter(X) sqlite3_open_file_count+=(X)
#else
#define OpenCounter(X)
-#endif /* defined(SQLITE_TEST) */
+#endif
#endif /* !defined(_OS_COMMON_H_) */
@@ -36911,7 +33232,6 @@ SQLITE_API extern int sqlite3_open_file_count;
/*
** Include the header file for the Windows VFS.
*/
-/* #include "os_win.h" */
/*
** Compiling and using WAL mode requires several APIs that are only
@@ -36964,10 +33284,6 @@ SQLITE_API extern int sqlite3_open_file_count;
# define NTDDI_WINBLUE 0x06030000
#endif
-#ifndef NTDDI_WINTHRESHOLD
-# define NTDDI_WINTHRESHOLD 0x06040000
-#endif
-
/*
** Check to see if the GetVersionEx[AW] functions are deprecated on the
** target system. GetVersionEx was first deprecated in Win8.1.
@@ -36981,19 +33297,6 @@ SQLITE_API extern int sqlite3_open_file_count;
#endif
/*
-** Check to see if the CreateFileMappingA function is supported on the
-** target system. It is unavailable when using "mincore.lib" on Win10.
-** When compiling for Windows 10, always assume "mincore.lib" is in use.
-*/
-#ifndef SQLITE_WIN32_CREATEFILEMAPPINGA
-# if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINTHRESHOLD
-# define SQLITE_WIN32_CREATEFILEMAPPINGA 0
-# else
-# define SQLITE_WIN32_CREATEFILEMAPPINGA 1
-# endif
-#endif
-
-/*
** This constant should already be defined (in the "WinDef.h" SDK file).
*/
#ifndef MAX_PATH
@@ -37233,22 +33536,10 @@ struct winFile {
#endif
/*
- * This is cache size used in the calculation of the initial size of the
- * Win32-specific heap. It cannot be negative.
- */
-#ifndef SQLITE_WIN32_CACHE_SIZE
-# if SQLITE_DEFAULT_CACHE_SIZE>=0
-# define SQLITE_WIN32_CACHE_SIZE (SQLITE_DEFAULT_CACHE_SIZE)
-# else
-# define SQLITE_WIN32_CACHE_SIZE (-(SQLITE_DEFAULT_CACHE_SIZE))
-# endif
-#endif
-
-/*
* The initial size of the Win32-specific heap. This value may be zero.
*/
#ifndef SQLITE_WIN32_HEAP_INIT_SIZE
-# define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_WIN32_CACHE_SIZE) * \
+# define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_DEFAULT_CACHE_SIZE) * \
(SQLITE_DEFAULT_PAGE_SIZE) + 4194304)
#endif
@@ -37411,9 +33702,8 @@ static struct win_syscall {
#define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \
LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent)
-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \
- (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) && \
- SQLITE_WIN32_CREATEFILEMAPPINGA
+#if (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \
+ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0))
{ "CreateFileMappingA", (SYSCALL)CreateFileMappingA, 0 },
#else
{ "CreateFileMappingA", (SYSCALL)0, 0 },
@@ -37643,7 +33933,8 @@ static struct win_syscall {
#define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent)
-#if defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_GETVERSIONEX
+#if defined(SQLITE_WIN32_HAS_ANSI) && defined(SQLITE_WIN32_GETVERSIONEX) && \
+ SQLITE_WIN32_GETVERSIONEX
{ "GetVersionExA", (SYSCALL)GetVersionExA, 0 },
#else
{ "GetVersionExA", (SYSCALL)0, 0 },
@@ -37653,7 +33944,7 @@ static struct win_syscall {
LPOSVERSIONINFOA))aSyscall[34].pCurrent)
#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
- SQLITE_WIN32_GETVERSIONEX
+ defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX
{ "GetVersionExW", (SYSCALL)GetVersionExW, 0 },
#else
{ "GetVersionExW", (SYSCALL)0, 0 },
@@ -38122,7 +34413,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_compact_heap(LPUINT pnLargest){
if( lastErrno==NO_ERROR ){
sqlite3_log(SQLITE_NOMEM, "failed to HeapCompact (no space), heap=%p",
(void*)hHeap);
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}else{
sqlite3_log(SQLITE_ERROR, "failed to HeapCompact (%lu), heap=%p",
osGetLastError(), (void*)hHeap);
@@ -38148,8 +34439,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_reset_heap(){
int rc;
MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */
- MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
- MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); )
+ MUTEX_LOGIC( pMaster = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); )
+ MUTEX_LOGIC( pMem = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); )
sqlite3_mutex_enter(pMaster);
sqlite3_mutex_enter(pMem);
winMemAssertMagic();
@@ -38194,12 +34485,6 @@ SQLITE_API void SQLITE_STDCALL sqlite3_win32_write_debug(const char *zBuf, int n
int nMin = MIN(nBuf, (SQLITE_WIN32_DBG_BUF_SIZE - 1)); /* may be negative. */
if( nMin<-1 ) nMin = -1; /* all negative values become -1. */
assert( nMin==-1 || nMin==0 || nMin<SQLITE_WIN32_DBG_BUF_SIZE );
-#ifdef SQLITE_ENABLE_API_ARMOR
- if( !zBuf ){
- (void)SQLITE_MISUSE_BKPT;
- return;
- }
-#endif
#if defined(SQLITE_WIN32_HAS_ANSI)
if( nMin>0 ){
memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE);
@@ -38270,7 +34555,7 @@ SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){
** the LockFileEx() API.
*/
-#if !SQLITE_WIN32_GETVERSIONEX
+#if !defined(SQLITE_WIN32_GETVERSIONEX) || !SQLITE_WIN32_GETVERSIONEX
# define osIsNT() (1)
#elif SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI)
# define osIsNT() (1)
@@ -38291,7 +34576,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_is_nt(void){
** kernel.
*/
return 1;
-#elif SQLITE_WIN32_GETVERSIONEX
+#elif defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX
if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){
#if defined(SQLITE_WIN32_HAS_ANSI)
OSVERSIONINFOA sInfo;
@@ -38448,7 +34733,7 @@ static int winMemInit(void *pAppData){
"failed to HeapCreate (%lu), flags=%u, initSize=%lu, maxSize=%lu",
osGetLastError(), SQLITE_WIN32_HEAP_FLAGS, dwInitialSize,
dwMaximumSize);
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
pWinMemData->bOwned = TRUE;
assert( pWinMemData->bOwned );
@@ -38458,7 +34743,7 @@ static int winMemInit(void *pAppData){
if( !pWinMemData->hHeap ){
sqlite3_log(SQLITE_NOMEM,
"failed to GetProcessHeap (%lu)", osGetLastError());
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
pWinMemData->bOwned = FALSE;
assert( !pWinMemData->bOwned );
@@ -38525,244 +34810,147 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){
#endif /* SQLITE_WIN32_MALLOC */
/*
-** Convert a UTF-8 string to Microsoft Unicode.
+** Convert a UTF-8 string to Microsoft Unicode (UTF-16?).
**
-** Space to hold the returned string is obtained from sqlite3_malloc().
+** Space to hold the returned string is obtained from malloc.
*/
-static LPWSTR winUtf8ToUnicode(const char *zText){
+static LPWSTR winUtf8ToUnicode(const char *zFilename){
int nChar;
- LPWSTR zWideText;
+ LPWSTR zWideFilename;
- nChar = osMultiByteToWideChar(CP_UTF8, 0, zText, -1, NULL, 0);
+ nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
if( nChar==0 ){
return 0;
}
- zWideText = sqlite3MallocZero( nChar*sizeof(WCHAR) );
- if( zWideText==0 ){
+ zWideFilename = sqlite3MallocZero( nChar*sizeof(zWideFilename[0]) );
+ if( zWideFilename==0 ){
return 0;
}
- nChar = osMultiByteToWideChar(CP_UTF8, 0, zText, -1, zWideText,
+ nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename,
nChar);
if( nChar==0 ){
- sqlite3_free(zWideText);
- zWideText = 0;
+ sqlite3_free(zWideFilename);
+ zWideFilename = 0;
}
- return zWideText;
+ return zWideFilename;
}
/*
-** Convert a Microsoft Unicode string to UTF-8.
-**
-** Space to hold the returned string is obtained from sqlite3_malloc().
+** Convert Microsoft Unicode to UTF-8. Space to hold the returned string is
+** obtained from sqlite3_malloc().
*/
-static char *winUnicodeToUtf8(LPCWSTR zWideText){
+static char *winUnicodeToUtf8(LPCWSTR zWideFilename){
int nByte;
- char *zText;
+ char *zFilename;
- nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideText, -1, 0, 0, 0, 0);
+ nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
if( nByte == 0 ){
return 0;
}
- zText = sqlite3MallocZero( nByte );
- if( zText==0 ){
+ zFilename = sqlite3MallocZero( nByte );
+ if( zFilename==0 ){
return 0;
}
- nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideText, -1, zText, nByte,
+ nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
0, 0);
if( nByte == 0 ){
- sqlite3_free(zText);
- zText = 0;
+ sqlite3_free(zFilename);
+ zFilename = 0;
}
- return zText;
+ return zFilename;
}
/*
-** Convert an ANSI string to Microsoft Unicode, using the ANSI or OEM
-** code page.
+** Convert an ANSI string to Microsoft Unicode, based on the
+** current codepage settings for file apis.
**
-** Space to hold the returned string is obtained from sqlite3_malloc().
+** Space to hold the returned string is obtained
+** from sqlite3_malloc.
*/
-static LPWSTR winMbcsToUnicode(const char *zText, int useAnsi){
+static LPWSTR winMbcsToUnicode(const char *zFilename){
int nByte;
- LPWSTR zMbcsText;
- int codepage = useAnsi ? CP_ACP : CP_OEMCP;
+ LPWSTR zMbcsFilename;
+ int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
- nByte = osMultiByteToWideChar(codepage, 0, zText, -1, NULL,
+ nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, NULL,
0)*sizeof(WCHAR);
if( nByte==0 ){
return 0;
}
- zMbcsText = sqlite3MallocZero( nByte*sizeof(WCHAR) );
- if( zMbcsText==0 ){
+ zMbcsFilename = sqlite3MallocZero( nByte*sizeof(zMbcsFilename[0]) );
+ if( zMbcsFilename==0 ){
return 0;
}
- nByte = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText,
+ nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename,
nByte);
if( nByte==0 ){
- sqlite3_free(zMbcsText);
- zMbcsText = 0;
+ sqlite3_free(zMbcsFilename);
+ zMbcsFilename = 0;
}
- return zMbcsText;
+ return zMbcsFilename;
}
/*
-** Convert a Microsoft Unicode string to a multi-byte character string,
-** using the ANSI or OEM code page.
+** Convert Microsoft Unicode to multi-byte character string, based on the
+** user's ANSI codepage.
**
-** Space to hold the returned string is obtained from sqlite3_malloc().
+** Space to hold the returned string is obtained from
+** sqlite3_malloc().
*/
-static char *winUnicodeToMbcs(LPCWSTR zWideText, int useAnsi){
+static char *winUnicodeToMbcs(LPCWSTR zWideFilename){
int nByte;
- char *zText;
- int codepage = useAnsi ? CP_ACP : CP_OEMCP;
+ char *zFilename;
+ int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
- nByte = osWideCharToMultiByte(codepage, 0, zWideText, -1, 0, 0, 0, 0);
+ nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0);
if( nByte == 0 ){
return 0;
}
- zText = sqlite3MallocZero( nByte );
- if( zText==0 ){
+ zFilename = sqlite3MallocZero( nByte );
+ if( zFilename==0 ){
return 0;
}
- nByte = osWideCharToMultiByte(codepage, 0, zWideText, -1, zText,
+ nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename,
nByte, 0, 0);
if( nByte == 0 ){
- sqlite3_free(zText);
- zText = 0;
+ sqlite3_free(zFilename);
+ zFilename = 0;
}
- return zText;
+ return zFilename;
}
/*
-** Convert a multi-byte character string to UTF-8.
-**
-** Space to hold the returned string is obtained from sqlite3_malloc().
+** Convert multibyte character string to UTF-8. Space to hold the
+** returned string is obtained from sqlite3_malloc().
*/
-static char *winMbcsToUtf8(const char *zText, int useAnsi){
- char *zTextUtf8;
+SQLITE_API char *SQLITE_STDCALL sqlite3_win32_mbcs_to_utf8(const char *zFilename){
+ char *zFilenameUtf8;
LPWSTR zTmpWide;
- zTmpWide = winMbcsToUnicode(zText, useAnsi);
+ zTmpWide = winMbcsToUnicode(zFilename);
if( zTmpWide==0 ){
return 0;
}
- zTextUtf8 = winUnicodeToUtf8(zTmpWide);
+ zFilenameUtf8 = winUnicodeToUtf8(zTmpWide);
sqlite3_free(zTmpWide);
- return zTextUtf8;
+ return zFilenameUtf8;
}
/*
-** Convert a UTF-8 string to a multi-byte character string.
-**
-** Space to hold the returned string is obtained from sqlite3_malloc().
+** Convert UTF-8 to multibyte character string. Space to hold the
+** returned string is obtained from sqlite3_malloc().
*/
-static char *winUtf8ToMbcs(const char *zText, int useAnsi){
- char *zTextMbcs;
+SQLITE_API char *SQLITE_STDCALL sqlite3_win32_utf8_to_mbcs(const char *zFilename){
+ char *zFilenameMbcs;
LPWSTR zTmpWide;
- zTmpWide = winUtf8ToUnicode(zText);
+ zTmpWide = winUtf8ToUnicode(zFilename);
if( zTmpWide==0 ){
return 0;
}
- zTextMbcs = winUnicodeToMbcs(zTmpWide, useAnsi);
+ zFilenameMbcs = winUnicodeToMbcs(zTmpWide);
sqlite3_free(zTmpWide);
- return zTextMbcs;
-}
-
-/*
-** This is a public wrapper for the winUtf8ToUnicode() function.
-*/
-SQLITE_API LPWSTR SQLITE_STDCALL sqlite3_win32_utf8_to_unicode(const char *zText){
-#ifdef SQLITE_ENABLE_API_ARMOR
- if( !zText ){
- (void)SQLITE_MISUSE_BKPT;
- return 0;
- }
-#endif
-#ifndef SQLITE_OMIT_AUTOINIT
- if( sqlite3_initialize() ) return 0;
-#endif
- return winUtf8ToUnicode(zText);
-}
-
-/*
-** This is a public wrapper for the winUnicodeToUtf8() function.
-*/
-SQLITE_API char *SQLITE_STDCALL sqlite3_win32_unicode_to_utf8(LPCWSTR zWideText){
-#ifdef SQLITE_ENABLE_API_ARMOR
- if( !zWideText ){
- (void)SQLITE_MISUSE_BKPT;
- return 0;
- }
-#endif
-#ifndef SQLITE_OMIT_AUTOINIT
- if( sqlite3_initialize() ) return 0;
-#endif
- return winUnicodeToUtf8(zWideText);
-}
-
-/*
-** This is a public wrapper for the winMbcsToUtf8() function.
-*/
-SQLITE_API char *SQLITE_STDCALL sqlite3_win32_mbcs_to_utf8(const char *zText){
-#ifdef SQLITE_ENABLE_API_ARMOR
- if( !zText ){
- (void)SQLITE_MISUSE_BKPT;
- return 0;
- }
-#endif
-#ifndef SQLITE_OMIT_AUTOINIT
- if( sqlite3_initialize() ) return 0;
-#endif
- return winMbcsToUtf8(zText, osAreFileApisANSI());
-}
-
-/*
-** This is a public wrapper for the winMbcsToUtf8() function.
-*/
-SQLITE_API char *SQLITE_STDCALL sqlite3_win32_mbcs_to_utf8_v2(const char *zText, int useAnsi){
-#ifdef SQLITE_ENABLE_API_ARMOR
- if( !zText ){
- (void)SQLITE_MISUSE_BKPT;
- return 0;
- }
-#endif
-#ifndef SQLITE_OMIT_AUTOINIT
- if( sqlite3_initialize() ) return 0;
-#endif
- return winMbcsToUtf8(zText, useAnsi);
-}
-
-/*
-** This is a public wrapper for the winUtf8ToMbcs() function.
-*/
-SQLITE_API char *SQLITE_STDCALL sqlite3_win32_utf8_to_mbcs(const char *zText){
-#ifdef SQLITE_ENABLE_API_ARMOR
- if( !zText ){
- (void)SQLITE_MISUSE_BKPT;
- return 0;
- }
-#endif
-#ifndef SQLITE_OMIT_AUTOINIT
- if( sqlite3_initialize() ) return 0;
-#endif
- return winUtf8ToMbcs(zText, osAreFileApisANSI());
-}
-
-/*
-** This is a public wrapper for the winUtf8ToMbcs() function.
-*/
-SQLITE_API char *SQLITE_STDCALL sqlite3_win32_utf8_to_mbcs_v2(const char *zText, int useAnsi){
-#ifdef SQLITE_ENABLE_API_ARMOR
- if( !zText ){
- (void)SQLITE_MISUSE_BKPT;
- return 0;
- }
-#endif
-#ifndef SQLITE_OMIT_AUTOINIT
- if( sqlite3_initialize() ) return 0;
-#endif
- return winUtf8ToMbcs(zText, useAnsi);
+ return zFilenameMbcs;
}
/*
@@ -38792,7 +34980,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_set_directory(DWORD type, LPCWSTR zV
if( zValue && zValue[0] ){
zValueUtf8 = winUnicodeToUtf8(zValue);
if ( zValueUtf8==0 ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
}
sqlite3_free(*ppDirectory);
@@ -38864,7 +35052,7 @@ static int winGetLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){
if( dwLen > 0 ){
/* allocate a buffer and convert to UTF8 */
sqlite3BeginBenignMalloc();
- zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI());
+ zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
sqlite3EndBenignMalloc();
/* free the system buffer allocated by FormatMessage */
osLocalFree(zTemp);
@@ -39006,17 +35194,16 @@ static void winLogIoerr(int nRetry, int lineno){
}
}
-/*
-** This #if does not rely on the SQLITE_OS_WINCE define because the
-** corresponding section in "date.c" cannot use it.
+#if SQLITE_OS_WINCE
+/*************************************************************************
+** This section contains code for WinCE only.
*/
-#if !defined(SQLITE_OMIT_LOCALTIME) && defined(_WIN32_WCE) && \
- (!defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API)
+#if !defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API
/*
-** The MSVC CRT on Windows CE may not have a localtime() function.
-** So define a substitute.
+** The MSVC CRT on Windows CE may not have a localtime() function. So
+** create a substitute.
*/
-/* # include <time.h> */
+/* #include <time.h> */
struct tm *__cdecl localtime(const time_t *t)
{
static struct tm y;
@@ -39040,10 +35227,6 @@ struct tm *__cdecl localtime(const time_t *t)
}
#endif
-#if SQLITE_OS_WINCE
-/*************************************************************************
-** This section contains code for WinCE only.
-*/
#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]
/*
@@ -39074,7 +35257,7 @@ static int winceCreateLock(const char *zFilename, winFile *pFile){
zName = winUtf8ToUnicode(zFilename);
if( zName==0 ){
/* out of memory */
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
/* Initialize the local lockdata */
@@ -39550,7 +35733,7 @@ static int winRead(
pFile->h, pBuf, amt, offset, pFile->locktype));
#if SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this read request as possible by transfering
+ /* Deal with as much of this read request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -39627,8 +35810,8 @@ static int winWrite(
"offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile,
pFile->h, pBuf, amt, offset, pFile->locktype));
-#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this write request as possible by transfering
+#if SQLITE_MAX_MMAP_SIZE>0
+ /* Deal with as much of this write request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -40040,12 +36223,6 @@ static int winLock(sqlite3_file *id, int locktype){
return SQLITE_OK;
}
- /* Do not allow any kind of write-lock on a read-only database
- */
- if( (pFile->ctrlFlags & WINFILE_RDONLY)!=0 && locktype>=RESERVED_LOCK ){
- return SQLITE_IOERR_LOCK;
- }
-
/* Make sure the locking sequence is correct
*/
assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
@@ -40057,8 +36234,9 @@ static int winLock(sqlite3_file *id, int locktype){
** the PENDING_LOCK byte is temporary.
*/
newLocktype = pFile->locktype;
- if( pFile->locktype==NO_LOCK
- || (locktype==EXCLUSIVE_LOCK && pFile->locktype<=RESERVED_LOCK)
+ if( (pFile->locktype==NO_LOCK)
+ || ( (locktype==EXCLUSIVE_LOCK)
+ && (pFile->locktype==RESERVED_LOCK))
){
int cnt = 3;
while( cnt-->0 && (res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS,
@@ -40174,7 +36352,7 @@ static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
res = 1;
OSTRACE(("TEST-WR-LOCK file=%p, result=%d (local)\n", pFile->h, res));
}else{
- res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE,0,1,0);
+ res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0);
if( res ){
winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
}
@@ -40264,7 +36442,7 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
return SQLITE_OK;
}
- case SQLITE_FCNTL_LAST_ERRNO: {
+ case SQLITE_LAST_ERRNO: {
*(int*)pArg = (int)pFile->lastErrno;
OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
return SQLITE_OK;
@@ -40414,14 +36592,14 @@ static SYSTEM_INFO winSysInfo;
** winShmLeaveMutex()
*/
static void winShmEnterMutex(void){
- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
}
static void winShmLeaveMutex(void){
- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
}
#ifndef NDEBUG
static int winShmMutexHeld(void) {
- return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
+ return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
}
#endif
@@ -40622,12 +36800,12 @@ static int winOpenSharedMemory(winFile *pDbFd){
** allocate space for a new winShmNode and filename.
*/
p = sqlite3MallocZero( sizeof(*p) );
- if( p==0 ) return SQLITE_IOERR_NOMEM_BKPT;
+ if( p==0 ) return SQLITE_IOERR_NOMEM;
nName = sqlite3Strlen30(pDbFd->zPath);
pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 );
if( pNew==0 ){
sqlite3_free(p);
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
pNew->zFilename = (char*)&pNew[1];
sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
@@ -40652,12 +36830,10 @@ static int winOpenSharedMemory(winFile *pDbFd){
pShmNode->pNext = winShmNodeList;
winShmNodeList = pShmNode;
- if( sqlite3GlobalConfig.bCoreMutex ){
- pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
- if( pShmNode->mutex==0 ){
- rc = SQLITE_IOERR_NOMEM_BKPT;
- goto shm_open_err;
- }
+ pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ if( pShmNode->mutex==0 ){
+ rc = SQLITE_IOERR_NOMEM;
+ goto shm_open_err;
}
rc = winOpen(pDbFd->pVfs,
@@ -40876,8 +37052,8 @@ static void winShmBarrier(
sqlite3_file *fd /* Database holding the shared memory */
){
UNUSED_PARAMETER(fd);
- sqlite3MemoryBarrier(); /* compiler-defined memory barrier */
- winShmEnterMutex(); /* Also mutex, for redundancy */
+ /* MemoryBarrier(); // does not work -- do not know why not */
+ winShmEnterMutex();
winShmLeaveMutex();
}
@@ -40961,7 +37137,7 @@ static int winShmMap(
pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
);
if( !apNew ){
- rc = SQLITE_IOERR_NOMEM_BKPT;
+ rc = SQLITE_IOERR_NOMEM;
goto shmpage_out;
}
pShmNode->aRegion = apNew;
@@ -40978,7 +37154,7 @@ static int winShmMap(
hMap = osCreateFileMappingW(pShmNode->hFile.h,
NULL, PAGE_READWRITE, 0, nByte, NULL
);
-#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA
+#elif defined(SQLITE_WIN32_HAS_ANSI)
hMap = osCreateFileMappingA(pShmNode->hFile.h,
NULL, PAGE_READWRITE, 0, nByte, NULL
);
@@ -41122,19 +37298,17 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){
DWORD flags = FILE_MAP_READ;
winUnmapfile(pFd);
-#ifdef SQLITE_MMAP_READWRITE
if( (pFd->ctrlFlags & WINFILE_RDONLY)==0 ){
protect = PAGE_READWRITE;
flags |= FILE_MAP_WRITE;
}
-#endif
#if SQLITE_OS_WINRT
pFd->hMap = osCreateFileMappingFromApp(pFd->h, NULL, protect, nMap, NULL);
#elif defined(SQLITE_WIN32_HAS_WIDE)
pFd->hMap = osCreateFileMappingW(pFd->h, NULL, protect,
(DWORD)((nMap>>32) & 0xffffffff),
(DWORD)(nMap & 0xffffffff), NULL);
-#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA
+#elif defined(SQLITE_WIN32_HAS_ANSI)
pFd->hMap = osCreateFileMappingA(pFd->h, NULL, protect,
(DWORD)((nMap>>32) & 0xffffffff),
(DWORD)(nMap & 0xffffffff), NULL);
@@ -41315,7 +37489,7 @@ static char *winConvertToUtf8Filename(const void *zFilename){
}
#ifdef SQLITE_WIN32_HAS_ANSI
else{
- zConverted = winMbcsToUtf8(zFilename, osAreFileApisANSI());
+ zConverted = sqlite3_win32_mbcs_to_utf8(zFilename);
}
#endif
/* caller will handle out of memory */
@@ -41336,7 +37510,7 @@ static void *winConvertFromUtf8Filename(const char *zFilename){
}
#ifdef SQLITE_WIN32_HAS_ANSI
else{
- zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI());
+ zConverted = sqlite3_win32_utf8_to_mbcs(zFilename);
}
#endif
/* caller will handle out of memory */
@@ -41391,7 +37565,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
zBuf = sqlite3MallocZero( nBuf );
if( !zBuf ){
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
/* Figure out the effective temporary directory. First, check if one
@@ -41449,7 +37623,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
if( !zConverted ){
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
if( winIsDir(zConverted) ){
sqlite3_snprintf(nMax, zBuf, "%s", zDir);
@@ -41462,7 +37636,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
if( !zConverted ){
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
if( cygwin_conv_path(
osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A, zDir,
@@ -41483,7 +37657,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
sqlite3_free(zConverted);
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
sqlite3_snprintf(nMax, zBuf, "%s", zUtf8);
sqlite3_free(zUtf8);
@@ -41501,7 +37675,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
if( !zWidePath ){
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
if( osGetTempPathW(nMax, zWidePath)==0 ){
sqlite3_free(zWidePath);
@@ -41519,7 +37693,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
sqlite3_free(zWidePath);
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
}
#ifdef SQLITE_WIN32_HAS_ANSI
@@ -41529,7 +37703,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
if( !zMbcsPath ){
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
if( osGetTempPathA(nMax, zMbcsPath)==0 ){
sqlite3_free(zBuf);
@@ -41537,14 +37711,14 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
return winLogError(SQLITE_IOERR_GETTEMPPATH, osGetLastError(),
"winGetTempname3", 0);
}
- zUtf8 = winMbcsToUtf8(zMbcsPath, osAreFileApisANSI());
+ zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath);
if( zUtf8 ){
sqlite3_snprintf(nMax, zBuf, "%s", zUtf8);
sqlite3_free(zUtf8);
}else{
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
}
#endif /* SQLITE_WIN32_HAS_ANSI */
@@ -41736,7 +37910,7 @@ static int winOpen(
if( zConverted==0 ){
sqlite3_free(zTmpname);
OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name));
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
if( winIsDir(zConverted) ){
@@ -41936,7 +38110,7 @@ static int winDelete(
zConverted = winConvertFromUtf8Filename(zFilename);
if( zConverted==0 ){
OSTRACE(("DELETE name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
if( osIsNT() ){
do {
@@ -42044,7 +38218,7 @@ static int winAccess(
zConverted = winConvertFromUtf8Filename(zFilename);
if( zConverted==0 ){
OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
if( osIsNT() ){
int cnt = 0;
@@ -42171,7 +38345,7 @@ static int winFullPathname(
*/
char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
if( !zOut ){
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
if( cygwin_conv_path(
(osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A) |
@@ -42183,7 +38357,7 @@ static int winFullPathname(
char *zUtf8 = winConvertToUtf8Filename(zOut);
if( !zUtf8 ){
sqlite3_free(zOut);
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
sqlite3_data_directory, winGetDirSep(), zUtf8);
@@ -42193,7 +38367,7 @@ static int winFullPathname(
}else{
char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
if( !zOut ){
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
if( cygwin_conv_path(
(osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A),
@@ -42205,7 +38379,7 @@ static int winFullPathname(
char *zUtf8 = winConvertToUtf8Filename(zOut);
if( !zUtf8 ){
sqlite3_free(zOut);
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zUtf8);
sqlite3_free(zUtf8);
@@ -42265,7 +38439,7 @@ static int winFullPathname(
}
zConverted = winConvertFromUtf8Filename(zRelative);
if( zConverted==0 ){
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
if( osIsNT() ){
LPWSTR zTemp;
@@ -42279,7 +38453,7 @@ static int winFullPathname(
zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
if( zTemp==0 ){
sqlite3_free(zConverted);
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
nByte = osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0);
if( nByte==0 ){
@@ -42305,7 +38479,7 @@ static int winFullPathname(
zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
if( zTemp==0 ){
sqlite3_free(zConverted);
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
nByte = osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
if( nByte==0 ){
@@ -42315,7 +38489,7 @@ static int winFullPathname(
"winFullPathname4", zRelative);
}
sqlite3_free(zConverted);
- zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI());
+ zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
sqlite3_free(zTemp);
}
#endif
@@ -42324,7 +38498,7 @@ static int winFullPathname(
sqlite3_free(zOut);
return SQLITE_OK;
}else{
- return SQLITE_IOERR_NOMEM_BKPT;
+ return SQLITE_IOERR_NOMEM;
}
#endif
}
@@ -42399,85 +38573,65 @@ static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
#define winDlClose 0
#endif
-/* State information for the randomness gatherer. */
-typedef struct EntropyGatherer EntropyGatherer;
-struct EntropyGatherer {
- unsigned char *a; /* Gather entropy into this buffer */
- int na; /* Size of a[] in bytes */
- int i; /* XOR next input into a[i] */
- int nXor; /* Number of XOR operations done */
-};
-
-#if !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS)
-/* Mix sz bytes of entropy into p. */
-static void xorMemory(EntropyGatherer *p, unsigned char *x, int sz){
- int j, k;
- for(j=0, k=p->i; j<sz; j++){
- p->a[k++] ^= x[j];
- if( k>=p->na ) k = 0;
- }
- p->i = k;
- p->nXor += sz;
-}
-#endif /* !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS) */
/*
** Write up to nBuf bytes of randomness into zBuf.
*/
static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
-#if defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS)
+ int n = 0;
UNUSED_PARAMETER(pVfs);
+#if defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS)
+ n = nBuf;
memset(zBuf, 0, nBuf);
- return nBuf;
#else
- EntropyGatherer e;
- UNUSED_PARAMETER(pVfs);
- memset(zBuf, 0, nBuf);
-#if defined(_MSC_VER) && _MSC_VER>=1400 && !SQLITE_OS_WINCE
- rand_s((unsigned int*)zBuf); /* rand_s() is not available with MinGW */
-#endif /* defined(_MSC_VER) && _MSC_VER>=1400 */
- e.a = (unsigned char*)zBuf;
- e.na = nBuf;
- e.nXor = 0;
- e.i = 0;
- {
+ if( sizeof(SYSTEMTIME)<=nBuf-n ){
SYSTEMTIME x;
osGetSystemTime(&x);
- xorMemory(&e, (unsigned char*)&x, sizeof(SYSTEMTIME));
+ memcpy(&zBuf[n], &x, sizeof(x));
+ n += sizeof(x);
}
- {
+ if( sizeof(DWORD)<=nBuf-n ){
DWORD pid = osGetCurrentProcessId();
- xorMemory(&e, (unsigned char*)&pid, sizeof(DWORD));
+ memcpy(&zBuf[n], &pid, sizeof(pid));
+ n += sizeof(pid);
}
#if SQLITE_OS_WINRT
- {
+ if( sizeof(ULONGLONG)<=nBuf-n ){
ULONGLONG cnt = osGetTickCount64();
- xorMemory(&e, (unsigned char*)&cnt, sizeof(ULONGLONG));
+ memcpy(&zBuf[n], &cnt, sizeof(cnt));
+ n += sizeof(cnt);
}
#else
- {
+ if( sizeof(DWORD)<=nBuf-n ){
DWORD cnt = osGetTickCount();
- xorMemory(&e, (unsigned char*)&cnt, sizeof(DWORD));
+ memcpy(&zBuf[n], &cnt, sizeof(cnt));
+ n += sizeof(cnt);
}
-#endif /* SQLITE_OS_WINRT */
- {
+#endif
+ if( sizeof(LARGE_INTEGER)<=nBuf-n ){
LARGE_INTEGER i;
osQueryPerformanceCounter(&i);
- xorMemory(&e, (unsigned char*)&i, sizeof(LARGE_INTEGER));
+ memcpy(&zBuf[n], &i, sizeof(i));
+ n += sizeof(i);
}
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
- {
+ if( sizeof(UUID)<=nBuf-n ){
UUID id;
memset(&id, 0, sizeof(UUID));
osUuidCreate(&id);
- xorMemory(&e, (unsigned char*)&id, sizeof(UUID));
+ memcpy(zBuf, &id, sizeof(UUID));
+ n += sizeof(UUID);
+ }
+ if( sizeof(UUID)<=nBuf-n ){
+ UUID id;
memset(&id, 0, sizeof(UUID));
osUuidCreateSequential(&id);
- xorMemory(&e, (unsigned char*)&id, sizeof(UUID));
+ memcpy(zBuf, &id, sizeof(UUID));
+ n += sizeof(UUID);
}
-#endif /* !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID */
- return e.nXor>nBuf ? nBuf : e.nXor;
-#endif /* defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS) */
+#endif
+#endif /* defined(SQLITE_TEST) || defined(SQLITE_ZERO_PRNG_SEED) */
+ return n;
}
@@ -42593,10 +38747,8 @@ static int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
** sqlite3_errmsg(), possibly making IO errors easier to debug.
*/
static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
- DWORD e = osGetLastError();
UNUSED_PARAMETER(pVfs);
- if( nBuf>0 ) winGetLastErrorMsg(e, nBuf, zBuf);
- return e;
+ return winGetLastErrorMsg(osGetLastError(), nBuf, zBuf);
}
/*
@@ -42727,15 +38879,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
** start of a transaction, and is thus usually less than a few thousand,
** but can be as large as 2 billion for a really big database.
*/
-/* #include "sqliteInt.h" */
/* Size of the Bitvec structure in bytes. */
#define BITVEC_SZ 512
/* Round the union size down to the nearest pointer boundary, since that's how
** it will be aligned within the Bitvec struct. */
-#define BITVEC_USIZE \
- (((BITVEC_SZ-(3*sizeof(u32)))/sizeof(Bitvec*))*sizeof(Bitvec*))
+#define BITVEC_USIZE (((BITVEC_SZ-(3*sizeof(u32)))/sizeof(Bitvec*))*sizeof(Bitvec*))
/* Type of the array "element" for the bitmap representation.
** Should be a power of 2, and ideally, evenly divide into BITVEC_USIZE.
@@ -42820,10 +38970,10 @@ SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32 iSize){
** If p is NULL (if the bitmap has not been created) or if
** i is out of range, then return false.
*/
-SQLITE_PRIVATE int sqlite3BitvecTestNotNull(Bitvec *p, u32 i){
- assert( p!=0 );
+SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec *p, u32 i){
+ if( p==0 ) return 0;
+ if( i>p->iSize || i==0 ) return 0;
i--;
- if( i>=p->iSize ) return 0;
while( p->iDivisor ){
u32 bin = i/p->iDivisor;
i = i%p->iDivisor;
@@ -42843,9 +38993,6 @@ SQLITE_PRIVATE int sqlite3BitvecTestNotNull(Bitvec *p, u32 i){
return 0;
}
}
-SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec *p, u32 i){
- return p!=0 && sqlite3BitvecTestNotNull(p,i);
-}
/*
** Set the i-th bit. Return 0 on success and an error code if
@@ -42870,7 +39017,7 @@ SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec *p, u32 i){
i = i%p->iDivisor;
if( p->u.apSub[bin]==0 ){
p->u.apSub[bin] = sqlite3BitvecCreate( p->iDivisor );
- if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM_BKPT;
+ if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM;
}
p = p->u.apSub[bin];
}
@@ -42905,7 +39052,7 @@ bitvec_set_rehash:
int rc;
u32 *aiValues = sqlite3StackAllocRaw(0, sizeof(p->u.aHash));
if( aiValues==0 ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}else{
memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash));
memset(p->u.apSub, 0, sizeof(p->u.apSub));
@@ -43118,39 +39265,15 @@ bitvec_end:
*************************************************************************
** This file implements that page cache.
*/
-/* #include "sqliteInt.h" */
/*
-** A complete page cache is an instance of this structure. Every
-** entry in the cache holds a single page of the database file. The
-** btree layer only operates on the cached copy of the database pages.
-**
-** A page cache entry is "clean" if it exactly matches what is currently
-** on disk. A page is "dirty" if it has been modified and needs to be
-** persisted to disk.
-**
-** pDirty, pDirtyTail, pSynced:
-** All dirty pages are linked into the doubly linked list using
-** PgHdr.pDirtyNext and pDirtyPrev. The list is maintained in LRU order
-** such that p was added to the list more recently than p->pDirtyNext.
-** PCache.pDirty points to the first (newest) element in the list and
-** pDirtyTail to the last (oldest).
-**
-** The PCache.pSynced variable is used to optimize searching for a dirty
-** page to eject from the cache mid-transaction. It is better to eject
-** a page that does not require a journal sync than one that does.
-** Therefore, pSynced is maintained to that it *almost* always points
-** to either the oldest page in the pDirty/pDirtyTail list that has a
-** clear PGHDR_NEED_SYNC flag or to a page that is older than this one
-** (so that the right page to eject can be found by following pDirtyPrev
-** pointers).
+** A complete page cache is an instance of this structure.
*/
struct PCache {
PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */
PgHdr *pSynced; /* Last synced page in dirty page list */
- int nRefSum; /* Sum of ref counts over all pages */
+ int nRef; /* Number of referenced pages */
int szCache; /* Configured cache size */
- int szSpill; /* Size before spilling occurs */
int szPage; /* Size of every page in this cache */
int szExtra; /* Size of extra space for each page */
u8 bPurgeable; /* True if pages are on backing store */
@@ -43158,97 +39281,9 @@ struct PCache {
int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */
void *pStress; /* Argument to xStress */
sqlite3_pcache *pCache; /* Pluggable cache module */
+ PgHdr *pPage1; /* Reference to page 1 */
};
-/********************************** Test and Debug Logic **********************/
-/*
-** Debug tracing macros. Enable by by changing the "0" to "1" and
-** recompiling.
-**
-** When sqlite3PcacheTrace is 1, single line trace messages are issued.
-** When sqlite3PcacheTrace is 2, a dump of the pcache showing all cache entries
-** is displayed for many operations, resulting in a lot of output.
-*/
-#if defined(SQLITE_DEBUG) && 0
- int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */
- int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */
-# define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;}
- void pcacheDump(PCache *pCache){
- int N;
- int i, j;
- sqlite3_pcache_page *pLower;
- PgHdr *pPg;
- unsigned char *a;
-
- if( sqlite3PcacheTrace<2 ) return;
- if( pCache->pCache==0 ) return;
- N = sqlite3PcachePagecount(pCache);
- if( N>sqlite3PcacheMxDump ) N = sqlite3PcacheMxDump;
- for(i=1; i<=N; i++){
- pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0);
- if( pLower==0 ) continue;
- pPg = (PgHdr*)pLower->pExtra;
- printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags);
- a = (unsigned char *)pLower->pBuf;
- for(j=0; j<12; j++) printf("%02x", a[j]);
- printf("\n");
- if( pPg->pPage==0 ){
- sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0);
- }
- }
- }
- #else
-# define pcacheTrace(X)
-# define pcacheDump(X)
-#endif
-
-/*
-** Check invariants on a PgHdr entry. Return true if everything is OK.
-** Return false if any invariant is violated.
-**
-** This routine is for use inside of assert() statements only. For
-** example:
-**
-** assert( sqlite3PcachePageSanity(pPg) );
-*/
-#if SQLITE_DEBUG
-SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr *pPg){
- PCache *pCache;
- assert( pPg!=0 );
- assert( pPg->pgno>0 ); /* Page number is 1 or more */
- pCache = pPg->pCache;
- assert( pCache!=0 ); /* Every page has an associated PCache */
- if( pPg->flags & PGHDR_CLEAN ){
- assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */
- assert( pCache->pDirty!=pPg ); /* CLEAN pages not on dirty list */
- assert( pCache->pDirtyTail!=pPg );
- }
- /* WRITEABLE pages must also be DIRTY */
- if( pPg->flags & PGHDR_WRITEABLE ){
- assert( pPg->flags & PGHDR_DIRTY ); /* WRITEABLE implies DIRTY */
- }
- /* NEED_SYNC can be set independently of WRITEABLE. This can happen,
- ** for example, when using the sqlite3PagerDontWrite() optimization:
- ** (1) Page X is journalled, and gets WRITEABLE and NEED_SEEK.
- ** (2) Page X moved to freelist, WRITEABLE is cleared
- ** (3) Page X reused, WRITEABLE is set again
- ** If NEED_SYNC had been cleared in step 2, then it would not be reset
- ** in step 3, and page might be written into the database without first
- ** syncing the rollback journal, which might cause corruption on a power
- ** loss.
- **
- ** Another example is when the database page size is smaller than the
- ** disk sector size. When any page of a sector is journalled, all pages
- ** in that sector are marked NEED_SYNC even if they are still CLEAN, just
- ** in case they are later modified, since all pages in the same sector
- ** must be journalled and synced before any of those pages can be safely
- ** written.
- */
- return 1;
-}
-#endif /* SQLITE_DEBUG */
-
-
/********************************** Linked List Management ********************/
/* Allowed values for second argument to pcacheManageDirtyList() */
@@ -43265,16 +39300,17 @@ SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr *pPg){
static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
PCache *p = pPage->pCache;
- pcacheTrace(("%p.DIRTYLIST.%s %d\n", p,
- addRemove==1 ? "REMOVE" : addRemove==2 ? "ADD" : "FRONT",
- pPage->pgno));
if( addRemove & PCACHE_DIRTYLIST_REMOVE ){
assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
assert( pPage->pDirtyPrev || pPage==p->pDirty );
/* Update the PCache1.pSynced variable if necessary. */
if( p->pSynced==pPage ){
- p->pSynced = pPage->pDirtyPrev;
+ PgHdr *pSynced = pPage->pDirtyPrev;
+ while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
+ pSynced = pSynced->pDirtyPrev;
+ }
+ p->pSynced = pSynced;
}
if( pPage->pDirtyNext ){
@@ -43286,15 +39322,10 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
if( pPage->pDirtyPrev ){
pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
}else{
- /* If there are now no dirty pages in the cache, set eCreate to 2.
- ** This is an optimization that allows sqlite3PcacheFetch() to skip
- ** searching for a dirty page to eject from the cache when it might
- ** otherwise have to. */
assert( pPage==p->pDirty );
p->pDirty = pPage->pDirtyNext;
- assert( p->bPurgeable || p->eCreate==2 );
- if( p->pDirty==0 ){ /*OPTIMIZATION-IF-TRUE*/
- assert( p->bPurgeable==0 || p->eCreate==1 );
+ if( p->pDirty==0 && p->bPurgeable ){
+ assert( p->eCreate==1 );
p->eCreate = 2;
}
}
@@ -43316,19 +39347,10 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
}
}
p->pDirty = pPage;
-
- /* If pSynced is NULL and this page has a clear NEED_SYNC flag, set
- ** pSynced to point to it. Checking the NEED_SYNC flag is an
- ** optimization, as if pSynced points to a page with the NEED_SYNC
- ** flag set sqlite3PcacheFetchStress() searches through all newer
- ** entries of the dirty-list for a page with NEED_SYNC clear anyway. */
- if( !p->pSynced
- && 0==(pPage->flags&PGHDR_NEED_SYNC) /*OPTIMIZATION-IF-FALSE*/
- ){
+ if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
p->pSynced = pPage;
}
}
- pcacheDump(p);
}
/*
@@ -43337,15 +39359,18 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
*/
static void pcacheUnpin(PgHdr *p){
if( p->pCache->bPurgeable ){
- pcacheTrace(("%p.UNPIN %d\n", p->pCache, p->pgno));
+ if( p->pgno==1 ){
+ p->pCache->pPage1 = 0;
+ }
sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0);
- pcacheDump(p->pCache);
}
}
/*
-** Compute the number of pages of cache requested. p->szCache is the
+** Compute the number of pages of cache requested. p->szCache is the
** cache size requested by the "PRAGMA cache_size" statement.
+**
+**
*/
static int numberOfCachePages(PCache *p){
if( p->szCache>=0 ){
@@ -43408,8 +39433,6 @@ SQLITE_PRIVATE int sqlite3PcacheOpen(
p->xStress = xStress;
p->pStress = pStress;
p->szCache = 100;
- p->szSpill = 1;
- pcacheTrace(("%p.OPEN szPage %d bPurgeable %d\n",p,szPage,bPurgeable));
return sqlite3PcacheSetPageSize(p, szPage);
}
@@ -43418,21 +39441,21 @@ SQLITE_PRIVATE int sqlite3PcacheOpen(
** are no outstanding page references when this function is called.
*/
SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
- assert( pCache->nRefSum==0 && pCache->pDirty==0 );
+ assert( pCache->nRef==0 && pCache->pDirty==0 );
if( pCache->szPage ){
sqlite3_pcache *pNew;
pNew = sqlite3GlobalConfig.pcache2.xCreate(
szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)),
pCache->bPurgeable
);
- if( pNew==0 ) return SQLITE_NOMEM_BKPT;
+ if( pNew==0 ) return SQLITE_NOMEM;
sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache));
if( pCache->pCache ){
sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
}
pCache->pCache = pNew;
+ pCache->pPage1 = 0;
pCache->szPage = szPage;
- pcacheTrace(("%p.PAGESIZE %d\n",pCache,szPage));
}
return SQLITE_OK;
}
@@ -43467,13 +39490,11 @@ SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(
int createFlag /* If true, create page if it does not exist already */
){
int eCreate;
- sqlite3_pcache_page *pRes;
assert( pCache!=0 );
assert( pCache->pCache!=0 );
assert( createFlag==3 || createFlag==0 );
assert( pgno>0 );
- assert( pCache->eCreate==((pCache->bPurgeable && pCache->pDirty) ? 1 : 2) );
/* eCreate defines what to do if the page does not exist.
** 0 Do not allocate a new page. (createFlag==0)
@@ -43486,15 +39507,12 @@ SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(
assert( eCreate==0 || eCreate==1 || eCreate==2 );
assert( createFlag==0 || pCache->eCreate==eCreate );
assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
- pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
- pcacheTrace(("%p.FETCH %d%s (result: %p)\n",pCache,pgno,
- createFlag?" create":"",pRes));
- return pRes;
+ return sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
}
/*
** If the sqlite3PcacheFetch() routine is unable to allocate a new
-** page because no clean pages are available for reuse and the cache
+** page because new clean pages are available for reuse and the cache
** size limit has been reached, then this routine can be invoked to
** try harder to allocate a page. This routine might invoke the stress
** callback to spill dirty pages to the journal. It will then try to
@@ -43511,43 +39529,36 @@ SQLITE_PRIVATE int sqlite3PcacheFetchStress(
PgHdr *pPg;
if( pCache->eCreate==2 ) return 0;
- if( sqlite3PcachePagecount(pCache)>pCache->szSpill ){
- /* Find a dirty page to write-out and recycle. First try to find a
- ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
- ** cleared), but if that is not possible settle for any other
- ** unreferenced dirty page.
- **
- ** If the LRU page in the dirty list that has a clear PGHDR_NEED_SYNC
- ** flag is currently referenced, then the following may leave pSynced
- ** set incorrectly (pointing to other than the LRU page with NEED_SYNC
- ** cleared). This is Ok, as pSynced is just an optimization. */
- for(pPg=pCache->pSynced;
- pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
- pPg=pPg->pDirtyPrev
- );
- pCache->pSynced = pPg;
- if( !pPg ){
- for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
- }
- if( pPg ){
- int rc;
+
+ /* Find a dirty page to write-out and recycle. First try to find a
+ ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
+ ** cleared), but if that is not possible settle for any other
+ ** unreferenced dirty page.
+ */
+ for(pPg=pCache->pSynced;
+ pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
+ pPg=pPg->pDirtyPrev
+ );
+ pCache->pSynced = pPg;
+ if( !pPg ){
+ for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev);
+ }
+ if( pPg ){
+ int rc;
#ifdef SQLITE_LOG_CACHE_SPILL
- sqlite3_log(SQLITE_FULL,
- "spill page %d making room for %d - cache used: %d/%d",
- pPg->pgno, pgno,
- sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
+ sqlite3_log(SQLITE_FULL,
+ "spill page %d making room for %d - cache used: %d/%d",
+ pPg->pgno, pgno,
+ sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
numberOfCachePages(pCache));
#endif
- pcacheTrace(("%p.SPILL %d\n",pCache,pPg->pgno));
- rc = pCache->xStress(pCache->pStress, pPg);
- pcacheDump(pCache);
- if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
- return rc;
- }
+ rc = pCache->xStress(pCache->pStress, pPg);
+ if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
+ return rc;
}
}
*ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
- return *ppPage==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
+ return *ppPage==0 ? SQLITE_NOMEM : SQLITE_OK;
}
/*
@@ -43568,14 +39579,13 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
assert( pPage!=0 );
pPgHdr = (PgHdr*)pPage->pExtra;
assert( pPgHdr->pPage==0 );
- memset(pPgHdr, 0, sizeof(PgHdr));
+ memset(pPgHdr, 0, sizeof(PgHdr));
pPgHdr->pPage = pPage;
pPgHdr->pData = pPage->pBuf;
pPgHdr->pExtra = (void *)&pPgHdr[1];
memset(pPgHdr->pExtra, 0, pCache->szExtra);
pPgHdr->pCache = pCache;
pPgHdr->pgno = pgno;
- pPgHdr->flags = PGHDR_CLEAN;
return sqlite3PcacheFetchFinish(pCache,pgno,pPage);
}
@@ -43592,15 +39602,19 @@ SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish(
){
PgHdr *pPgHdr;
- assert( pPage!=0 );
+ if( pPage==0 ) return 0;
pPgHdr = (PgHdr *)pPage->pExtra;
if( !pPgHdr->pPage ){
return pcacheFetchFinishWithInit(pCache, pgno, pPage);
}
- pCache->nRefSum++;
+ if( 0==pPgHdr->nRef ){
+ pCache->nRef++;
+ }
pPgHdr->nRef++;
- assert( sqlite3PcachePageSanity(pPgHdr) );
+ if( pgno==1 ){
+ pCache->pPage1 = pPgHdr;
+ }
return pPgHdr;
}
@@ -43610,15 +39624,13 @@ SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish(
*/
SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
assert( p->nRef>0 );
- p->pCache->nRefSum--;
- if( (--p->nRef)==0 ){
- if( p->flags&PGHDR_CLEAN ){
+ p->nRef--;
+ if( p->nRef==0 ){
+ p->pCache->nRef--;
+ if( (p->flags&PGHDR_DIRTY)==0 ){
pcacheUnpin(p);
- }else if( p->pDirtyPrev!=0 ){ /*OPTIMIZATION-IF-FALSE*/
- /* Move the page to the head of the dirty list. If p->pDirtyPrev==0,
- ** then page p is already at the head of the dirty list and the
- ** following call would be a no-op. Hence the OPTIMIZATION-IF-FALSE
- ** tag above. */
+ }else if( p->pDirtyPrev!=0 ){
+ /* Move the page to the head of the dirty list. */
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
}
}
@@ -43629,9 +39641,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
*/
SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){
assert(p->nRef>0);
- assert( sqlite3PcachePageSanity(p) );
p->nRef++;
- p->pCache->nRefSum++;
}
/*
@@ -43641,11 +39651,13 @@ SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){
*/
SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){
assert( p->nRef==1 );
- assert( sqlite3PcachePageSanity(p) );
if( p->flags&PGHDR_DIRTY ){
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
}
- p->pCache->nRefSum--;
+ p->pCache->nRef--;
+ if( p->pgno==1 ){
+ p->pCache->pPage1 = 0;
+ }
sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 1);
}
@@ -43654,17 +39666,11 @@ SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){
** make it so.
*/
SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){
+ p->flags &= ~PGHDR_DONT_WRITE;
assert( p->nRef>0 );
- assert( sqlite3PcachePageSanity(p) );
- if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){ /*OPTIMIZATION-IF-FALSE*/
- p->flags &= ~PGHDR_DONT_WRITE;
- if( p->flags & PGHDR_CLEAN ){
- p->flags ^= (PGHDR_DIRTY|PGHDR_CLEAN);
- pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno));
- assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY );
- pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
- }
- assert( sqlite3PcachePageSanity(p) );
+ if( 0==(p->flags & PGHDR_DIRTY) ){
+ p->flags |= PGHDR_DIRTY;
+ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
}
}
@@ -43673,14 +39679,9 @@ SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){
** make it so.
*/
SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){
- assert( sqlite3PcachePageSanity(p) );
- if( ALWAYS((p->flags & PGHDR_DIRTY)!=0) ){
- assert( (p->flags & PGHDR_CLEAN)==0 );
+ if( (p->flags & PGHDR_DIRTY) ){
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
- p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE);
- p->flags |= PGHDR_CLEAN;
- pcacheTrace(("%p.CLEAN %d\n",p->pCache,p->pgno));
- assert( sqlite3PcachePageSanity(p) );
+ p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC);
if( p->nRef==0 ){
pcacheUnpin(p);
}
@@ -43692,25 +39693,12 @@ SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){
*/
SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache *pCache){
PgHdr *p;
- pcacheTrace(("%p.CLEAN-ALL\n",pCache));
while( (p = pCache->pDirty)!=0 ){
sqlite3PcacheMakeClean(p);
}
}
/*
-** Clear the PGHDR_NEED_SYNC and PGHDR_WRITEABLE flag from all dirty pages.
-*/
-SQLITE_PRIVATE void sqlite3PcacheClearWritable(PCache *pCache){
- PgHdr *p;
- pcacheTrace(("%p.CLEAR-WRITEABLE\n",pCache));
- for(p=pCache->pDirty; p; p=p->pDirtyNext){
- p->flags &= ~(PGHDR_NEED_SYNC|PGHDR_WRITEABLE);
- }
- pCache->pSynced = pCache->pDirtyTail;
-}
-
-/*
** Clear the PGHDR_NEED_SYNC flag from all dirty pages.
*/
SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *pCache){
@@ -43728,8 +39716,6 @@ SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
PCache *pCache = p->pCache;
assert( p->nRef>0 );
assert( newPgno>0 );
- assert( sqlite3PcachePageSanity(p) );
- pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno));
sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
p->pgno = newPgno;
if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
@@ -43750,7 +39736,6 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
if( pCache->pCache ){
PgHdr *p;
PgHdr *pNext;
- pcacheTrace(("%p.TRUNCATE %d\n",pCache,pgno));
for(p=pCache->pDirty; p; p=pNext){
pNext = p->pDirtyNext;
/* This routine never gets call with a positive pgno except right
@@ -43758,19 +39743,14 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
** it must be that pgno==0.
*/
assert( p->pgno>0 );
- if( p->pgno>pgno ){
+ if( ALWAYS(p->pgno>pgno) ){
assert( p->flags&PGHDR_DIRTY );
sqlite3PcacheMakeClean(p);
}
}
- if( pgno==0 && pCache->nRefSum ){
- sqlite3_pcache_page *pPage1;
- pPage1 = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache,1,0);
- if( ALWAYS(pPage1) ){ /* Page 1 is always available in cache, because
- ** pCache->nRefSum>0 */
- memset(pPage1->pBuf, 0, pCache->szPage);
- pgno = 1;
- }
+ if( pgno==0 && pCache->pPage1 ){
+ memset(pCache->pPage1->pData, 0, pCache->szPage);
+ pgno = 1;
}
sqlite3GlobalConfig.pcache2.xTruncate(pCache->pCache, pgno+1);
}
@@ -43781,7 +39761,6 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
*/
SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){
assert( pCache->pCache!=0 );
- pcacheTrace(("%p.CLOSE\n",pCache));
sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
}
@@ -43874,13 +39853,10 @@ SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
}
/*
-** Return the total number of references to all pages held by the cache.
-**
-** This is not the total number of pages referenced, but the sum of the
-** reference count for all pages.
+** Return the total number of referenced pages held by the cache.
*/
SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache *pCache){
- return pCache->nRefSum;
+ return pCache->nRef;
}
/*
@@ -43918,25 +39894,6 @@ SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
}
/*
-** Set the suggested cache-spill value. Make no changes if if the
-** argument is zero. Return the effective cache-spill size, which will
-** be the larger of the szSpill and szCache.
-*/
-SQLITE_PRIVATE int sqlite3PcacheSetSpillsize(PCache *p, int mxPage){
- int res;
- assert( p->pCache!=0 );
- if( mxPage ){
- if( mxPage<0 ){
- mxPage = (int)((-1024*(i64)mxPage)/(p->szPage+p->szExtra));
- }
- p->szSpill = mxPage;
- }
- res = numberOfCachePages(p);
- if( res<p->szSpill ) res = p->szSpill;
- return res;
-}
-
-/*
** Free up as much memory as possible from the page cache.
*/
SQLITE_PRIVATE void sqlite3PcacheShrink(PCache *pCache){
@@ -43950,17 +39907,6 @@ SQLITE_PRIVATE void sqlite3PcacheShrink(PCache *pCache){
*/
SQLITE_PRIVATE int sqlite3HeaderSizePcache(void){ return ROUND8(sizeof(PgHdr)); }
-/*
-** Return the number of dirty pages currently in the cache, as a percentage
-** of the configured cache size.
-*/
-SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache *pCache){
- PgHdr *pDirty;
- int nDirty = 0;
- int nCache = numberOfCachePages(pCache);
- for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext) nDirty++;
- return nCache ? (int)(((i64)nDirty * 100) / nCache) : 0;
-}
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
/*
@@ -43995,96 +39941,14 @@ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHd
** of the SQLITE_CONFIG_PAGECACHE and sqlite3_release_memory() features.
** If the default page cache implementation is overridden, then neither of
** these two features are available.
-**
-** A Page cache line looks like this:
-**
-** -------------------------------------------------------------
-** | database page content | PgHdr1 | MemPage | PgHdr |
-** -------------------------------------------------------------
-**
-** The database page content is up front (so that buffer overreads tend to
-** flow harmlessly into the PgHdr1, MemPage, and PgHdr extensions). MemPage
-** is the extension added by the btree.c module containing information such
-** as the database page number and how that database page is used. PgHdr
-** is added by the pcache.c layer and contains information used to keep track
-** of which pages are "dirty". PgHdr1 is an extension added by this
-** module (pcache1.c). The PgHdr1 header is a subclass of sqlite3_pcache_page.
-** PgHdr1 contains information needed to look up a page by its page number.
-** The superclass sqlite3_pcache_page.pBuf points to the start of the
-** database page content and sqlite3_pcache_page.pExtra points to PgHdr.
-**
-** The size of the extension (MemPage+PgHdr+PgHdr1) can be determined at
-** runtime using sqlite3_config(SQLITE_CONFIG_PCACHE_HDRSZ, &size). The
-** sizes of the extensions sum to 272 bytes on x64 for 3.8.10, but this
-** size can vary according to architecture, compile-time options, and
-** SQLite library version number.
-**
-** If SQLITE_PCACHE_SEPARATE_HEADER is defined, then the extension is obtained
-** using a separate memory allocation from the database page content. This
-** seeks to overcome the "clownshoe" problem (also called "internal
-** fragmentation" in academic literature) of allocating a few bytes more
-** than a power of two with the memory allocator rounding up to the next
-** power of two, and leaving the rounded-up space unused.
-**
-** This module tracks pointers to PgHdr1 objects. Only pcache.c communicates
-** with this module. Information is passed back and forth as PgHdr1 pointers.
-**
-** The pcache.c and pager.c modules deal pointers to PgHdr objects.
-** The btree.c module deals with pointers to MemPage objects.
-**
-** SOURCE OF PAGE CACHE MEMORY:
-**
-** Memory for a page might come from any of three sources:
-**
-** (1) The general-purpose memory allocator - sqlite3Malloc()
-** (2) Global page-cache memory provided using sqlite3_config() with
-** SQLITE_CONFIG_PAGECACHE.
-** (3) PCache-local bulk allocation.
-**
-** The third case is a chunk of heap memory (defaulting to 100 pages worth)
-** that is allocated when the page cache is created. The size of the local
-** bulk allocation can be adjusted using
-**
-** sqlite3_config(SQLITE_CONFIG_PAGECACHE, (void*)0, 0, N).
-**
-** If N is positive, then N pages worth of memory are allocated using a single
-** sqlite3Malloc() call and that memory is used for the first N pages allocated.
-** Or if N is negative, then -1024*N bytes of memory are allocated and used
-** for as many pages as can be accomodated.
-**
-** Only one of (2) or (3) can be used. Once the memory available to (2) or
-** (3) is exhausted, subsequent allocations fail over to the general-purpose
-** memory allocator (1).
-**
-** Earlier versions of SQLite used only methods (1) and (2). But experiments
-** show that method (3) with N==100 provides about a 5% performance boost for
-** common workloads.
*/
-/* #include "sqliteInt.h" */
+
typedef struct PCache1 PCache1;
typedef struct PgHdr1 PgHdr1;
typedef struct PgFreeslot PgFreeslot;
typedef struct PGroup PGroup;
-/*
-** Each cache entry is represented by an instance of the following
-** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
-** PgHdr1.pCache->szPage bytes is allocated directly before this structure
-** in memory.
-*/
-struct PgHdr1 {
- sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */
- unsigned int iKey; /* Key value (page number) */
- u8 isPinned; /* Page in use, not on the LRU list */
- u8 isBulkLocal; /* This page from bulk local storage */
- u8 isAnchor; /* This is the PGroup.lru element */
- PgHdr1 *pNext; /* Next in hash table chain */
- PCache1 *pCache; /* Cache that currently owns this page */
- PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */
- PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
-};
-
/* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set
** of one or more PCaches that are able to recycle each other's unpinned
** pages when they are under memory pressure. A PGroup is an instance of
@@ -44113,7 +39977,7 @@ struct PGroup {
unsigned int nMinPage; /* Sum of nMin for purgeable caches */
unsigned int mxPinned; /* nMaxpage + 10 - nMinPage */
unsigned int nCurrentPage; /* Number of purgeable pages allocated */
- PgHdr1 lru; /* The beginning and end of the LRU list */
+ PgHdr1 *pLruHead, *pLruTail; /* LRU list of unpinned pages */
};
/* Each page cache is an instance of the following object. Every
@@ -44131,9 +39995,8 @@ struct PCache1 {
** The PGroup mutex must be held when accessing nMax.
*/
PGroup *pGroup; /* PGroup this cache belongs to */
- int szPage; /* Size of database content section */
- int szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */
- int szAlloc; /* Total size of one pcache line */
+ int szPage; /* Size of allocated pages in bytes */
+ int szExtra; /* Size of extra space in bytes */
int bPurgeable; /* True if cache is purgeable */
unsigned int nMin; /* Minimum number of pages reserved */
unsigned int nMax; /* Configured "cache_size" value */
@@ -44147,13 +40010,27 @@ struct PCache1 {
unsigned int nPage; /* Total number of pages in apHash */
unsigned int nHash; /* Number of slots in apHash[] */
PgHdr1 **apHash; /* Hash table for fast lookup by key */
- PgHdr1 *pFree; /* List of unused pcache-local pages */
- void *pBulk; /* Bulk memory used by pcache-local */
};
/*
-** Free slots in the allocator used to divide up the global page cache
-** buffer provided using the SQLITE_CONFIG_PAGECACHE mechanism.
+** Each cache entry is represented by an instance of the following
+** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
+** PgHdr1.pCache->szPage bytes is allocated directly before this structure
+** in memory.
+*/
+struct PgHdr1 {
+ sqlite3_pcache_page page;
+ unsigned int iKey; /* Key value (page number) */
+ u8 isPinned; /* Page in use, not on the LRU list */
+ PgHdr1 *pNext; /* Next in hash table chain */
+ PCache1 *pCache; /* Cache that currently owns this page */
+ PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */
+ PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
+};
+
+/*
+** Free slots in the allocator used to divide up the buffer provided using
+** the SQLITE_CONFIG_PAGECACHE mechanism.
*/
struct PgFreeslot {
PgFreeslot *pNext; /* Next free slot */
@@ -44171,12 +40048,10 @@ static SQLITE_WSD struct PCacheGlobal {
** The nFreeSlot and pFree values do require mutex protection.
*/
int isInit; /* True if initialized */
- int separateCache; /* Use a new PGroup for each PCache */
- int nInitPage; /* Initial bulk allocation size */
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 global page cache memory */
+ void *pStart, *pEnd; /* Bounds of pagecache malloc range */
/* Above requires no mutex. Use mutex below for variable that follow. */
sqlite3_mutex *mutex; /* Mutex for accessing the following: */
PgFreeslot *pFree; /* Free page blocks */
@@ -44198,20 +40073,12 @@ static SQLITE_WSD struct PCacheGlobal {
/*
** Macros to enter and leave the PCache LRU mutex.
*/
-#if !defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || SQLITE_THREADSAFE==0
-# define pcache1EnterMutex(X) assert((X)->mutex==0)
-# define pcache1LeaveMutex(X) assert((X)->mutex==0)
-# define PCACHE1_MIGHT_USE_GROUP_MUTEX 0
-#else
-# define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex)
-# define pcache1LeaveMutex(X) sqlite3_mutex_leave((X)->mutex)
-# define PCACHE1_MIGHT_USE_GROUP_MUTEX 1
-#endif
+#define pcache1EnterMutex(X) sqlite3_mutex_enter((X)->mutex)
+#define pcache1LeaveMutex(X) sqlite3_mutex_leave((X)->mutex)
/******************************************************************************/
/******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/
-
/*
** This function is called during initialization if a static buffer is
** supplied to use for the page-cache by passing the SQLITE_CONFIG_PAGECACHE
@@ -44224,7 +40091,6 @@ static SQLITE_WSD struct PCacheGlobal {
SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
if( pcache1.isInit ){
PgFreeslot *p;
- if( pBuf==0 ) sz = n = 0;
sz = ROUNDDOWN8(sz);
pcache1.szSlot = sz;
pcache1.nSlot = pcache1.nFreeSlot = n;
@@ -44243,44 +40109,6 @@ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
}
/*
-** Try to initialize the pCache->pFree and pCache->pBulk fields. Return
-** true if pCache->pFree ends up containing one or more free pages.
-*/
-static int pcache1InitBulk(PCache1 *pCache){
- i64 szBulk;
- char *zBulk;
- if( pcache1.nInitPage==0 ) return 0;
- /* Do not bother with a bulk allocation if the cache size very small */
- if( pCache->nMax<3 ) return 0;
- sqlite3BeginBenignMalloc();
- if( pcache1.nInitPage>0 ){
- szBulk = pCache->szAlloc * (i64)pcache1.nInitPage;
- }else{
- szBulk = -1024 * (i64)pcache1.nInitPage;
- }
- if( szBulk > pCache->szAlloc*(i64)pCache->nMax ){
- szBulk = pCache->szAlloc*pCache->nMax;
- }
- zBulk = pCache->pBulk = sqlite3Malloc( szBulk );
- sqlite3EndBenignMalloc();
- if( zBulk ){
- int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc;
- int i;
- for(i=0; i<nBulk; i++){
- PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage];
- pX->page.pBuf = zBulk;
- pX->page.pExtra = &pX[1];
- pX->isBulkLocal = 1;
- pX->isAnchor = 0;
- pX->pNext = pCache->pFree;
- pCache->pFree = pX;
- zBulk += pCache->szAlloc;
- }
- }
- return pCache->pFree!=0;
-}
-
-/*
** Malloc function used within this file to allocate space from the buffer
** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no
** such buffer exists or there is no space left in it, this function falls
@@ -44300,7 +40128,7 @@ static void *pcache1Alloc(int nByte){
pcache1.nFreeSlot--;
pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
assert( pcache1.nFreeSlot>=0 );
- sqlite3StatusHighwater(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
+ sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_USED, 1);
}
sqlite3_mutex_leave(pcache1.mutex);
@@ -44314,7 +40142,7 @@ static void *pcache1Alloc(int nByte){
if( p ){
int sz = sqlite3MallocSize(p);
sqlite3_mutex_enter(pcache1.mutex);
- sqlite3StatusHighwater(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
+ sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
sqlite3_mutex_leave(pcache1.mutex);
}
@@ -44327,9 +40155,10 @@ static void *pcache1Alloc(int nByte){
/*
** Free an allocated buffer obtained from pcache1Alloc().
*/
-static void pcache1Free(void *p){
- if( p==0 ) return;
- if( SQLITE_WITHIN(p, pcache1.pStart, pcache1.pEnd) ){
+static int pcache1Free(void *p){
+ int nFreed = 0;
+ if( p==0 ) return 0;
+ if( p>=pcache1.pStart && p<pcache1.pEnd ){
PgFreeslot *pSlot;
sqlite3_mutex_enter(pcache1.mutex);
sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_USED, 1);
@@ -44343,17 +40172,15 @@ static void pcache1Free(void *p){
}else{
assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
+ nFreed = sqlite3MallocSize(p);
#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
- {
- int nFreed = 0;
- nFreed = sqlite3MallocSize(p);
- sqlite3_mutex_enter(pcache1.mutex);
- sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
- sqlite3_mutex_leave(pcache1.mutex);
- }
+ sqlite3_mutex_enter(pcache1.mutex);
+ sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
+ sqlite3_mutex_leave(pcache1.mutex);
#endif
sqlite3_free(p);
}
+ return nFreed;
}
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
@@ -44377,72 +40204,58 @@ static int pcache1MemSize(void *p){
/*
** Allocate a new page object initially associated with cache pCache.
*/
-static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
+static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
PgHdr1 *p = 0;
void *pPg;
+ /* The group mutex must be released before pcache1Alloc() is called. This
+ ** is because it may call sqlite3_release_memory(), which assumes that
+ ** this mutex is not held. */
assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
- if( pCache->pFree || (pCache->nPage==0 && pcache1InitBulk(pCache)) ){
- p = pCache->pFree;
- pCache->pFree = p->pNext;
- p->pNext = 0;
- }else{
-#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
- /* The group mutex must be released before pcache1Alloc() is called. This
- ** is because it might call sqlite3_release_memory(), which assumes that
- ** this mutex is not held. */
- assert( pcache1.separateCache==0 );
- assert( pCache->pGroup==&pcache1.grp );
- pcache1LeaveMutex(pCache->pGroup);
-#endif
- if( benignMalloc ){ sqlite3BeginBenignMalloc(); }
+ pcache1LeaveMutex(pCache->pGroup);
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
- pPg = pcache1Alloc(pCache->szPage);
- p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
- if( !pPg || !p ){
- pcache1Free(pPg);
- sqlite3_free(p);
- pPg = 0;
- }
+ pPg = pcache1Alloc(pCache->szPage);
+ p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
+ if( !pPg || !p ){
+ pcache1Free(pPg);
+ sqlite3_free(p);
+ pPg = 0;
+ }
#else
- pPg = pcache1Alloc(pCache->szAlloc);
- p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
+ pPg = pcache1Alloc(ROUND8(sizeof(PgHdr1)) + pCache->szPage + pCache->szExtra);
+ p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
#endif
- if( benignMalloc ){ sqlite3EndBenignMalloc(); }
-#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
- pcache1EnterMutex(pCache->pGroup);
-#endif
- if( pPg==0 ) return 0;
+ pcache1EnterMutex(pCache->pGroup);
+
+ if( pPg ){
p->page.pBuf = pPg;
p->page.pExtra = &p[1];
- p->isBulkLocal = 0;
- p->isAnchor = 0;
- }
- if( pCache->bPurgeable ){
- pCache->pGroup->nCurrentPage++;
+ if( pCache->bPurgeable ){
+ pCache->pGroup->nCurrentPage++;
+ }
+ return p;
}
- return p;
+ return 0;
}
/*
** Free a page object allocated by pcache1AllocPage().
+**
+** The pointer is allowed to be NULL, which is prudent. But it turns out
+** that the current implementation happens to never call this routine
+** with a NULL pointer, so we mark the NULL test with ALWAYS().
*/
static void pcache1FreePage(PgHdr1 *p){
- PCache1 *pCache;
- assert( p!=0 );
- pCache = p->pCache;
- assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) );
- if( p->isBulkLocal ){
- p->pNext = pCache->pFree;
- pCache->pFree = p;
- }else{
+ if( ALWAYS(p) ){
+ PCache1 *pCache = p->pCache;
+ assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) );
pcache1Free(p->page.pBuf);
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
sqlite3_free(p);
#endif
- }
- if( pCache->bPurgeable ){
- pCache->pGroup->nCurrentPage--;
+ if( pCache->bPurgeable ){
+ pCache->pGroup->nCurrentPage--;
+ }
}
}
@@ -44537,35 +40350,41 @@ static void pcache1ResizeHash(PCache1 *p){
**
** The PGroup mutex must be held when this function is called.
*/
-static PgHdr1 *pcache1PinPage(PgHdr1 *pPage){
+static void pcache1PinPage(PgHdr1 *pPage){
PCache1 *pCache;
+ PGroup *pGroup;
assert( pPage!=0 );
assert( pPage->isPinned==0 );
pCache = pPage->pCache;
- assert( pPage->pLruNext );
- assert( pPage->pLruPrev );
- assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
- pPage->pLruPrev->pLruNext = pPage->pLruNext;
- pPage->pLruNext->pLruPrev = pPage->pLruPrev;
+ pGroup = pCache->pGroup;
+ assert( pPage->pLruNext || pPage==pGroup->pLruTail );
+ assert( pPage->pLruPrev || pPage==pGroup->pLruHead );
+ assert( sqlite3_mutex_held(pGroup->mutex) );
+ if( pPage->pLruPrev ){
+ pPage->pLruPrev->pLruNext = pPage->pLruNext;
+ }else{
+ pGroup->pLruHead = pPage->pLruNext;
+ }
+ if( pPage->pLruNext ){
+ pPage->pLruNext->pLruPrev = pPage->pLruPrev;
+ }else{
+ pGroup->pLruTail = pPage->pLruPrev;
+ }
pPage->pLruNext = 0;
pPage->pLruPrev = 0;
pPage->isPinned = 1;
- assert( pPage->isAnchor==0 );
- assert( pCache->pGroup->lru.isAnchor==1 );
pCache->nRecyclable--;
- return pPage;
}
/*
** Remove the page supplied as an argument from the hash table
** (PCache1.apHash structure) that it is currently stored in.
-** Also free the page if freePage is true.
**
** The PGroup mutex must be held when this function is called.
*/
-static void pcache1RemoveFromHash(PgHdr1 *pPage, int freeFlag){
+static void pcache1RemoveFromHash(PgHdr1 *pPage){
unsigned int h;
PCache1 *pCache = pPage->pCache;
PgHdr1 **pp;
@@ -44576,28 +40395,21 @@ static void pcache1RemoveFromHash(PgHdr1 *pPage, int freeFlag){
*pp = (*pp)->pNext;
pCache->nPage--;
- if( freeFlag ) pcache1FreePage(pPage);
}
/*
** If there are currently more than nMaxPage pages allocated, try
** to recycle pages to reduce the number allocated to nMaxPage.
*/
-static void pcache1EnforceMaxPage(PCache1 *pCache){
- PGroup *pGroup = pCache->pGroup;
- PgHdr1 *p;
+static void pcache1EnforceMaxPage(PGroup *pGroup){
assert( sqlite3_mutex_held(pGroup->mutex) );
- while( pGroup->nCurrentPage>pGroup->nMaxPage
- && (p=pGroup->lru.pLruPrev)->isAnchor==0
- ){
+ while( pGroup->nCurrentPage>pGroup->nMaxPage && pGroup->pLruTail ){
+ PgHdr1 *p = pGroup->pLruTail;
assert( p->pCache->pGroup==pGroup );
assert( p->isPinned==0 );
pcache1PinPage(p);
- pcache1RemoveFromHash(p, 1);
- }
- if( pCache->nPage==0 && pCache->pBulk ){
- sqlite3_free(pCache->pBulk);
- pCache->pBulk = pCache->pFree = 0;
+ pcache1RemoveFromHash(p);
+ pcache1FreePage(p);
}
}
@@ -44643,44 +40455,9 @@ static int pcache1Init(void *NotUsed){
UNUSED_PARAMETER(NotUsed);
assert( pcache1.isInit==0 );
memset(&pcache1, 0, sizeof(pcache1));
-
-
- /*
- ** The pcache1.separateCache variable is true if each PCache has its own
- ** private PGroup (mode-1). pcache1.separateCache is false if the single
- ** PGroup in pcache1.grp is used for all page caches (mode-2).
- **
- ** * Always use a unified cache (mode-2) if ENABLE_MEMORY_MANAGEMENT
- **
- ** * Use a unified cache in single-threaded applications that have
- ** configured a start-time buffer for use as page-cache memory using
- ** sqlite3_config(SQLITE_CONFIG_PAGECACHE, pBuf, sz, N) with non-NULL
- ** pBuf argument.
- **
- ** * Otherwise use separate caches (mode-1)
- */
-#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT)
- pcache1.separateCache = 0;
-#elif SQLITE_THREADSAFE
- pcache1.separateCache = sqlite3GlobalConfig.pPage==0
- || sqlite3GlobalConfig.bCoreMutex>0;
-#else
- pcache1.separateCache = sqlite3GlobalConfig.pPage==0;
-#endif
-
-#if SQLITE_THREADSAFE
if( sqlite3GlobalConfig.bCoreMutex ){
- pcache1.grp.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_LRU);
- pcache1.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PMEM);
- }
-#endif
- if( pcache1.separateCache
- && sqlite3GlobalConfig.nPage!=0
- && sqlite3GlobalConfig.pPage==0
- ){
- pcache1.nInitPage = sqlite3GlobalConfig.nPage;
- }else{
- pcache1.nInitPage = 0;
+ 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;
@@ -44711,26 +40488,39 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
PGroup *pGroup; /* The group the new page cache will belong to */
int sz; /* Bytes of memory required to allocate the new cache */
+ /*
+ ** The separateCache variable is true if each PCache has its own private
+ ** PGroup. In other words, separateCache is true for mode (1) where no
+ ** mutexing is required.
+ **
+ ** * Always use a unified cache (mode-2) if ENABLE_MEMORY_MANAGEMENT
+ **
+ ** * Always use a unified cache in single-threaded applications
+ **
+ ** * Otherwise (if multi-threaded and ENABLE_MEMORY_MANAGEMENT is off)
+ ** use separate caches (mode-1)
+ */
+#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || SQLITE_THREADSAFE==0
+ const int separateCache = 0;
+#else
+ int separateCache = sqlite3GlobalConfig.bCoreMutex>0;
+#endif
+
assert( (szPage & (szPage-1))==0 && szPage>=512 && szPage<=65536 );
assert( szExtra < 300 );
- sz = sizeof(PCache1) + sizeof(PGroup)*pcache1.separateCache;
+ sz = sizeof(PCache1) + sizeof(PGroup)*separateCache;
pCache = (PCache1 *)sqlite3MallocZero(sz);
if( pCache ){
- if( pcache1.separateCache ){
+ if( separateCache ){
pGroup = (PGroup*)&pCache[1];
pGroup->mxPinned = 10;
}else{
pGroup = &pcache1.grp;
}
- if( pGroup->lru.isAnchor==0 ){
- pGroup->lru.isAnchor = 1;
- pGroup->lru.pLruPrev = pGroup->lru.pLruNext = &pGroup->lru;
- }
pCache->pGroup = pGroup;
pCache->szPage = szPage;
pCache->szExtra = szExtra;
- pCache->szAlloc = szPage + szExtra + ROUND8(sizeof(PgHdr1));
pCache->bPurgeable = (bPurgeable ? 1 : 0);
pcache1EnterMutex(pGroup);
pcache1ResizeHash(pCache);
@@ -44762,7 +40552,7 @@ static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
pCache->nMax = nMax;
pCache->n90pct = pCache->nMax*9/10;
- pcache1EnforceMaxPage(pCache);
+ pcache1EnforceMaxPage(pGroup);
pcache1LeaveMutex(pGroup);
}
}
@@ -44780,7 +40570,7 @@ static void pcache1Shrink(sqlite3_pcache *p){
pcache1EnterMutex(pGroup);
savedMaxPage = pGroup->nMaxPage;
pGroup->nMaxPage = 0;
- pcache1EnforceMaxPage(pCache);
+ pcache1EnforceMaxPage(pGroup);
pGroup->nMaxPage = savedMaxPage;
pcache1LeaveMutex(pGroup);
}
@@ -44833,17 +40623,26 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
assert( pCache->nHash>0 && pCache->apHash );
/* Step 4. Try to recycle a page. */
- if( pCache->bPurgeable
- && !pGroup->lru.pLruPrev->isAnchor
- && ((pCache->nPage+1>=pCache->nMax) || pcache1UnderMemoryPressure(pCache))
- ){
+ if( pCache->bPurgeable && pGroup->pLruTail && (
+ (pCache->nPage+1>=pCache->nMax)
+ || pGroup->nCurrentPage>=pGroup->nMaxPage
+ || pcache1UnderMemoryPressure(pCache)
+ )){
PCache1 *pOther;
- pPage = pGroup->lru.pLruPrev;
+ pPage = pGroup->pLruTail;
assert( pPage->isPinned==0 );
- pcache1RemoveFromHash(pPage, 0);
+ pcache1RemoveFromHash(pPage);
pcache1PinPage(pPage);
pOther = pPage->pCache;
- if( pOther->szAlloc != pCache->szAlloc ){
+
+ /* We want to verify that szPage and szExtra are the same for pOther
+ ** and pCache. Assert that we can verify this by comparing sums. */
+ assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 );
+ assert( pCache->szExtra<512 );
+ assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 );
+ assert( pOther->szExtra<512 );
+
+ if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){
pcache1FreePage(pPage);
pPage = 0;
}else{
@@ -44855,7 +40654,9 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
** attempt to allocate a new one.
*/
if( !pPage ){
- pPage = pcache1AllocPage(pCache, createFlag==1);
+ if( createFlag==1 ) sqlite3BeginBenignMalloc();
+ pPage = pcache1AllocPage(pCache);
+ if( createFlag==1 ) sqlite3EndBenignMalloc();
}
if( pPage ){
@@ -44929,13 +40730,8 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
** proceed to step 5.
**
** 5. Otherwise, allocate and return a new page buffer.
-**
-** There are two versions of this routine. pcache1FetchWithMutex() is
-** the general case. pcache1FetchNoMutex() is a faster implementation for
-** the common case where pGroup->mutex is NULL. The pcache1Fetch() wrapper
-** invokes the appropriate routine.
*/
-static PgHdr1 *pcache1FetchNoMutex(
+static sqlite3_pcache_page *pcache1Fetch(
sqlite3_pcache *p,
unsigned int iKey,
int createFlag
@@ -44943,66 +40739,28 @@ static PgHdr1 *pcache1FetchNoMutex(
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = 0;
+ assert( offsetof(PgHdr1,page)==0 );
+ assert( pCache->bPurgeable || createFlag!=1 );
+ assert( pCache->bPurgeable || pCache->nMin==0 );
+ assert( pCache->bPurgeable==0 || pCache->nMin==10 );
+ assert( pCache->nMin==0 || pCache->bPurgeable );
+ assert( pCache->nHash>0 );
+ pcache1EnterMutex(pCache->pGroup);
+
/* Step 1: Search the hash table for an existing entry. */
pPage = pCache->apHash[iKey % pCache->nHash];
while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; }
- /* Step 2: If the page was found in the hash table, then return it.
- ** If the page was not in the hash table and createFlag is 0, abort.
- ** Otherwise (page not in hash and createFlag!=0) continue with
- ** subsequent steps to try to create the page. */
+ /* Step 2: Abort if no existing page is found and createFlag is 0 */
if( pPage ){
- if( !pPage->isPinned ){
- return pcache1PinPage(pPage);
- }else{
- return pPage;
- }
+ if( !pPage->isPinned ) pcache1PinPage(pPage);
}else if( createFlag ){
/* Steps 3, 4, and 5 implemented by this subroutine */
- return pcache1FetchStage2(pCache, iKey, createFlag);
- }else{
- return 0;
+ pPage = pcache1FetchStage2(pCache, iKey, createFlag);
}
-}
-#if PCACHE1_MIGHT_USE_GROUP_MUTEX
-static PgHdr1 *pcache1FetchWithMutex(
- sqlite3_pcache *p,
- unsigned int iKey,
- int createFlag
-){
- PCache1 *pCache = (PCache1 *)p;
- PgHdr1 *pPage;
-
- pcache1EnterMutex(pCache->pGroup);
- pPage = pcache1FetchNoMutex(p, iKey, createFlag);
assert( pPage==0 || pCache->iMaxKey>=iKey );
pcache1LeaveMutex(pCache->pGroup);
- return pPage;
-}
-#endif
-static sqlite3_pcache_page *pcache1Fetch(
- sqlite3_pcache *p,
- unsigned int iKey,
- int createFlag
-){
-#if PCACHE1_MIGHT_USE_GROUP_MUTEX || defined(SQLITE_DEBUG)
- PCache1 *pCache = (PCache1 *)p;
-#endif
-
- assert( offsetof(PgHdr1,page)==0 );
- assert( pCache->bPurgeable || createFlag!=1 );
- assert( pCache->bPurgeable || pCache->nMin==0 );
- assert( pCache->bPurgeable==0 || pCache->nMin==10 );
- assert( pCache->nMin==0 || pCache->bPurgeable );
- assert( pCache->nHash>0 );
-#if PCACHE1_MIGHT_USE_GROUP_MUTEX
- if( pCache->pGroup->mutex ){
- return (sqlite3_pcache_page*)pcache1FetchWithMutex(p, iKey, createFlag);
- }else
-#endif
- {
- return (sqlite3_pcache_page*)pcache1FetchNoMutex(p, iKey, createFlag);
- }
+ return (sqlite3_pcache_page*)pPage;
}
@@ -45027,16 +40785,22 @@ static void pcache1Unpin(
** part of the PGroup LRU list.
*/
assert( pPage->pLruPrev==0 && pPage->pLruNext==0 );
+ assert( pGroup->pLruHead!=pPage && pGroup->pLruTail!=pPage );
assert( pPage->isPinned==1 );
if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){
- pcache1RemoveFromHash(pPage, 1);
+ pcache1RemoveFromHash(pPage);
+ pcache1FreePage(pPage);
}else{
/* Add the page to the PGroup LRU list. */
- PgHdr1 **ppFirst = &pGroup->lru.pLruNext;
- pPage->pLruPrev = &pGroup->lru;
- (pPage->pLruNext = *ppFirst)->pLruPrev = pPage;
- *ppFirst = pPage;
+ if( pGroup->pLruHead ){
+ pGroup->pLruHead->pLruPrev = pPage;
+ pPage->pLruNext = pGroup->pLruHead;
+ pGroup->pLruHead = pPage;
+ }else{
+ pGroup->pLruTail = pPage;
+ pGroup->pLruHead = pPage;
+ }
pCache->nRecyclable++;
pPage->isPinned = 0;
}
@@ -45113,9 +40877,8 @@ static void pcache1Destroy(sqlite3_pcache *p){
assert( pGroup->nMinPage >= pCache->nMin );
pGroup->nMinPage -= pCache->nMin;
pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
- pcache1EnforceMaxPage(pCache);
+ pcache1EnforceMaxPage(pGroup);
pcache1LeaveMutex(pGroup);
- sqlite3_free(pCache->pBulk);
sqlite3_free(pCache->apHash);
sqlite3_free(pCache);
}
@@ -45171,20 +40934,18 @@ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
int nFree = 0;
assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
assert( sqlite3_mutex_notheld(pcache1.mutex) );
- if( sqlite3GlobalConfig.nPage==0 ){
+ if( pcache1.pStart==0 ){
PgHdr1 *p;
pcache1EnterMutex(&pcache1.grp);
- while( (nReq<0 || nFree<nReq)
- && (p=pcache1.grp.lru.pLruPrev)!=0
- && p->isAnchor==0
- ){
+ while( (nReq<0 || nFree<nReq) && ((p=pcache1.grp.pLruTail)!=0) ){
nFree += pcache1MemSize(p->page.pBuf);
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
nFree += sqlite3MemSize(p);
#endif
assert( p->isPinned==0 );
pcache1PinPage(p);
- pcache1RemoveFromHash(p, 1);
+ pcache1RemoveFromHash(p);
+ pcache1FreePage(p);
}
pcache1LeaveMutex(&pcache1.grp);
}
@@ -45205,7 +40966,7 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
){
PgHdr1 *p;
int nRecyclable = 0;
- for(p=pcache1.grp.lru.pLruNext; p && !p->isAnchor; p=p->pLruNext){
+ for(p=pcache1.grp.pLruHead; p; p=p->pLruNext){
assert( p->isPinned==0 );
nRecyclable++;
}
@@ -45277,11 +41038,9 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
** of the first SMALLEST is O(NlogN). Second and subsequent SMALLEST
** primitives are constant time. The cost of DESTROY is O(N).
**
-** TEST and SMALLEST may not be used by the same RowSet. This used to
-** be possible, but the feature was not used, so it was removed in order
-** to simplify the code.
+** There is an added cost of O(N) when switching between TEST and
+** SMALLEST primitives.
*/
-/* #include "sqliteInt.h" */
/*
@@ -45400,11 +41159,9 @@ SQLITE_PRIVATE void sqlite3RowSetClear(RowSet *p){
*/
static struct RowSetEntry *rowSetEntryAlloc(RowSet *p){
assert( p!=0 );
- if( p->nFresh==0 ){ /*OPTIMIZATION-IF-FALSE*/
- /* We could allocate a fresh RowSetEntry each time one is needed, but it
- ** is more efficient to pull a preallocated entry from the pool */
+ if( p->nFresh==0 ){
struct RowSetChunk *pNew;
- pNew = sqlite3DbMallocRawNN(p->db, sizeof(*pNew));
+ pNew = sqlite3DbMallocRaw(p->db, sizeof(*pNew));
if( pNew==0 ){
return 0;
}
@@ -45436,9 +41193,7 @@ SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){
pEntry->pRight = 0;
pLast = p->pLast;
if( pLast ){
- if( rowid<=pLast->v ){ /*OPTIMIZATION-IF-FALSE*/
- /* Avoid unnecessary sorts by preserving the ROWSET_SORTED flags
- ** where possible */
+ if( (p->rsFlags & ROWSET_SORTED)!=0 && rowid<=pLast->v ){
p->rsFlags &= ~ROWSET_SORTED;
}
pLast->pRight = pEntry;
@@ -45560,29 +41315,23 @@ static struct RowSetEntry *rowSetNDeepTree(
){
struct RowSetEntry *p; /* Root of the new tree */
struct RowSetEntry *pLeft; /* Left subtree */
- if( *ppList==0 ){ /*OPTIMIZATION-IF-TRUE*/
- /* Prevent unnecessary deep recursion when we run out of entries */
- return 0;
- }
- if( iDepth>1 ){ /*OPTIMIZATION-IF-TRUE*/
- /* This branch causes a *balanced* tree to be generated. A valid tree
- ** is still generated without this branch, but the tree is wildly
- ** unbalanced and inefficient. */
- pLeft = rowSetNDeepTree(ppList, iDepth-1);
- p = *ppList;
- if( p==0 ){ /*OPTIMIZATION-IF-FALSE*/
- /* It is safe to always return here, but the resulting tree
- ** would be unbalanced */
- return pLeft;
- }
- p->pLeft = pLeft;
- *ppList = p->pRight;
- p->pRight = rowSetNDeepTree(ppList, iDepth-1);
- }else{
+ if( *ppList==0 ){
+ return 0;
+ }
+ if( iDepth==1 ){
p = *ppList;
*ppList = p->pRight;
p->pLeft = p->pRight = 0;
+ return p;
+ }
+ pLeft = rowSetNDeepTree(ppList, iDepth-1);
+ p = *ppList;
+ if( p==0 ){
+ return pLeft;
}
+ p->pLeft = pLeft;
+ *ppList = p->pRight;
+ p->pRight = rowSetNDeepTree(ppList, iDepth-1);
return p;
}
@@ -45610,36 +41359,58 @@ static struct RowSetEntry *rowSetListToTree(struct RowSetEntry *pList){
}
/*
+** Take all the entries on p->pEntry and on the trees in p->pForest and
+** sort them all together into one big ordered list on p->pEntry.
+**
+** This routine should only be called once in the life of a RowSet.
+*/
+static void rowSetToList(RowSet *p){
+
+ /* This routine is called only once */
+ assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 );
+
+ if( (p->rsFlags & ROWSET_SORTED)==0 ){
+ p->pEntry = rowSetEntrySort(p->pEntry);
+ }
+
+ /* While this module could theoretically support it, sqlite3RowSetNext()
+ ** is never called after sqlite3RowSetText() for the same RowSet. So
+ ** there is never a forest to deal with. Should this change, simply
+ ** remove the assert() and the #if 0. */
+ assert( p->pForest==0 );
+#if 0
+ while( p->pForest ){
+ struct RowSetEntry *pTree = p->pForest->pLeft;
+ if( pTree ){
+ struct RowSetEntry *pHead, *pTail;
+ rowSetTreeToList(pTree, &pHead, &pTail);
+ p->pEntry = rowSetEntryMerge(p->pEntry, pHead);
+ }
+ p->pForest = p->pForest->pRight;
+ }
+#endif
+ p->rsFlags |= ROWSET_NEXT; /* Verify this routine is never called again */
+}
+
+/*
** Extract the smallest element from the RowSet.
** Write the element into *pRowid. Return 1 on success. Return
** 0 if the RowSet is already empty.
**
** After this routine has been called, the sqlite3RowSetInsert()
-** routine may not be called again.
-**
-** This routine may not be called after sqlite3RowSetTest() has
-** been used. Older versions of RowSet allowed that, but as the
-** capability was not used by the code generator, it was removed
-** for code economy.
+** routine may not be called again.
*/
SQLITE_PRIVATE int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
assert( p!=0 );
- assert( p->pForest==0 ); /* Cannot be used with sqlite3RowSetText() */
/* Merge the forest into a single sorted list on first call */
- if( (p->rsFlags & ROWSET_NEXT)==0 ){ /*OPTIMIZATION-IF-FALSE*/
- if( (p->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/
- p->pEntry = rowSetEntrySort(p->pEntry);
- }
- p->rsFlags |= ROWSET_SORTED|ROWSET_NEXT;
- }
+ if( (p->rsFlags & ROWSET_NEXT)==0 ) rowSetToList(p);
/* Return the next entry on the list */
if( p->pEntry ){
*pRowid = p->pEntry->v;
p->pEntry = p->pEntry->pRight;
- if( p->pEntry==0 ){ /*OPTIMIZATION-IF-TRUE*/
- /* Free memory immediately, rather than waiting on sqlite3_finalize() */
+ if( p->pEntry==0 ){
sqlite3RowSetClear(p);
}
return 1;
@@ -45662,15 +41433,13 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
/* This routine is never called after sqlite3RowSetNext() */
assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 );
- /* Sort entries into the forest on the first test of a new batch.
- ** To save unnecessary work, only do this when the batch number changes.
+ /* Sort entries into the forest on the first test of a new batch
*/
- if( iBatch!=pRowSet->iBatch ){ /*OPTIMIZATION-IF-FALSE*/
+ if( iBatch!=pRowSet->iBatch ){
p = pRowSet->pEntry;
if( p ){
struct RowSetEntry **ppPrevTree = &pRowSet->pForest;
- if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/
- /* Only sort the current set of entiries if they need it */
+ if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){
p = rowSetEntrySort(p);
}
for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){
@@ -45741,7 +41510,6 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
** another is writing.
*/
#ifndef SQLITE_OMIT_DISKIO
-/* #include "sqliteInt.h" */
/************** Include wal.h in the middle of pager.c ***********************/
/************** Begin file wal.h *********************************************/
/*
@@ -45763,7 +41531,6 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
#ifndef _WAL_H_
#define _WAL_H_
-/* #include "sqliteInt.h" */
/* Additional values that can be added to the sync_flags argument of
** sqlite3WalFrames():
@@ -45790,7 +41557,6 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
# define sqlite3WalHeapMemory(z) 0
# define sqlite3WalFramesize(z) 0
# define sqlite3WalFindFrame(x,y,z) 0
-# define sqlite3WalFile(x) 0
#else
#define WAL_SAVEPOINT_NDATA 4
@@ -45873,11 +41639,6 @@ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op);
*/
SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal);
-#ifdef SQLITE_ENABLE_SNAPSHOT
-SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot);
-SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot);
-#endif
-
#ifdef SQLITE_ENABLE_ZIPVFS
/* If the WAL file is not empty, return the number of bytes of content
** stored in each frame (i.e. the db page-size when the WAL was created).
@@ -45885,9 +41646,6 @@ SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapsho
SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal);
#endif
-/* Return the sqlite3_file object for the WAL file */
-SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal);
-
#endif /* ifndef SQLITE_OMIT_WAL */
#endif /* _WAL_H_ */
@@ -46300,7 +42058,6 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
*/
#define MAX_SECTOR_SIZE 0x10000
-
/*
** An instance of the following structure is allocated for each active
** savepoint and statement transaction in the system. All such structures
@@ -46329,9 +42086,9 @@ struct PagerSavepoint {
/*
** Bits of the Pager.doNotSpill flag. See further description below.
*/
-#define SPILLFLAG_OFF 0x01 /* Never spill cache. Set via pragma */
-#define SPILLFLAG_ROLLBACK 0x02 /* Current rolling back, so do not spill */
-#define SPILLFLAG_NOSYNC 0x04 /* Spill is ok, but do not sync */
+#define SPILLFLAG_OFF 0x01 /* Never spill cache. Set via pragma */
+#define SPILLFLAG_ROLLBACK 0x02 /* Current rolling back, so do not spill */
+#define SPILLFLAG_NOSYNC 0x04 /* Spill is ok, but do not sync */
/*
** An open page cache is an instance of struct Pager. A description of
@@ -46413,11 +42170,11 @@ struct PagerSavepoint {
** while it is being traversed by code in pager_playback(). The SPILLFLAG_OFF
** case is a user preference.
**
-** If the SPILLFLAG_NOSYNC bit is set, writing to the database from
-** pagerStress() is permitted, but syncing the journal file is not.
-** This flag is set by sqlite3PagerWrite() when the file-system sector-size
-** is larger than the database page-size in order to prevent a journal sync
-** from happening in between the journalling of two pages on the same sector.
+** If the SPILLFLAG_NOSYNC bit is set, writing to the database from pagerStress()
+** is permitted, but syncing the journal file is not. This flag is set
+** by sqlite3PagerWrite() when the file-system sector-size is larger than
+** the database page-size in order to prevent a journal sync from happening
+** in between the journalling of two pages on the same sector.
**
** subjInMemory
**
@@ -46496,7 +42253,6 @@ struct Pager {
u8 useJournal; /* Use a rollback journal on this file */
u8 noSync; /* Do not sync the journal if true */
u8 fullSync; /* Do extra syncs of the journal for robustness */
- u8 extraSync; /* sync directory after journal delete */
u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */
u8 walSyncFlags; /* SYNC_NORMAL or SYNC_FULL for wal writes */
u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */
@@ -46521,7 +42277,7 @@ struct Pager {
u8 doNotSpill; /* Do not spill the cache when non-zero */
u8 subjInMemory; /* True to use in-memory sub-journals */
u8 bUseFetch; /* True to use xFetch() */
- u8 hasHeldSharedLock; /* True if a shared lock has ever been held */
+ u8 hasBeenUsed; /* True if any content previously read from this pager*/
Pgno dbSize; /* Number of pages in the database */
Pgno dbOrigSize; /* dbSize before the current transaction */
Pgno dbFileSize; /* Number of pages in the database file */
@@ -46682,7 +42438,7 @@ static const unsigned char aJournalMagic[] = {
**
** if( pPager->jfd->pMethods ){ ...
*/
-#define isOpen(pFd) ((pFd)->pMethods!=0)
+#define isOpen(pFd) ((pFd)->pMethods)
/*
** Return true if this pager uses a write-ahead log instead of the usual
@@ -46744,7 +42500,6 @@ static int assert_pager_state(Pager *p){
** state.
*/
if( MEMDB ){
- assert( !isOpen(p->fd) );
assert( p->noSync );
assert( p->journalMode==PAGER_JOURNALMODE_OFF
|| p->journalMode==PAGER_JOURNALMODE_MEMORY
@@ -46831,7 +42586,7 @@ static int assert_pager_state(Pager *p){
** back to OPEN state.
*/
assert( pPager->errCode!=SQLITE_OK );
- assert( sqlite3PcacheRefCount(pPager->pPCache)>0 || pPager->tempFile );
+ assert( sqlite3PcacheRefCount(pPager->pPCache)>0 );
break;
}
@@ -46906,21 +42661,19 @@ static int subjRequiresPage(PgHdr *pPg){
int i;
for(i=0; i<pPager->nSavepoint; i++){
p = &pPager->aSavepoint[i];
- if( p->nOrig>=pgno && 0==sqlite3BitvecTestNotNull(p->pInSavepoint, pgno) ){
+ if( p->nOrig>=pgno && 0==sqlite3BitvecTest(p->pInSavepoint, pgno) ){
return 1;
}
}
return 0;
}
-#ifdef SQLITE_DEBUG
/*
** Return true if the page is already in the journal file.
*/
static int pageInJournal(Pager *pPager, PgHdr *pPg){
return sqlite3BitvecTest(pPager->pInJournal, pPg->pgno);
}
-#endif
/*
** Read a 32-bit integer from the given file descriptor. Store the integer
@@ -47043,8 +42796,6 @@ static int jrnlBufferSize(Pager *pPager){
return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager);
}
-#else
-# define jrnlBufferSize(x) 0
#endif
/*
@@ -47205,7 +42956,6 @@ static i64 journalHdrOffset(Pager *pPager){
static int zeroJournalHdr(Pager *pPager, int doTruncate){
int rc = SQLITE_OK; /* Return code */
assert( isOpen(pPager->jfd) );
- assert( !sqlite3JournalIsInMemory(pPager->jfd) );
if( pPager->journalOff ){
const i64 iLimit = pPager->journalSizeLimit; /* Local cache of jsl */
@@ -47535,8 +43285,7 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
|| (0 != (rc = sqlite3OsWrite(pPager->jfd, zMaster, nMaster, iHdrOff+4)))
|| (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster, nMaster)))
|| (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster+4, cksum)))
- || (0 != (rc = sqlite3OsWrite(pPager->jfd, aJournalMagic, 8,
- iHdrOff+4+nMaster+8)))
+ || (0 != (rc = sqlite3OsWrite(pPager->jfd, aJournalMagic, 8, iHdrOff+4+nMaster+8)))
){
return rc;
}
@@ -47587,7 +43336,7 @@ static void releaseAllSavepoints(Pager *pPager){
for(ii=0; ii<pPager->nSavepoint; ii++){
sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint);
}
- if( !pPager->exclusiveMode || sqlite3JournalIsInMemory(pPager->sjfd) ){
+ if( !pPager->exclusiveMode || sqlite3IsMemJournal(pPager->sjfd) ){
sqlite3OsClose(pPager->sjfd);
}
sqlite3_free(pPager->aSavepoint);
@@ -47693,17 +43442,13 @@ static void pager_unlock(Pager *pPager){
** it can safely move back to PAGER_OPEN state. This happens in both
** normal and exclusive-locking mode.
*/
- assert( pPager->errCode==SQLITE_OK || !MEMDB );
if( pPager->errCode ){
- if( pPager->tempFile==0 ){
- pager_reset(pPager);
- pPager->changeCountDone = 0;
- pPager->eState = PAGER_OPEN;
- }else{
- pPager->eState = (isOpen(pPager->jfd) ? PAGER_OPEN : PAGER_READER);
- }
- if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
+ assert( !MEMDB );
+ pager_reset(pPager);
+ pPager->changeCountDone = pPager->tempFile;
+ pPager->eState = PAGER_OPEN;
pPager->errCode = SQLITE_OK;
+ if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
}
pPager->journalOff = 0;
@@ -47748,29 +43493,6 @@ static int pager_error(Pager *pPager, int rc){
static int pager_truncate(Pager *pPager, Pgno nPage);
/*
-** The write transaction open on pPager is being committed (bCommit==1)
-** or rolled back (bCommit==0).
-**
-** Return TRUE if and only if all dirty pages should be flushed to disk.
-**
-** Rules:
-**
-** * For non-TEMP databases, always sync to disk. This is necessary
-** for transactions to be durable.
-**
-** * Sync TEMP database only on a COMMIT (not a ROLLBACK) when the backing
-** file has been created already (via a spill on pagerStress()) and
-** when the number of dirty pages in memory exceeds 25% of the total
-** cache size.
-*/
-static int pagerFlushOnCommit(Pager *pPager, int bCommit){
- if( pPager->tempFile==0 ) return 1;
- if( !bCommit ) return 0;
- if( !isOpen(pPager->fd) ) return 0;
- return (sqlite3PCachePercentDirty(pPager->pPCache)>=25);
-}
-
-/*
** This routine ends a transaction. A transaction is usually ended by
** either a COMMIT or a ROLLBACK operation. This routine may be called
** after rollback of a hot-journal, or if an error occurs while opening
@@ -47852,8 +43574,8 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
assert( !pagerUseWal(pPager) );
/* Finalize the journal file. */
- if( sqlite3JournalIsInMemory(pPager->jfd) ){
- /* assert( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ); */
+ if( sqlite3IsMemJournal(pPager->jfd) ){
+ assert( pPager->journalMode==PAGER_JOURNALMODE_MEMORY );
sqlite3OsClose(pPager->jfd);
}else if( pPager->journalMode==PAGER_JOURNALMODE_TRUNCATE ){
if( pPager->journalOff==0 ){
@@ -47873,23 +43595,22 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
}else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST
|| (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL)
){
- rc = zeroJournalHdr(pPager, hasMaster||pPager->tempFile);
+ rc = zeroJournalHdr(pPager, hasMaster);
pPager->journalOff = 0;
}else{
/* This branch may be executed with Pager.journalMode==MEMORY if
** a hot-journal was just rolled back. In this case the journal
** file should be closed and deleted. If this connection writes to
- ** the database file, it will do so using an in-memory journal.
+ ** the database file, it will do so using an in-memory journal.
*/
- int bDelete = !pPager->tempFile;
- assert( sqlite3JournalIsInMemory(pPager->jfd)==0 );
+ int bDelete = (!pPager->tempFile && sqlite3JournalExists(pPager->jfd));
assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE
|| pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|| pPager->journalMode==PAGER_JOURNALMODE_WAL
);
sqlite3OsClose(pPager->jfd);
if( bDelete ){
- rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, pPager->extraSync);
+ rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
}
}
}
@@ -47908,14 +43629,8 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
sqlite3BitvecDestroy(pPager->pInJournal);
pPager->pInJournal = 0;
pPager->nRec = 0;
- if( rc==SQLITE_OK ){
- if( pagerFlushOnCommit(pPager, bCommit) ){
- sqlite3PcacheCleanAll(pPager->pPCache);
- }else{
- sqlite3PcacheClearWritable(pPager->pPCache);
- }
- sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize);
- }
+ sqlite3PcacheCleanAll(pPager->pPCache);
+ sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize);
if( pagerUseWal(pPager) ){
/* Drop the WAL write-lock, if any. Also, if the connection was in
@@ -48028,20 +43743,6 @@ static void pagerReportSize(Pager *pPager){
# define pagerReportSize(X) /* No-op if we do not support a codec */
#endif
-#ifdef SQLITE_HAS_CODEC
-/*
-** Make sure the number of reserved bits is the same in the destination
-** pager as it is in the source. This comes up when a VACUUM changes the
-** number of reserved bits to the "optimal" amount.
-*/
-SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager *pDest, Pager *pSrc){
- if( pDest->nReserve!=pSrc->nReserve ){
- pDest->nReserve = pSrc->nReserve;
- pagerReportSize(pDest);
- }
-}
-#endif
-
/*
** Read a single page from either the journal file (if isMainJrnl==1) or
** from the sub-journal (if isMainJrnl==0) and playback that page.
@@ -48144,7 +43845,7 @@ static int pager_playback_one_page(
}
}
- /* If this page has already been played back before during the current
+ /* If this page has already been played by before during the current
** rollback, then don't bother to play it back again.
*/
if( pDone && (rc = sqlite3BitvecSet(pDone, pgno))!=SQLITE_OK ){
@@ -48199,7 +43900,7 @@ static int pager_playback_one_page(
pPg = sqlite3PagerLookup(pPager, pgno);
}
assert( pPg || !MEMDB );
- assert( pPager->eState!=PAGER_OPEN || pPg==0 || pPager->tempFile );
+ assert( pPager->eState!=PAGER_OPEN || pPg==0 );
PAGERTRACE(("PLAYBACK %d page %d hash(%08x) %s\n",
PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, (u8*)aData),
(isMainJrnl?"main-journal":"sub-journal")
@@ -48221,9 +43922,9 @@ static int pager_playback_one_page(
pPager->dbFileSize = pgno;
}
if( pPager->pBackup ){
- CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
+ CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM);
sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
- CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData);
+ CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM, aData);
}
}else if( !isMainJrnl && pPg==0 ){
/* If this is a rollback of a savepoint and data was not written to
@@ -48245,10 +43946,11 @@ static int pager_playback_one_page(
assert( isSavepnt );
assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)==0 );
pPager->doNotSpill |= SPILLFLAG_ROLLBACK;
- rc = sqlite3PagerGet(pPager, pgno, &pPg, 1);
+ rc = sqlite3PagerAcquire(pPager, pgno, &pPg, 1);
assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)!=0 );
pPager->doNotSpill &= ~SPILLFLAG_ROLLBACK;
if( rc!=SQLITE_OK ) return rc;
+ pPg->flags &= ~PGHDR_NEED_READ;
sqlite3PcacheMakeDirty(pPg);
}
if( pPg ){
@@ -48262,10 +43964,29 @@ static int pager_playback_one_page(
pData = pPg->pData;
memcpy(pData, (u8*)aData, pPager->pageSize);
pPager->xReiniter(pPg);
- /* It used to be that sqlite3PcacheMakeClean(pPg) was called here. But
- ** that call was dangerous and had no detectable benefit since the cache
- ** is normally cleaned by sqlite3PcacheCleanAll() after rollback and so
- ** has been removed. */
+ if( isMainJrnl && (!isSavepnt || *pOffset<=pPager->journalHdr) ){
+ /* If the contents of this page were just restored from the main
+ ** journal file, then its content must be as they were when the
+ ** transaction was first opened. In this case we can mark the page
+ ** as clean, since there will be no need to write it out to the
+ ** database.
+ **
+ ** There is one exception to this rule. If the page is being rolled
+ ** back as part of a savepoint (or statement) rollback from an
+ ** unsynced portion of the main journal file, then it is not safe
+ ** to mark the page as clean. This is because marking the page as
+ ** clean will clear the PGHDR_NEED_SYNC flag. Since the page is
+ ** already in the journal file (recorded in Pager.pInJournal) and
+ ** the PGHDR_NEED_SYNC flag is cleared, if the page is written to
+ ** again within this transaction, it will be marked as dirty but
+ ** the PGHDR_NEED_SYNC flag will not be set. It could then potentially
+ ** be written out into the database file before its journal file
+ ** segment is synced. If a crash occurs during or following this,
+ ** database corruption may ensue.
+ */
+ assert( !pagerUseWal(pPager) );
+ sqlite3PcacheMakeClean(pPg);
+ }
pager_set_pagehash(pPg);
/* If this was page 1, then restore the value of Pager.dbFileVers.
@@ -48275,7 +43996,7 @@ static int pager_playback_one_page(
}
/* Decode the page just read from disk */
- CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT);
+ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM);
sqlite3PcacheRelease(pPg);
}
return rc;
@@ -48341,7 +44062,7 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){
pMaster = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile);
if( !pMaster ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}else{
const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0);
@@ -48358,7 +44079,7 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){
nMasterPtr = pVfs->mxPathname+1;
zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 1);
if( !zMasterJournal ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
goto delmaster_out;
}
zMasterPtr = &zMasterJournal[nMasterJournal+1];
@@ -48606,7 +44327,7 @@ static int pager_playback(Pager *pPager, int isHot){
** TODO: Technically the following is an error because it assumes that
** buffer Pager.pTmpSpace is (mxPathname+1) bytes or larger. i.e. that
** (pPager->pageSize >= pPager->pVfs->mxPathname+1). Using os_unix.c,
- ** mxPathname is 512, which is the same as the minimum allowable value
+ ** mxPathname is 512, which is the same as the minimum allowable value
** for pageSize.
*/
zMaster = pPager->pTmpSpace;
@@ -48828,7 +44549,7 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){
memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
}
}
- CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM_BKPT);
+ CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM);
PAGER_INCR(sqlite3_pager_readdb_count);
PAGER_INCR(pPager->nRead);
@@ -49056,20 +44777,22 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
*/
assert( pPager->eState==PAGER_OPEN );
assert( pPager->eLock>=SHARED_LOCK );
- assert( isOpen(pPager->fd) );
- assert( pPager->tempFile==0 );
nPage = sqlite3WalDbsize(pPager->pWal);
- /* If the number of pages in the database is not available from the
- ** WAL sub-system, determine the page counte based on the size of
- ** the database file. If the size of the database file is not an
- ** integer multiple of the page-size, round up the result.
+ /* If the database size was not available from the WAL sub-system,
+ ** determine it based on the size of the database file. If the size
+ ** of the database file is not an integer multiple of the page-size,
+ ** round down to the nearest page. Except, any file larger than 0
+ ** bytes in size is considered to contain at least one page.
*/
- if( nPage==0 && ALWAYS(isOpen(pPager->fd)) ){
+ if( nPage==0 ){
i64 n = 0; /* Size of db file in bytes */
- int rc = sqlite3OsFileSize(pPager->fd, &n);
- if( rc!=SQLITE_OK ){
- return rc;
+ assert( isOpen(pPager->fd) || pPager->tempFile );
+ if( isOpen(pPager->fd) ){
+ int rc = sqlite3OsFileSize(pPager->fd, &n);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
}
nPage = (Pgno)((n+pPager->pageSize-1) / pPager->pageSize);
}
@@ -49187,7 +44910,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
if( pSavepoint ){
pDone = sqlite3BitvecCreate(pSavepoint->nOrig);
if( !pDone ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
}
@@ -49283,22 +45006,13 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
}
/*
-** Change the maximum number of in-memory pages that are allowed
-** before attempting to recycle clean and unused pages.
+** Change the maximum number of in-memory pages that are allowed.
*/
SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){
sqlite3PcacheSetCachesize(pPager->pPCache, mxPage);
}
/*
-** Change the maximum number of in-memory pages that are allowed
-** before attempting to spill pages to journal.
-*/
-SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager *pPager, int mxPage){
- return sqlite3PcacheSetSpillsize(pPager->pPCache, mxPage);
-}
-
-/*
** Invoke SQLITE_FCNTL_MMAP_SIZE based on the current value of szMmap.
*/
static void pagerFixMaplimit(Pager *pPager){
@@ -49334,7 +45048,7 @@ SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
** The "level" in pgFlags & PAGER_SYNCHRONOUS_MASK sets the robustness
** of the database to damage due to OS crashes or power failures by
** changing the number of syncs()s when writing the journals.
-** There are four levels:
+** There are three levels:
**
** OFF sqlite3OsSync() is never called. This is the default
** for temporary and transient files.
@@ -49354,10 +45068,6 @@ SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
** assurance that the journal will not be corrupted to the
** point of causing damage to the database during rollback.
**
-** EXTRA This is like FULL except that is also syncs the directory
-** that contains the rollback journal after the rollback
-** journal is unlinked.
-**
** 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
@@ -49365,8 +45075,7 @@ SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
** 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. There is no difference between FULL
-** and EXTRA for WAL mode.
+** 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
@@ -49385,15 +45094,9 @@ SQLITE_PRIVATE void sqlite3PagerSetFlags(
unsigned pgFlags /* Various flags */
){
unsigned level = pgFlags & PAGER_SYNCHRONOUS_MASK;
- if( pPager->tempFile ){
- pPager->noSync = 1;
- pPager->fullSync = 0;
- pPager->extraSync = 0;
- }else{
- pPager->noSync = level==PAGER_SYNCHRONOUS_OFF ?1:0;
- pPager->fullSync = level>=PAGER_SYNCHRONOUS_FULL ?1:0;
- pPager->extraSync = level==PAGER_SYNCHRONOUS_EXTRA ?1:0;
- }
+ assert( level>=1 && level<=3 );
+ pPager->noSync = (level==1 || pPager->tempFile) ?1:0;
+ pPager->fullSync = (level==3 && !pPager->tempFile) ?1:0;
if( pPager->noSync ){
pPager->syncFlags = 0;
pPager->ckptSyncFlags = 0;
@@ -49555,7 +45258,7 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR
}
if( rc==SQLITE_OK ){
pNew = (char *)sqlite3PageMalloc(pageSize);
- if( !pNew ) rc = SQLITE_NOMEM_BKPT;
+ if( !pNew ) rc = SQLITE_NOMEM;
}
if( rc==SQLITE_OK ){
@@ -49831,7 +45534,7 @@ static int pagerAcquireMapPage(
*ppPage = p = (PgHdr *)sqlite3MallocZero(sizeof(PgHdr) + pPager->nExtra);
if( p==0 ){
sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1) * pPager->pageSize, pData);
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
p->pExtra = (void *)&p[1];
p->flags = PGHDR_MMAP;
@@ -50145,9 +45848,8 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
/* This function is only called for rollback pagers in WRITER_DBMOD state. */
assert( !pagerUseWal(pPager) );
- assert( pPager->tempFile || pPager->eState==PAGER_WRITER_DBMOD );
+ assert( pPager->eState==PAGER_WRITER_DBMOD );
assert( pPager->eLock==EXCLUSIVE_LOCK );
- assert( isOpen(pPager->fd) || pList->pDirty==0 );
/* If the file is a temp-file has not yet been opened, open it now. It
** is not possible for rc to be other than SQLITE_OK if this branch
@@ -50190,7 +45892,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
if( pList->pgno==1 ) pager_write_changecounter(pList);
/* Encode the database */
- CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM_BKPT, pData);
+ CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData);
/* Write out the page data. */
rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset);
@@ -50235,20 +45937,19 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
static int openSubJournal(Pager *pPager){
int rc = SQLITE_OK;
if( !isOpen(pPager->sjfd) ){
- const int flags = SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_READWRITE
- | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE
- | SQLITE_OPEN_DELETEONCLOSE;
- int nStmtSpill = sqlite3Config.nStmtSpill;
if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){
- nStmtSpill = -1;
+ sqlite3MemJournalOpen(pPager->sjfd);
+ }else{
+ rc = pagerOpentemp(pPager, pPager->sjfd, SQLITE_OPEN_SUBJOURNAL);
}
- rc = sqlite3JournalOpen(pPager->pVfs, 0, pPager->sjfd, flags, nStmtSpill);
}
return rc;
}
/*
** Append a record of the current state of page pPg to the sub-journal.
+** It is the callers responsibility to use subjRequiresPage() to check
+** that it is really required before calling this function.
**
** If successful, set the bit corresponding to pPg->pgno in the bitvecs
** for all open savepoints before returning.
@@ -50280,7 +45981,7 @@ static int subjournalPage(PgHdr *pPg){
i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
char *pData2;
- CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
+ CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
rc = write32bits(pPager->sjfd, offset, pPg->pgno);
if( rc==SQLITE_OK ){
@@ -50295,13 +45996,6 @@ static int subjournalPage(PgHdr *pPg){
}
return rc;
}
-static int subjournalPageIfRequired(PgHdr *pPg){
- if( subjRequiresPage(pPg) ){
- return subjournalPage(pPg);
- }else{
- return SQLITE_OK;
- }
-}
/*
** This function is called by the pcache layer when it has reached some
@@ -50359,7 +46053,9 @@ static int pagerStress(void *p, PgHdr *pPg){
pPg->pDirty = 0;
if( pagerUseWal(pPager) ){
/* Write a single frame for this page to the log. */
- rc = subjournalPageIfRequired(pPg);
+ if( subjRequiresPage(pPg) ){
+ rc = subjournalPage(pPg);
+ }
if( rc==SQLITE_OK ){
rc = pagerWalFrames(pPager, pPg, 0, 0);
}
@@ -50372,6 +46068,39 @@ static int pagerStress(void *p, PgHdr *pPg){
rc = syncJournal(pPager, 1);
}
+ /* If the page number of this page is larger than the current size of
+ ** the database image, it may need to be written to the sub-journal.
+ ** This is because the call to pager_write_pagelist() below will not
+ ** actually write data to the file in this case.
+ **
+ ** Consider the following sequence of events:
+ **
+ ** BEGIN;
+ ** <journal page X>
+ ** <modify page X>
+ ** SAVEPOINT sp;
+ ** <shrink database file to Y pages>
+ ** pagerStress(page X)
+ ** ROLLBACK TO sp;
+ **
+ ** If (X>Y), then when pagerStress is called page X will not be written
+ ** out to the database file, but will be dropped from the cache. Then,
+ ** following the "ROLLBACK TO sp" statement, reading page X will read
+ ** data from the database file. This will be the copy of page X as it
+ ** was when the transaction started, not as it was when "SAVEPOINT sp"
+ ** was executed.
+ **
+ ** The solution is to write the current data for page X into the
+ ** sub-journal file now (if it is not already there), so that it will
+ ** be restored to its current value when the "ROLLBACK TO sp" is
+ ** executed.
+ */
+ if( NEVER(
+ rc==SQLITE_OK && pPg->pgno>pPager->dbSize && subjRequiresPage(pPg)
+ ) ){
+ rc = subjournalPage(pPg);
+ }
+
/* Write the contents of the page out to the database file. */
if( rc==SQLITE_OK ){
assert( (pPg->flags&PGHDR_NEED_SYNC)==0 );
@@ -50388,25 +46117,6 @@ static int pagerStress(void *p, PgHdr *pPg){
return pager_error(pPager, rc);
}
-/*
-** Flush all unreferenced dirty pages to disk.
-*/
-SQLITE_PRIVATE int sqlite3PagerFlush(Pager *pPager){
- int rc = pPager->errCode;
- if( !MEMDB ){
- PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
- assert( assert_pager_state(pPager) );
- while( rc==SQLITE_OK && pList ){
- PgHdr *pNext = pList->pDirty;
- if( pList->nRef==0 ){
- rc = pagerStress((void*)pPager, pList);
- }
- pList = pNext;
- }
- }
-
- return rc;
-}
/*
** Allocate and initialize a new Pager object and put a pointer to it
@@ -50463,8 +46173,18 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
int nUri = 0; /* Number of bytes of URI args at *zUri */
/* Figure out how much space is required for each journal file-handle
- ** (there are two of them, the main journal and the sub-journal). */
- journalFileSize = ROUND8(sqlite3JournalSize(pVfs));
+ ** (there are two of them, the main journal and the sub-journal). This
+ ** is the maximum space required for an in-memory journal file handle
+ ** and a regular journal file-handle. Note that a "regular journal-handle"
+ ** may be a wrapper capable of caching the first portion of the journal
+ ** file in memory to implement the atomic-write optimization (see
+ ** source file journal.c).
+ */
+ if( sqlite3JournalSize(pVfs)>sqlite3MemJournalSize() ){
+ journalFileSize = ROUND8(sqlite3JournalSize(pVfs));
+ }else{
+ journalFileSize = ROUND8(sqlite3MemJournalSize());
+ }
/* Set the output variable to NULL in case an error occurs. */
*ppPager = 0;
@@ -50474,7 +46194,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
memDb = 1;
if( zFilename && zFilename[0] ){
zPathname = sqlite3DbStrDup(0, zFilename);
- if( zPathname==0 ) return SQLITE_NOMEM_BKPT;
+ if( zPathname==0 ) return SQLITE_NOMEM;
nPathname = sqlite3Strlen30(zPathname);
zFilename = 0;
}
@@ -50490,7 +46210,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
nPathname = pVfs->mxPathname+1;
zPathname = sqlite3DbMallocRaw(0, nPathname*2);
if( zPathname==0 ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */
rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
@@ -50543,7 +46263,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) );
if( !pPtr ){
sqlite3DbFree(0, zPathname);
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
pPager = (Pager*)(pPtr);
pPager->pPCache = (PCache*)(pPtr += ROUND8(sizeof(*pPager)));
@@ -50636,7 +46356,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
act_like_temp_file:
tempFile = 1;
pPager->eState = PAGER_READER; /* Pretend we already have a lock */
- pPager->eLock = EXCLUSIVE_LOCK; /* Pretend we are in EXCLUSIVE mode */
+ pPager->eLock = EXCLUSIVE_LOCK; /* Pretend we are in EXCLUSIVE locking mode */
pPager->noLock = 1; /* Do no locking */
readOnly = (vfsFlags&SQLITE_OPEN_READONLY);
}
@@ -50655,7 +46375,7 @@ act_like_temp_file:
assert( nExtra<1000 );
nExtra = ROUND8(nExtra);
rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb,
- !memDb?pagerStress:0, (void *)pPager, pPager->pPCache);
+ !memDb?pagerStress:0, (void *)pPager, pPager->pPCache);
}
/* If an error occurred above, free the Pager structure and close the file.
@@ -50692,13 +46412,11 @@ act_like_temp_file:
pPager->noSync = pPager->tempFile;
if( pPager->noSync ){
assert( pPager->fullSync==0 );
- assert( pPager->extraSync==0 );
assert( pPager->syncFlags==0 );
assert( pPager->walSyncFlags==0 );
assert( pPager->ckptSyncFlags==0 );
}else{
pPager->fullSync = 1;
- pPager->extraSync = 0;
pPager->syncFlags = SQLITE_SYNC_NORMAL;
pPager->walSyncFlags = SQLITE_SYNC_NORMAL | WAL_SYNC_TRANSACTIONS;
pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
@@ -50815,7 +46533,6 @@ static int hasHotJournal(Pager *pPager, int *pExists){
if( rc==SQLITE_OK && !locked ){
Pgno nPage; /* Number of pages in database file */
- assert( pPager->tempFile==0 );
rc = pagerPagecount(pPager, &nPage);
if( rc==SQLITE_OK ){
/* If the database is zero pages in size, that means that either (1) the
@@ -50877,7 +46594,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
/*
** This function is called to obtain a shared lock on the database file.
-** It is illegal to call sqlite3PagerGet() until after this function
+** It is illegal to call sqlite3PagerAcquire() until after this function
** has been successfully called. If a shared-lock is already held when
** this function is called, it is a no-op.
**
@@ -50908,17 +46625,17 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
/* This routine is only called from b-tree and only when there are no
** outstanding pages. This implies that the pager state should either
** be OPEN or READER. READER is only possible if the pager is or was in
- ** exclusive access mode. */
+ ** exclusive access mode.
+ */
assert( sqlite3PcacheRefCount(pPager->pPCache)==0 );
assert( assert_pager_state(pPager) );
assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER );
- assert( pPager->errCode==SQLITE_OK );
+ if( NEVER(MEMDB && pPager->errCode) ){ return pPager->errCode; }
if( !pagerUseWal(pPager) && pPager->eState==PAGER_OPEN ){
int bHotJournal = 1; /* True if there exists a hot journal-file */
assert( !MEMDB );
- assert( pPager->tempFile==0 || pPager->eLock==EXCLUSIVE_LOCK );
rc = pager_wait_on_lock(pPager, SHARED_LOCK);
if( rc!=SQLITE_OK ){
@@ -51004,7 +46721,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
assert( rc==SQLITE_OK );
rc = pagerSyncHotJournal(pPager);
if( rc==SQLITE_OK ){
- rc = pager_playback(pPager, !pPager->tempFile);
+ rc = pager_playback(pPager, 1);
pPager->eState = PAGER_OPEN;
}
}else if( !pPager->exclusiveMode ){
@@ -51038,14 +46755,14 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
);
}
- if( !pPager->tempFile && pPager->hasHeldSharedLock ){
+ if( !pPager->tempFile && pPager->hasBeenUsed ){
/* The shared-lock has just been acquired then check to
** see if the database has been modified. If the database has changed,
- ** flush the cache. The hasHeldSharedLock flag prevents this from
+ ** flush the cache. The pPager->hasBeenUsed flag prevents this from
** occurring on the very first access to a file, in order to save a
** single unnecessary sqlite3OsRead() call at the start-up.
**
- ** Database changes are detected by looking at 15 bytes beginning
+ ** Database changes is detected by looking at 15 bytes beginning
** at offset 24 into the file. The first 4 of these 16 bytes are
** a 32-bit counter that is incremented with each change. The
** other bytes change randomly with each file change when
@@ -51100,7 +46817,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
rc = pagerBeginReadTransaction(pPager);
}
- if( pPager->tempFile==0 && pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
+ if( pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
rc = pagerPagecount(pPager, &pPager->dbSize);
}
@@ -51111,7 +46828,6 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
assert( pPager->eState==PAGER_OPEN );
}else{
pPager->eState = PAGER_READER;
- pPager->hasHeldSharedLock = 1;
}
return rc;
}
@@ -51180,7 +46896,7 @@ static void pagerUnlockIfUnused(Pager *pPager){
** Since Lookup() never goes to disk, it never has to deal with locks
** or journal files.
*/
-SQLITE_PRIVATE int sqlite3PagerGet(
+SQLITE_PRIVATE int sqlite3PagerAcquire(
Pager *pPager, /* The pager open on the database file */
Pgno pgno, /* Page number to fetch */
DbPage **ppPage, /* Write a pointer to the page here */
@@ -51195,25 +46911,21 @@ SQLITE_PRIVATE int sqlite3PagerGet(
** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
** flag was specified by the caller. And so long as the db is not a
** temporary or in-memory database. */
- const int bMmapOk = (pgno>1 && USEFETCH(pPager)
+ const int bMmapOk = (pgno!=1 && USEFETCH(pPager)
&& (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
#ifdef SQLITE_HAS_CODEC
&& pPager->xCodec==0
#endif
);
- /* Optimization note: Adding the "pgno<=1" term before "pgno==0" here
- ** allows the compiler optimizer to reuse the results of the "pgno>1"
- ** test in the previous statement, and avoid testing pgno==0 in the
- ** common case where pgno is large. */
- if( pgno<=1 && pgno==0 ){
- return SQLITE_CORRUPT_BKPT;
- }
assert( pPager->eState>=PAGER_READER );
assert( assert_pager_state(pPager) );
assert( noContent==0 || bMmapOk==0 );
- assert( pPager->hasHeldSharedLock==1 );
+ if( pgno==0 ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+ pPager->hasBeenUsed = 1;
/* If the pager is in the error state, return an error immediately.
** Otherwise, request the page from the PCache layer. */
@@ -51233,7 +46945,7 @@ SQLITE_PRIVATE int sqlite3PagerGet(
);
if( rc==SQLITE_OK && pData ){
- if( pPager->eState>PAGER_READER || pPager->tempFile ){
+ if( pPager->eState>PAGER_READER ){
pPg = sqlite3PagerLookup(pPager, pgno);
}
if( pPg==0 ){
@@ -51258,14 +46970,9 @@ SQLITE_PRIVATE int sqlite3PagerGet(
if( pBase==0 ){
rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase);
if( rc!=SQLITE_OK ) goto pager_acquire_err;
- if( pBase==0 ){
- pPg = *ppPage = 0;
- rc = SQLITE_NOMEM_BKPT;
- goto pager_acquire_err;
- }
}
pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase);
- assert( pPg!=0 );
+ if( pPg==0 ) rc = SQLITE_NOMEM;
}
}
@@ -51276,11 +46983,10 @@ SQLITE_PRIVATE int sqlite3PagerGet(
pPg = 0;
goto pager_acquire_err;
}
- assert( pPg==(*ppPage) );
- assert( pPg->pgno==pgno );
- assert( pPg->pPager==pPager || pPg->pPager==0 );
+ assert( (*ppPage)->pgno==pgno );
+ assert( (*ppPage)->pPager==pPager || (*ppPage)->pPager==0 );
- if( pPg->pPager && !noContent ){
+ if( (*ppPage)->pPager && !noContent ){
/* In this case the pcache already contains an initialized copy of
** the page. Return without further ado. */
assert( pgno<=PAGER_MAX_PGNO && pgno!=PAGER_MJ_PGNO(pPager) );
@@ -51291,6 +46997,7 @@ SQLITE_PRIVATE int sqlite3PagerGet(
/* The pager cache has created a new page. Its content needs to
** be initialized. */
+ pPg = *ppPage;
pPg->pPager = pPager;
/* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page
@@ -51300,8 +47007,7 @@ SQLITE_PRIVATE int sqlite3PagerGet(
goto pager_acquire_err;
}
- assert( !isOpen(pPager->fd) || !MEMDB );
- if( !isOpen(pPager->fd) || pPager->dbSize<pgno || noContent ){
+ if( MEMDB || pPager->dbSize<pgno || noContent || !isOpen(pPager->fd) ){
if( pgno>pPager->mxPgno ){
rc = SQLITE_FULL;
goto pager_acquire_err;
@@ -51369,8 +47075,7 @@ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
assert( pgno!=0 );
assert( pPager->pPCache!=0 );
pPage = sqlite3PcacheFetch(pPager->pPCache, pgno, 0);
- assert( pPage==0 || pPager->hasHeldSharedLock );
- if( pPage==0 ) return 0;
+ assert( pPage==0 || pPager->hasBeenUsed );
return sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pPage);
}
@@ -51435,7 +47140,7 @@ static int pager_open_journal(Pager *pPager){
if( !pagerUseWal(pPager) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
pPager->pInJournal = sqlite3BitvecCreate(pPager->dbSize);
if( pPager->pInJournal==0 ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
/* Open the journal file if it is not already open. */
@@ -51443,24 +47148,24 @@ static int pager_open_journal(Pager *pPager){
if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){
sqlite3MemJournalOpen(pPager->jfd);
}else{
- int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
- int nSpill;
+ const int flags = /* VFS flags to open journal file */
+ SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
+ (pPager->tempFile ?
+ (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL):
+ (SQLITE_OPEN_MAIN_JOURNAL)
+ );
- if( pPager->tempFile ){
- flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL);
- nSpill = sqlite3Config.nStmtSpill;
- }else{
- flags |= SQLITE_OPEN_MAIN_JOURNAL;
- nSpill = jrnlBufferSize(pPager);
- }
-
/* Verify that the database still has the same name as it did when
** it was originally opened. */
rc = databaseIsUnmoved(pPager);
if( rc==SQLITE_OK ){
- rc = sqlite3JournalOpen (
- pVfs, pPager->zJournal, pPager->jfd, flags, nSpill
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+ rc = sqlite3JournalOpen(
+ pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager)
);
+#else
+ rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0);
+#endif
}
}
assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
@@ -51527,7 +47232,7 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory
if( rc!=SQLITE_OK ){
return rc;
}
- (void)sqlite3WalExclusiveMode(pPager->pWal, 1);
+ sqlite3WalExclusiveMode(pPager->pWal, 1);
}
/* Grab the write lock on the log file. If successful, upgrade to
@@ -51575,59 +47280,6 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory
}
/*
-** Write page pPg onto the end of the rollback journal.
-*/
-static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){
- Pager *pPager = pPg->pPager;
- int rc;
- u32 cksum;
- char *pData2;
- i64 iOff = pPager->journalOff;
-
- /* We should never write to the journal file the page that
- ** contains the database locks. The following assert verifies
- ** that we do not. */
- assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
-
- assert( pPager->journalHdr<=pPager->journalOff );
- CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
- cksum = pager_cksum(pPager, (u8*)pData2);
-
- /* Even if an IO or diskfull error occurs while journalling the
- ** page in the block above, set the need-sync flag for the page.
- ** Otherwise, when the transaction is rolled back, the logic in
- ** playback_one_page() will think that the page needs to be restored
- ** in the database file. And if an IO error occurs while doing so,
- ** then corruption may follow.
- */
- pPg->flags |= PGHDR_NEED_SYNC;
-
- rc = write32bits(pPager->jfd, iOff, pPg->pgno);
- if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3OsWrite(pPager->jfd, pData2, pPager->pageSize, iOff+4);
- if( rc!=SQLITE_OK ) return rc;
- rc = write32bits(pPager->jfd, iOff+pPager->pageSize+4, cksum);
- if( rc!=SQLITE_OK ) return rc;
-
- IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno,
- pPager->journalOff, pPager->pageSize));
- PAGER_INCR(sqlite3_pager_writej_count);
- PAGERTRACE(("JOURNAL %d page %d needSync=%d hash(%08x)\n",
- PAGERID(pPager), pPg->pgno,
- ((pPg->flags&PGHDR_NEED_SYNC)?1:0), pager_pagehash(pPg)));
-
- pPager->journalOff += 8 + pPager->pageSize;
- pPager->nRec++;
- assert( pPager->pInJournal!=0 );
- rc = sqlite3BitvecSet(pPager->pInJournal, pPg->pgno);
- testcase( rc==SQLITE_NOMEM );
- assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
- rc |= addToSavepointBitvecs(pPager, pPg->pgno);
- assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
- return rc;
-}
-
-/*
** Mark a single data page as writeable. The page is written into the
** main journal or sub-journal as required. If the page is written into
** one of the journals, the corresponding bit is set in the
@@ -51637,6 +47289,7 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){
static int pager_write(PgHdr *pPg){
Pager *pPager = pPg->pPager;
int rc = SQLITE_OK;
+ int inJournal;
/* This routine is not called unless a write-transaction has already
** been started. The journal file may or may not be open at this point.
@@ -51649,6 +47302,7 @@ static int pager_write(PgHdr *pPg){
assert( assert_pager_state(pPager) );
assert( pPager->errCode==0 );
assert( pPager->readOnly==0 );
+
CHECK_PAGE(pPg);
/* The journal file needs to be opened. Higher level routines have already
@@ -51667,48 +47321,91 @@ static int pager_write(PgHdr *pPg){
assert( pPager->eState>=PAGER_WRITER_CACHEMOD );
assert( assert_pager_state(pPager) );
- /* Mark the page that is about to be modified as dirty. */
- sqlite3PcacheMakeDirty(pPg);
-
- /* If a rollback journal is in use, them make sure the page that is about
- ** to change is in the rollback journal, or if the page is a new page off
- ** then end of the file, make sure it is marked as PGHDR_NEED_SYNC.
+ /* Mark the page as dirty. If the page has already been written
+ ** to the journal then we can return right away.
*/
- assert( (pPager->pInJournal!=0) == isOpen(pPager->jfd) );
- if( pPager->pInJournal!=0
- && sqlite3BitvecTestNotNull(pPager->pInJournal, pPg->pgno)==0
- ){
- assert( pagerUseWal(pPager)==0 );
- if( pPg->pgno<=pPager->dbOrigSize ){
- rc = pagerAddPageToRollbackJournal(pPg);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- }else{
- if( pPager->eState!=PAGER_WRITER_DBMOD ){
+ sqlite3PcacheMakeDirty(pPg);
+ inJournal = pageInJournal(pPager, pPg);
+ if( inJournal && (pPager->nSavepoint==0 || !subjRequiresPage(pPg)) ){
+ assert( !pagerUseWal(pPager) );
+ }else{
+
+ /* The transaction journal now exists and we have a RESERVED or an
+ ** EXCLUSIVE lock on the main database file. Write the current page to
+ ** the transaction journal if it is not there already.
+ */
+ if( !inJournal && !pagerUseWal(pPager) ){
+ assert( pagerUseWal(pPager)==0 );
+ if( pPg->pgno<=pPager->dbOrigSize && isOpen(pPager->jfd) ){
+ u32 cksum;
+ char *pData2;
+ i64 iOff = pPager->journalOff;
+
+ /* We should never write to the journal file the page that
+ ** contains the database locks. The following assert verifies
+ ** that we do not. */
+ assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
+
+ assert( pPager->journalHdr<=pPager->journalOff );
+ CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
+ cksum = pager_cksum(pPager, (u8*)pData2);
+
+ /* Even if an IO or diskfull error occurs while journalling the
+ ** page in the block above, set the need-sync flag for the page.
+ ** Otherwise, when the transaction is rolled back, the logic in
+ ** playback_one_page() will think that the page needs to be restored
+ ** in the database file. And if an IO error occurs while doing so,
+ ** then corruption may follow.
+ */
pPg->flags |= PGHDR_NEED_SYNC;
+
+ rc = write32bits(pPager->jfd, iOff, pPg->pgno);
+ if( rc!=SQLITE_OK ) return rc;
+ rc = sqlite3OsWrite(pPager->jfd, pData2, pPager->pageSize, iOff+4);
+ if( rc!=SQLITE_OK ) return rc;
+ rc = write32bits(pPager->jfd, iOff+pPager->pageSize+4, cksum);
+ if( rc!=SQLITE_OK ) return rc;
+
+ IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno,
+ pPager->journalOff, pPager->pageSize));
+ PAGER_INCR(sqlite3_pager_writej_count);
+ PAGERTRACE(("JOURNAL %d page %d needSync=%d hash(%08x)\n",
+ PAGERID(pPager), pPg->pgno,
+ ((pPg->flags&PGHDR_NEED_SYNC)?1:0), pager_pagehash(pPg)));
+
+ pPager->journalOff += 8 + pPager->pageSize;
+ pPager->nRec++;
+ assert( pPager->pInJournal!=0 );
+ rc = sqlite3BitvecSet(pPager->pInJournal, pPg->pgno);
+ testcase( rc==SQLITE_NOMEM );
+ assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
+ rc |= addToSavepointBitvecs(pPager, pPg->pgno);
+ if( rc!=SQLITE_OK ){
+ assert( rc==SQLITE_NOMEM );
+ return rc;
+ }
+ }else{
+ if( pPager->eState!=PAGER_WRITER_DBMOD ){
+ pPg->flags |= PGHDR_NEED_SYNC;
+ }
+ PAGERTRACE(("APPEND %d page %d needSync=%d\n",
+ PAGERID(pPager), pPg->pgno,
+ ((pPg->flags&PGHDR_NEED_SYNC)?1:0)));
}
- PAGERTRACE(("APPEND %d page %d needSync=%d\n",
- PAGERID(pPager), pPg->pgno,
- ((pPg->flags&PGHDR_NEED_SYNC)?1:0)));
}
- }
-
- /* The PGHDR_DIRTY bit is set above when the page was added to the dirty-list
- ** and before writing the page into the rollback journal. Wait until now,
- ** after the page has been successfully journalled, before setting the
- ** PGHDR_WRITEABLE bit that indicates that the page can be safely modified.
- */
- pPg->flags |= PGHDR_WRITEABLE;
- /* If the statement journal is open and the page is not in it,
- ** then write the page into the statement journal.
- */
- if( pPager->nSavepoint>0 ){
- rc = subjournalPageIfRequired(pPg);
+ /* If the statement journal is open and the page is not in it,
+ ** then write the current page to the statement journal. Note that
+ ** the statement journal format differs from the standard journal format
+ ** in that it omits the checksums and the header.
+ */
+ if( pPager->nSavepoint>0 && subjRequiresPage(pPg) ){
+ rc = subjournalPage(pPg);
+ }
}
- /* Update the database size and return. */
+ /* Update the database size and return.
+ */
if( pPager->dbSize<pPg->pgno ){
pPager->dbSize = pPg->pgno;
}
@@ -51723,17 +47420,17 @@ static int pager_write(PgHdr *pPg){
** a write.
**
** Usually, the sector size is less than or equal to the page size, in which
-** case pages can be individually written. This routine only runs in the
-** exceptional case where the page size is smaller than the sector size.
+** case pages can be individually written. This routine only runs in the exceptional
+** case where the page size is smaller than the sector size.
*/
static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){
- int rc = SQLITE_OK; /* Return code */
- Pgno nPageCount; /* Total number of pages in database file */
- Pgno pg1; /* First page of the sector pPg is located on. */
- int nPage = 0; /* Number of pages starting at pg1 to journal */
- int ii; /* Loop counter */
- int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */
- Pager *pPager = pPg->pPager; /* The pager that owns pPg */
+ int rc = SQLITE_OK; /* Return code */
+ Pgno nPageCount; /* Total number of pages in database file */
+ Pgno pg1; /* First page of the sector pPg is located on. */
+ int nPage = 0; /* Number of pages starting at pg1 to journal */
+ int ii; /* Loop counter */
+ int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */
+ Pager *pPager = pPg->pPager; /* The pager that owns pPg */
Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
/* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow
@@ -51767,7 +47464,7 @@ static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){
PgHdr *pPage;
if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){
if( pg!=PAGER_MJ_PGNO(pPager) ){
- rc = sqlite3PagerGet(pPager, pg, &pPage, 0);
+ rc = sqlite3PagerGet(pPager, pg, &pPage);
if( rc==SQLITE_OK ){
rc = pager_write(pPage);
if( pPage->flags&PGHDR_NEED_SYNC ){
@@ -51821,17 +47518,11 @@ static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){
** as appropriate. Otherwise, SQLITE_OK.
*/
SQLITE_PRIVATE int sqlite3PagerWrite(PgHdr *pPg){
- Pager *pPager = pPg->pPager;
assert( (pPg->flags & PGHDR_MMAP)==0 );
- assert( pPager->eState>=PAGER_WRITER_LOCKED );
- assert( assert_pager_state(pPager) );
- if( pPager->errCode ){
- return pPager->errCode;
- }else if( (pPg->flags & PGHDR_WRITEABLE)!=0 && pPager->dbSize>=pPg->pgno ){
- if( pPager->nSavepoint ) return subjournalPageIfRequired(pPg);
- return SQLITE_OK;
- }else if( pPager->sectorSize > (u32)pPager->pageSize ){
- assert( pPager->tempFile==0 );
+ assert( pPg->pPager->eState>=PAGER_WRITER_LOCKED );
+ assert( pPg->pPager->eState!=PAGER_ERROR );
+ assert( assert_pager_state(pPg->pPager) );
+ if( pPg->pPager->sectorSize > (u32)pPg->pPager->pageSize ){
return pagerWriteLargeSector(pPg);
}else{
return pager_write(pPg);
@@ -51845,7 +47536,7 @@ SQLITE_PRIVATE int sqlite3PagerWrite(PgHdr *pPg){
*/
#ifndef NDEBUG
SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage *pPg){
- return pPg->flags & PGHDR_WRITEABLE;
+ return pPg->flags&PGHDR_DIRTY;
}
#endif
@@ -51862,21 +47553,13 @@ SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage *pPg){
**
** Tests show that this optimization can quadruple the speed of large
** DELETE operations.
-**
-** This optimization cannot be used with a temp-file, as the page may
-** have been dirty at the start of the transaction. In that case, if
-** memory pressure forces page pPg out of the cache, the data does need
-** to be written out to disk so that it may be read back in if the
-** current transaction is rolled back.
*/
SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){
Pager *pPager = pPg->pPager;
- if( !pPager->tempFile && (pPg->flags&PGHDR_DIRTY) && pPager->nSavepoint==0 ){
+ if( (pPg->flags&PGHDR_DIRTY) && pPager->nSavepoint==0 ){
PAGERTRACE(("DONT_WRITE page %d of %d\n", pPg->pgno, PAGERID(pPager)));
IOTRACE(("CLEAN %p %d\n", pPager, pPg->pgno))
pPg->flags |= PGHDR_DONT_WRITE;
- pPg->flags &= ~PGHDR_WRITEABLE;
- testcase( pPg->flags & PGHDR_NEED_SYNC );
pager_set_pagehash(pPg);
}
}
@@ -51935,7 +47618,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
assert( !pPager->tempFile && isOpen(pPager->fd) );
/* Open page 1 of the file for writing. */
- rc = sqlite3PagerGet(pPager, 1, &pPgHdr, 0);
+ rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
assert( pPgHdr==0 || rc==SQLITE_OK );
/* If page one was fetched successfully, and this function is not
@@ -51955,7 +47638,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
if( DIRECT_MODE ){
const void *zBuf;
assert( pPager->dbFileSize>0 );
- CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM_BKPT, zBuf);
+ CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM, zBuf);
if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
pPager->aStat[PAGER_STAT_WRITE]++;
@@ -52013,17 +47696,14 @@ SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zMaster){
** returned.
*/
SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager *pPager){
- int rc = pPager->errCode;
+ int rc = SQLITE_OK;
+ assert( pPager->eState==PAGER_WRITER_CACHEMOD
+ || pPager->eState==PAGER_WRITER_DBMOD
+ || pPager->eState==PAGER_WRITER_LOCKED
+ );
assert( assert_pager_state(pPager) );
- if( rc==SQLITE_OK ){
- assert( pPager->eState==PAGER_WRITER_CACHEMOD
- || pPager->eState==PAGER_WRITER_DBMOD
- || pPager->eState==PAGER_WRITER_LOCKED
- );
- assert( assert_pager_state(pPager) );
- if( 0==pagerUseWal(pPager) ){
- rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
- }
+ if( 0==pagerUseWal(pPager) ){
+ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
}
return rc;
}
@@ -52071,21 +47751,17 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
/* If a prior error occurred, report that error again. */
if( NEVER(pPager->errCode) ) return pPager->errCode;
- /* Provide the ability to easily simulate an I/O error during testing */
- if( sqlite3FaultSim(400) ) return SQLITE_IOERR;
-
PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n",
pPager->zFilename, zMaster, pPager->dbSize));
/* If no database changes have been made, return early. */
if( pPager->eState<PAGER_WRITER_CACHEMOD ) return SQLITE_OK;
- assert( MEMDB==0 || pPager->tempFile );
- assert( isOpen(pPager->fd) || pPager->tempFile );
- if( 0==pagerFlushOnCommit(pPager, 1) ){
+ if( MEMDB ){
/* If this is an in-memory db, or no pages have been written to, or this
** function has already been called, it is mostly a no-op. However, any
- ** backup in progress needs to be restarted. */
+ ** backup in progress needs to be restarted.
+ */
sqlite3BackupRestart(pPager->pBackup);
}else{
if( pagerUseWal(pPager) ){
@@ -52094,7 +47770,7 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
if( pList==0 ){
/* Must have at least one page for the WAL commit flag.
** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */
- rc = sqlite3PagerGet(pPager, 1, &pPageOne, 0);
+ rc = sqlite3PagerGet(pPager, 1, &pPageOne);
pList = pPageOne;
pList->pDirty = 0;
}
@@ -52350,14 +48026,12 @@ SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager *pPager){
return pPager->readOnly;
}
-#ifdef SQLITE_DEBUG
/*
-** Return the sum of the reference counts for all pages held by pPager.
+** Return the number of references to the pager.
*/
SQLITE_PRIVATE int sqlite3PagerRefcount(Pager *pPager){
return sqlite3PcacheRefCount(pPager->pPCache);
}
-#endif
/*
** Return the approximate number of bytes of memory currently
@@ -52424,10 +48098,10 @@ SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, i
}
/*
-** Return true if this is an in-memory or temp-file backed pager.
+** Return true if this is an in-memory pager.
*/
SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){
- return pPager->tempFile;
+ return MEMDB;
}
/*
@@ -52440,63 +48114,55 @@ SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){
** occurs while opening the sub-journal file, then an IO error code is
** returned. Otherwise, SQLITE_OK.
*/
-static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){
+SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
int rc = SQLITE_OK; /* Return code */
int nCurrent = pPager->nSavepoint; /* Current number of savepoints */
- int ii; /* Iterator variable */
- PagerSavepoint *aNew; /* New Pager.aSavepoint array */
assert( pPager->eState>=PAGER_WRITER_LOCKED );
assert( assert_pager_state(pPager) );
- assert( nSavepoint>nCurrent && pPager->useJournal );
- /* Grow the Pager.aSavepoint array using realloc(). Return SQLITE_NOMEM
- ** if the allocation fails. Otherwise, zero the new portion in case a
- ** malloc failure occurs while populating it in the for(...) loop below.
- */
- aNew = (PagerSavepoint *)sqlite3Realloc(
- pPager->aSavepoint, sizeof(PagerSavepoint)*nSavepoint
- );
- if( !aNew ){
- return SQLITE_NOMEM_BKPT;
- }
- memset(&aNew[nCurrent], 0, (nSavepoint-nCurrent) * sizeof(PagerSavepoint));
- pPager->aSavepoint = aNew;
+ if( nSavepoint>nCurrent && pPager->useJournal ){
+ int ii; /* Iterator variable */
+ PagerSavepoint *aNew; /* New Pager.aSavepoint array */
- /* Populate the PagerSavepoint structures just allocated. */
- for(ii=nCurrent; ii<nSavepoint; ii++){
- aNew[ii].nOrig = pPager->dbSize;
- if( isOpen(pPager->jfd) && pPager->journalOff>0 ){
- aNew[ii].iOffset = pPager->journalOff;
- }else{
- aNew[ii].iOffset = JOURNAL_HDR_SZ(pPager);
- }
- aNew[ii].iSubRec = pPager->nSubRec;
- aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize);
- if( !aNew[ii].pInSavepoint ){
- return SQLITE_NOMEM_BKPT;
+ /* Grow the Pager.aSavepoint array using realloc(). Return SQLITE_NOMEM
+ ** if the allocation fails. Otherwise, zero the new portion in case a
+ ** malloc failure occurs while populating it in the for(...) loop below.
+ */
+ aNew = (PagerSavepoint *)sqlite3Realloc(
+ pPager->aSavepoint, sizeof(PagerSavepoint)*nSavepoint
+ );
+ if( !aNew ){
+ return SQLITE_NOMEM;
}
- if( pagerUseWal(pPager) ){
- sqlite3WalSavepoint(pPager->pWal, aNew[ii].aWalData);
+ memset(&aNew[nCurrent], 0, (nSavepoint-nCurrent) * sizeof(PagerSavepoint));
+ pPager->aSavepoint = aNew;
+
+ /* Populate the PagerSavepoint structures just allocated. */
+ for(ii=nCurrent; ii<nSavepoint; ii++){
+ aNew[ii].nOrig = pPager->dbSize;
+ if( isOpen(pPager->jfd) && pPager->journalOff>0 ){
+ aNew[ii].iOffset = pPager->journalOff;
+ }else{
+ aNew[ii].iOffset = JOURNAL_HDR_SZ(pPager);
+ }
+ aNew[ii].iSubRec = pPager->nSubRec;
+ aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize);
+ if( !aNew[ii].pInSavepoint ){
+ return SQLITE_NOMEM;
+ }
+ if( pagerUseWal(pPager) ){
+ sqlite3WalSavepoint(pPager->pWal, aNew[ii].aWalData);
+ }
+ pPager->nSavepoint = ii+1;
}
- pPager->nSavepoint = ii+1;
+ assert( pPager->nSavepoint==nSavepoint );
+ assertTruncateConstraint(pPager);
}
- assert( pPager->nSavepoint==nSavepoint );
- assertTruncateConstraint(pPager);
- return rc;
-}
-SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
- assert( pPager->eState>=PAGER_WRITER_LOCKED );
- assert( assert_pager_state(pPager) );
- if( nSavepoint>pPager->nSavepoint && pPager->useJournal ){
- return pagerOpenSavepoint(pPager, nSavepoint);
- }else{
- return SQLITE_OK;
- }
+ return rc;
}
-
/*
** This function is called to rollback or release (commit) a savepoint.
** The savepoint to release or rollback need not be the most recently
@@ -52552,7 +48218,7 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
if( op==SAVEPOINT_RELEASE ){
if( nNew==0 && isOpen(pPager->sjfd) ){
/* Only truncate if it is an in-memory sub-journal. */
- if( sqlite3JournalIsInMemory(pPager->sjfd) ){
+ if( sqlite3IsMemJournal(pPager->sjfd) ){
rc = sqlite3OsTruncate(pPager->sjfd, 0);
assert( rc==SQLITE_OK );
}
@@ -52591,7 +48257,7 @@ SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager *pPager, int nullIfMemDb){
/*
** Return the VFS structure for the pager.
*/
-SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){
+SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){
return pPager->pVfs;
}
@@ -52605,22 +48271,18 @@ SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){
}
/*
-** Return the file handle for the journal file (if it exists).
-** This will be either the rollback journal or the WAL file.
+** Return the full pathname of the journal file.
*/
-SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){
-#if SQLITE_OMIT_WAL
- return pPager->jfd;
-#else
- return pPager->pWal ? sqlite3WalFile(pPager->pWal) : pPager->jfd;
-#endif
+SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){
+ return pPager->zJournal;
}
/*
-** Return the full pathname of the journal file.
+** Return true if fsync() calls are disabled for this pager. Return FALSE
+** if fsync()s are executed normally.
*/
-SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){
- return pPager->zJournal;
+SQLITE_PRIVATE int sqlite3PagerNosync(Pager *pPager){
+ return pPager->noSync;
}
#ifdef SQLITE_HAS_CODEC
@@ -52707,8 +48369,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
/* In order to be able to rollback, an in-memory database must journal
** the page we are moving from.
*/
- assert( pPager->tempFile || !MEMDB );
- if( pPager->tempFile ){
+ if( MEMDB ){
rc = sqlite3PagerWrite(pPg);
if( rc ) return rc;
}
@@ -52731,8 +48392,9 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
** one or more savepoint bitvecs. This is the reason this function
** may return SQLITE_NOMEM.
*/
- if( (pPg->flags & PGHDR_DIRTY)!=0
- && SQLITE_OK!=(rc = subjournalPageIfRequired(pPg))
+ if( pPg->flags&PGHDR_DIRTY
+ && subjRequiresPage(pPg)
+ && SQLITE_OK!=(rc = subjournalPage(pPg))
){
return rc;
}
@@ -52765,7 +48427,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
assert( !pPgOld || pPgOld->nRef==1 );
if( pPgOld ){
pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
- if( pPager->tempFile ){
+ if( MEMDB ){
/* Do not discard pages from an in-memory database since we might
** need to rollback later. Just move the page out of the way. */
sqlite3PcacheMove(pPgOld, pPager->dbSize+1);
@@ -52782,7 +48444,8 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
** to exist, in case the transaction needs to roll back. Use pPgOld
** as the original page since it has already been allocated.
*/
- if( pPager->tempFile && pPgOld ){
+ if( MEMDB ){
+ assert( pPgOld );
sqlite3PcacheMove(pPgOld, origPgno);
sqlite3PagerUnrefNotNull(pPgOld);
}
@@ -52803,7 +48466,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
** the journal file twice, but that is not a problem.
*/
PgHdr *pPgHdr;
- rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr, 0);
+ rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr);
if( rc!=SQLITE_OK ){
if( needSyncPgno<=pPager->dbOrigSize ){
assert( pPager->pTmpSpace!=0 );
@@ -53034,8 +48697,7 @@ SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){
** Unless this is an in-memory or temporary database, clear the pager cache.
*/
SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){
- assert( MEMDB==0 || pPager->tempFile );
- if( pPager->tempFile==0 ) pager_reset(pPager);
+ if( !MEMDB && pPager->tempFile==0 ) pager_reset(pPager);
}
#endif
@@ -53070,7 +48732,6 @@ SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
*/
SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){
const sqlite3_io_methods *pMethods = pPager->fd->pMethods;
- if( pPager->noLock ) return 0;
return pPager->exclusiveMode || (pMethods->iVersion>=2 && pMethods->xShmMap);
}
@@ -53214,40 +48875,11 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
pPager->pageSize, (u8*)pPager->pTmpSpace);
pPager->pWal = 0;
pagerFixMaplimit(pPager);
- if( rc && !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK);
}
}
return rc;
}
-#ifdef SQLITE_ENABLE_SNAPSHOT
-/*
-** If this is a WAL database, obtain a snapshot handle for the snapshot
-** currently open. Otherwise, return an error.
-*/
-SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot){
- int rc = SQLITE_ERROR;
- if( pPager->pWal ){
- rc = sqlite3WalSnapshotGet(pPager->pWal, ppSnapshot);
- }
- return rc;
-}
-
-/*
-** If this is a WAL database, store a pointer to pSnapshot. Next time a
-** read transaction is opened, attempt to read from the snapshot it
-** identifies. If this is not a WAL database, return an error.
-*/
-SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot){
- int rc = SQLITE_OK;
- if( pPager->pWal ){
- sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot);
- }else{
- rc = SQLITE_ERROR;
- }
- return rc;
-}
-#endif /* SQLITE_ENABLE_SNAPSHOT */
#endif /* !SQLITE_OMIT_WAL */
#ifdef SQLITE_ENABLE_ZIPVFS
@@ -53513,7 +49145,6 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
*/
#ifndef SQLITE_OMIT_WAL
-/* #include "wal.h" */
/*
** Trace output macros
@@ -53543,8 +49174,7 @@ SQLITE_PRIVATE int sqlite3WalTrace = 0;
/*
** Indices of various locking bytes. WAL_NREADER is the number
-** of available reader locks and should be at least 3. The default
-** is SQLITE_SHM_NLOCK==8 and WAL_NREADER==5.
+** of available reader locks and should be at least 3.
*/
#define WAL_WRITE_LOCK 0
#define WAL_ALL_BUT_WRITE 1
@@ -53564,10 +49194,7 @@ typedef struct WalCkptInfo WalCkptInfo;
** The following object holds a copy of the wal-index header content.
**
** The actual header in the wal-index consists of two copies of this
-** object followed by one instance of the WalCkptInfo object.
-** For all versions of SQLite through 3.10.0 and probably beyond,
-** the locking bytes (WalCkptInfo.aLock) start at offset 120 and
-** the total header size is 136 bytes.
+** object.
**
** The szPage value can be any power of 2 between 512 and 32768, inclusive.
** Or it can be 1 to represent a 65536-byte page. The latter case was
@@ -53600,16 +49227,6 @@ struct WalIndexHdr {
** However, a WAL_WRITE_LOCK thread can move the value of nBackfill from
** mxFrame back to zero when the WAL is reset.
**
-** nBackfillAttempted is the largest value of nBackfill that a checkpoint
-** has attempted to achieve. Normally nBackfill==nBackfillAtempted, however
-** the nBackfillAttempted is set before any backfilling is done and the
-** nBackfill is only set after all backfilling completes. So if a checkpoint
-** crashes, nBackfillAttempted might be larger than nBackfill. The
-** WalIndexHdr.mxFrame must never be less than nBackfillAttempted.
-**
-** The aLock[] field is a set of bytes used for locking. These bytes should
-** never be read or written.
-**
** There is one entry in aReadMark[] for each reader lock. If a reader
** holds read-lock K, then the value in aReadMark[K] is no greater than
** the mxFrame for that reader. The value READMARK_NOT_USED (0xffffffff)
@@ -53649,9 +49266,6 @@ struct WalIndexHdr {
struct WalCkptInfo {
u32 nBackfill; /* Number of WAL frames backfilled into DB */
u32 aReadMark[WAL_NREADER]; /* Reader marks */
- u8 aLock[SQLITE_SHM_NLOCK]; /* Reserved space for locks */
- u32 nBackfillAttempted; /* WAL frames perhaps written, or maybe not */
- u32 notUsed0; /* Available for future enhancements */
};
#define READMARK_NOT_USED 0xffffffff
@@ -53661,8 +49275,9 @@ struct WalCkptInfo {
** only support mandatory file-locks, we do not read or write data
** from the region of the file on which locks are applied.
*/
-#define WALINDEX_LOCK_OFFSET (sizeof(WalIndexHdr)*2+offsetof(WalCkptInfo,aLock))
-#define WALINDEX_HDR_SIZE (sizeof(WalIndexHdr)*2+sizeof(WalCkptInfo))
+#define WALINDEX_LOCK_OFFSET (sizeof(WalIndexHdr)*2 + sizeof(WalCkptInfo))
+#define WALINDEX_LOCK_RESERVED 16
+#define WALINDEX_HDR_SIZE (WALINDEX_LOCK_OFFSET+WALINDEX_LOCK_RESERVED)
/* Size of header before each frame in wal */
#define WAL_FRAME_HDRSIZE 24
@@ -53715,16 +49330,11 @@ struct Wal {
u8 syncHeader; /* Fsync the WAL header if true */
u8 padToSectorBoundary; /* Pad transactions out to the next sector */
WalIndexHdr hdr; /* Wal-index header for current transaction */
- u32 minFrame; /* Ignore wal frames before this one */
- u32 iReCksum; /* On commit, recalculate checksums from here */
const char *zWalName; /* Name of WAL file */
u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
#ifdef SQLITE_DEBUG
u8 lockError; /* True if a locking error has occurred */
#endif
-#ifdef SQLITE_ENABLE_SNAPSHOT
- WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
-#endif
};
/*
@@ -53817,7 +49427,7 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte);
if( !apNew ){
*ppPage = 0;
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
memset((void*)&apNew[pWal->nWiData], 0,
sizeof(u32*)*(iPage+1-pWal->nWiData));
@@ -53829,7 +49439,7 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
if( pWal->apWiData[iPage]==0 ){
if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ);
- if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM_BKPT;
+ if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM;
}else{
rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
@@ -53940,9 +49550,9 @@ static void walIndexWriteHdr(Wal *pWal){
pWal->hdr.isInit = 1;
pWal->hdr.iVersion = WALINDEX_MAX_VERSION;
walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum);
- memcpy((void*)&aHdr[1], (const void*)&pWal->hdr, sizeof(WalIndexHdr));
+ memcpy((void *)&aHdr[1], (void *)&pWal->hdr, sizeof(WalIndexHdr));
walShmBarrier(pWal);
- memcpy((void*)&aHdr[0], (const void*)&pWal->hdr, sizeof(WalIndexHdr));
+ memcpy((void *)&aHdr[0], (void *)&pWal->hdr, sizeof(WalIndexHdr));
}
/*
@@ -53970,18 +49580,14 @@ static void walEncodeFrame(
assert( WAL_FRAME_HDRSIZE==24 );
sqlite3Put4byte(&aFrame[0], iPage);
sqlite3Put4byte(&aFrame[4], nTruncate);
- if( pWal->iReCksum==0 ){
- memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
+ memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
- nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
- walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
- walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
+ nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
+ walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
+ walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
- sqlite3Put4byte(&aFrame[16], aCksum[0]);
- sqlite3Put4byte(&aFrame[20], aCksum[1]);
- }else{
- memset(&aFrame[8], 0, 16);
- }
+ sqlite3Put4byte(&aFrame[16], aCksum[0]);
+ sqlite3Put4byte(&aFrame[20], aCksum[1]);
}
/*
@@ -54084,9 +49690,10 @@ static void walUnlockShared(Wal *pWal, int lockIdx){
SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED);
WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
}
-static int walLockExclusive(Wal *pWal, int lockIdx, int n){
+static int walLockExclusive(Wal *pWal, int lockIdx, int n, int fBlock){
int rc;
if( pWal->exclusiveMode ) return SQLITE_OK;
+ if( fBlock ) sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_WAL_BLOCK, 0);
rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
@@ -54247,13 +49854,13 @@ static void walCleanupHash(Wal *pWal){
** via the hash table even after the cleanup.
*/
if( iLimit ){
- int j; /* Loop counter */
+ int i; /* Loop counter */
int iKey; /* Hash key */
- for(j=1; j<=iLimit; j++){
- for(iKey=walHash(aPgno[j]); aHash[iKey]; iKey=walNextHash(iKey)){
- if( aHash[iKey]==j ) break;
+ for(i=1; i<=iLimit; i++){
+ for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
+ if( aHash[iKey]==i ) break;
}
- assert( aHash[iKey]==j );
+ assert( aHash[iKey]==i );
}
}
#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
@@ -54372,7 +49979,7 @@ static int walIndexRecover(Wal *pWal){
assert( pWal->writeLock );
iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
nLock = SQLITE_SHM_NLOCK - iLock;
- rc = walLockExclusive(pWal, iLock, nLock);
+ rc = walLockExclusive(pWal, iLock, nLock, 0);
if( rc ){
return rc;
}
@@ -54444,7 +50051,7 @@ static int walIndexRecover(Wal *pWal){
szFrame = szPage + WAL_FRAME_HDRSIZE;
aFrame = (u8 *)sqlite3_malloc64(szFrame);
if( !aFrame ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
goto recovery_error;
}
aData = &aFrame[WAL_FRAME_HDRSIZE];
@@ -54493,7 +50100,6 @@ finished:
*/
pInfo = walCkptInfo(pWal);
pInfo->nBackfill = 0;
- pInfo->nBackfillAttempted = pWal->hdr.mxFrame;
pInfo->aReadMark[0] = 0;
for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
if( pWal->hdr.mxFrame ) pInfo->aReadMark[1] = pWal->hdr.mxFrame;
@@ -54565,11 +50171,7 @@ SQLITE_PRIVATE int sqlite3WalOpen(
/* In the amalgamation, the os_unix.c and os_win.c source files come before
** this source file. Verify that the #defines of the locking byte offsets
** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value.
- ** For that matter, if the lock offset ever changes from its initial design
- ** value of 120, we need to know that so there is an assert() to check it.
*/
- assert( 120==WALINDEX_LOCK_OFFSET );
- assert( 136==WALINDEX_HDR_SIZE );
#ifdef WIN_SHM_BASE
assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET );
#endif
@@ -54582,7 +50184,7 @@ SQLITE_PRIVATE int sqlite3WalOpen(
*ppWal = 0;
pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile);
if( !pRet ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
pRet->pVfs = pVfs;
@@ -54760,7 +50362,7 @@ static void walMergesort(
int nMerge = 0; /* Number of elements in list aMerge */
ht_slot *aMerge = 0; /* List to be merged */
int iList; /* Index into input list */
- u32 iSub = 0; /* Index into aSub array */
+ int iSub = 0; /* Index into aSub array */
struct Sublist aSub[13]; /* Array of sub-lists */
memset(aSub, 0, sizeof(aSub));
@@ -54771,9 +50373,7 @@ static void walMergesort(
nMerge = 1;
aMerge = &aList[iList];
for(iSub=0; iList & (1<<iSub); iSub++){
- struct Sublist *p;
- assert( iSub<ArraySize(aSub) );
- p = &aSub[iSub];
+ struct Sublist *p = &aSub[iSub];
assert( p->aList && p->nList<=(1<<iSub) );
assert( p->aList==&aList[iList&~((2<<iSub)-1)] );
walMerge(aContent, p->aList, p->nList, &aMerge, &nMerge, aBuffer);
@@ -54784,9 +50384,7 @@ static void walMergesort(
for(iSub++; iSub<ArraySize(aSub); iSub++){
if( nList & (1<<iSub) ){
- struct Sublist *p;
- assert( iSub<ArraySize(aSub) );
- p = &aSub[iSub];
+ struct Sublist *p = &aSub[iSub];
assert( p->nList<=(1<<iSub) );
assert( p->aList==&aList[nList&~((2<<iSub)-1)] );
walMerge(aContent, p->aList, p->nList, &aMerge, &nMerge, aBuffer);
@@ -54846,7 +50444,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
+ iLast*sizeof(ht_slot);
p = (WalIterator *)sqlite3_malloc64(nByte);
if( !p ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
memset(p, 0, nByte);
p->nSegment = nSegment;
@@ -54858,7 +50456,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
);
if( !aTmp ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}
for(i=0; rc==SQLITE_OK && i<nSegment; i++){
@@ -54915,7 +50513,7 @@ static int walBusyLock(
){
int rc;
do {
- rc = walLockExclusive(pWal, lockIdx, n);
+ rc = walLockExclusive(pWal, lockIdx, n, 0);
}while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
return rc;
}
@@ -54955,7 +50553,6 @@ static void walRestartHdr(Wal *pWal, u32 salt1){
memcpy(&pWal->hdr.aSalt[1], &salt1, 4);
walIndexWriteHdr(pWal);
pInfo->nBackfill = 0;
- pInfo->nBackfillAttempted = 0;
pInfo->aReadMark[1] = 0;
for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
assert( pInfo->aReadMark[0]==0 );
@@ -55065,8 +50662,6 @@ static int walCheckpoint(
i64 nSize; /* Current size of database file */
u32 nBackfill = pInfo->nBackfill;
- pInfo->nBackfillAttempted = mxSafeFrame;
-
/* Sync the WAL to disk */
if( sync_flags ){
rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
@@ -55359,7 +50954,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
walUnlockShared(pWal, WAL_WRITE_LOCK);
rc = SQLITE_READONLY_RECOVERY;
}
- }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
+ }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1, 1)) ){
pWal->writeLock = 1;
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
badHdr = walIndexTryHdr(pWal, pChanged);
@@ -55450,7 +51045,6 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
int mxI; /* Index of largest aReadMark[] value */
int i; /* Loop counter */
int rc = SQLITE_OK; /* Return code */
- u32 mxFrame; /* Wal frame to lock to */
assert( pWal->readLock<0 ); /* Not currently locked */
@@ -55514,12 +51108,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
}
pInfo = walCkptInfo(pWal);
- if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame
-#ifdef SQLITE_ENABLE_SNAPSHOT
- && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0
- || 0==memcmp(&pWal->hdr, pWal->pSnapshot, sizeof(WalIndexHdr)))
-#endif
- ){
+ if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame ){
/* The WAL has been completely backfilled (or it is empty).
** and can be safely ignored.
*/
@@ -55557,88 +51146,70 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
*/
mxReadMark = 0;
mxI = 0;
- mxFrame = pWal->hdr.mxFrame;
-#ifdef SQLITE_ENABLE_SNAPSHOT
- if( pWal->pSnapshot && pWal->pSnapshot->mxFrame<mxFrame ){
- mxFrame = pWal->pSnapshot->mxFrame;
- }
-#endif
for(i=1; i<WAL_NREADER; i++){
u32 thisMark = pInfo->aReadMark[i];
- if( mxReadMark<=thisMark && thisMark<=mxFrame ){
+ if( mxReadMark<=thisMark && thisMark<=pWal->hdr.mxFrame ){
assert( thisMark!=READMARK_NOT_USED );
mxReadMark = thisMark;
mxI = i;
}
}
- if( (pWal->readOnly & WAL_SHM_RDONLY)==0
- && (mxReadMark<mxFrame || mxI==0)
- ){
- for(i=1; i<WAL_NREADER; i++){
- rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
- if( rc==SQLITE_OK ){
- mxReadMark = pInfo->aReadMark[i] = mxFrame;
- mxI = i;
- walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
- break;
- }else if( rc!=SQLITE_BUSY ){
- return rc;
+ /* There was once an "if" here. The extra "{" is to preserve indentation. */
+ {
+ if( (pWal->readOnly & WAL_SHM_RDONLY)==0
+ && (mxReadMark<pWal->hdr.mxFrame || mxI==0)
+ ){
+ for(i=1; i<WAL_NREADER; i++){
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1, 0);
+ if( rc==SQLITE_OK ){
+ mxReadMark = pInfo->aReadMark[i] = pWal->hdr.mxFrame;
+ mxI = i;
+ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ break;
+ }else if( rc!=SQLITE_BUSY ){
+ return rc;
+ }
}
}
- }
- if( mxI==0 ){
- assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 );
- return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTLOCK;
- }
+ if( mxI==0 ){
+ assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 );
+ return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTLOCK;
+ }
- rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
- if( rc ){
- return rc==SQLITE_BUSY ? WAL_RETRY : rc;
- }
- /* Now that the read-lock has been obtained, check that neither the
- ** value in the aReadMark[] array or the contents of the wal-index
- ** header have changed.
- **
- ** It is necessary to check that the wal-index header did not change
- ** between the time it was read and when the shared-lock was obtained
- ** on WAL_READ_LOCK(mxI) was obtained to account for the possibility
- ** that the log file may have been wrapped by a writer, or that frames
- ** that occur later in the log than pWal->hdr.mxFrame may have been
- ** copied into the database by a checkpointer. If either of these things
- ** happened, then reading the database with the current value of
- ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry
- ** instead.
- **
- ** Before checking that the live wal-index header has not changed
- ** since it was read, set Wal.minFrame to the first frame in the wal
- ** file that has not yet been checkpointed. This client will not need
- ** to read any frames earlier than minFrame from the wal file - they
- ** can be safely read directly from the database file.
- **
- ** Because a ShmBarrier() call is made between taking the copy of
- ** nBackfill and checking that the wal-header in shared-memory still
- ** matches the one cached in pWal->hdr, it is guaranteed that the
- ** checkpointer that set nBackfill was not working with a wal-index
- ** header newer than that cached in pWal->hdr. If it were, that could
- ** cause a problem. The checkpointer could omit to checkpoint
- ** a version of page X that lies before pWal->minFrame (call that version
- ** A) on the basis that there is a newer version (version B) of the same
- ** page later in the wal file. But if version B happens to like past
- ** frame pWal->hdr.mxFrame - then the client would incorrectly assume
- ** that it can read version A from the database file. However, since
- ** we can guarantee that the checkpointer that set nBackfill could not
- ** see any pages past pWal->hdr.mxFrame, this problem does not come up.
- */
- pWal->minFrame = pInfo->nBackfill+1;
- walShmBarrier(pWal);
- if( pInfo->aReadMark[mxI]!=mxReadMark
- || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
- ){
- walUnlockShared(pWal, WAL_READ_LOCK(mxI));
- return WAL_RETRY;
- }else{
- assert( mxReadMark<=pWal->hdr.mxFrame );
- pWal->readLock = (i16)mxI;
+ rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
+ if( rc ){
+ return rc==SQLITE_BUSY ? WAL_RETRY : rc;
+ }
+ /* Now that the read-lock has been obtained, check that neither the
+ ** value in the aReadMark[] array or the contents of the wal-index
+ ** header have changed.
+ **
+ ** It is necessary to check that the wal-index header did not change
+ ** between the time it was read and when the shared-lock was obtained
+ ** on WAL_READ_LOCK(mxI) was obtained to account for the possibility
+ ** that the log file may have been wrapped by a writer, or that frames
+ ** that occur later in the log than pWal->hdr.mxFrame may have been
+ ** copied into the database by a checkpointer. If either of these things
+ ** happened, then reading the database with the current value of
+ ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry
+ ** instead.
+ **
+ ** This does not guarantee that the copy of the wal-index header is up to
+ ** date before proceeding. That would not be possible without somehow
+ ** blocking writers. It only guarantees that a dangerous checkpoint or
+ ** log-wrap (either of which would require an exclusive lock on
+ ** WAL_READ_LOCK(mxI)) has not occurred since the snapshot was valid.
+ */
+ walShmBarrier(pWal);
+ if( pInfo->aReadMark[mxI]!=mxReadMark
+ || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
+ ){
+ walUnlockShared(pWal, WAL_READ_LOCK(mxI));
+ return WAL_RETRY;
+ }else{
+ assert( mxReadMark<=pWal->hdr.mxFrame );
+ pWal->readLock = (i16)mxI;
+ }
}
return rc;
}
@@ -55661,14 +51232,6 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
int rc; /* Return code */
int cnt = 0; /* Number of TryBeginRead attempts */
-#ifdef SQLITE_ENABLE_SNAPSHOT
- int bChanged = 0;
- WalIndexHdr *pSnapshot = pWal->pSnapshot;
- if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
- bChanged = 1;
- }
-#endif
-
do{
rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
}while( rc==WAL_RETRY );
@@ -55676,66 +51239,6 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
testcase( (rc&0xff)==SQLITE_IOERR );
testcase( rc==SQLITE_PROTOCOL );
testcase( rc==SQLITE_OK );
-
-#ifdef SQLITE_ENABLE_SNAPSHOT
- if( rc==SQLITE_OK ){
- if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
- /* At this point the client has a lock on an aReadMark[] slot holding
- ** a value equal to or smaller than pSnapshot->mxFrame, but pWal->hdr
- ** is populated with the wal-index header corresponding to the head
- ** of the wal file. Verify that pSnapshot is still valid before
- ** continuing. Reasons why pSnapshot might no longer be valid:
- **
- ** (1) The WAL file has been reset since the snapshot was taken.
- ** In this case, the salt will have changed.
- **
- ** (2) A checkpoint as been attempted that wrote frames past
- ** pSnapshot->mxFrame into the database file. Note that the
- ** checkpoint need not have completed for this to cause problems.
- */
- volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
-
- assert( pWal->readLock>0 || pWal->hdr.mxFrame==0 );
- assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame );
-
- /* It is possible that there is a checkpointer thread running
- ** concurrent with this code. If this is the case, it may be that the
- ** checkpointer has already determined that it will checkpoint
- ** snapshot X, where X is later in the wal file than pSnapshot, but
- ** has not yet set the pInfo->nBackfillAttempted variable to indicate
- ** its intent. To avoid the race condition this leads to, ensure that
- ** there is no checkpointer process by taking a shared CKPT lock
- ** before checking pInfo->nBackfillAttempted. */
- rc = walLockShared(pWal, WAL_CKPT_LOCK);
-
- if( rc==SQLITE_OK ){
- /* Check that the wal file has not been wrapped. Assuming that it has
- ** not, also check that no checkpointer has attempted to checkpoint any
- ** frames beyond pSnapshot->mxFrame. If either of these conditions are
- ** true, return SQLITE_BUSY_SNAPSHOT. Otherwise, overwrite pWal->hdr
- ** with *pSnapshot and set *pChanged as appropriate for opening the
- ** snapshot. */
- if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
- && pSnapshot->mxFrame>=pInfo->nBackfillAttempted
- ){
- assert( pWal->readLock>0 );
- memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr));
- *pChanged = bChanged;
- }else{
- rc = SQLITE_BUSY_SNAPSHOT;
- }
-
- /* Release the shared CKPT lock obtained above. */
- walUnlockShared(pWal, WAL_CKPT_LOCK);
- }
-
-
- if( rc!=SQLITE_OK ){
- sqlite3WalEndReadTransaction(pWal);
- }
- }
- }
-#endif
return rc;
}
@@ -55767,7 +51270,6 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
u32 iRead = 0; /* If !=0, WAL frame to return data from */
u32 iLast = pWal->hdr.mxFrame; /* Last page in WAL for this reader */
int iHash; /* Used to loop through N hash tables */
- int iMinHash;
/* This routine is only be called from within a read transaction. */
assert( pWal->readLock>=0 || pWal->lockError );
@@ -55808,8 +51310,7 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
** This condition filters out entries that were added to the hash
** table after the current read-transaction had started.
*/
- iMinHash = walFramePage(pWal->minFrame);
- for(iHash=walFramePage(iLast); iHash>=iMinHash && iRead==0; iHash--){
+ for(iHash=walFramePage(iLast); iHash>=0 && iRead==0; iHash--){
volatile ht_slot *aHash; /* Pointer to hash table */
volatile u32 *aPgno; /* Pointer to array of page numbers */
u32 iZero; /* Frame number corresponding to aPgno[0] */
@@ -55824,7 +51325,7 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
nCollide = HASHTABLE_NSLOT;
for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
u32 iFrame = aHash[iKey] + iZero;
- if( iFrame<=iLast && iFrame>=pWal->minFrame && aPgno[aHash[iKey]]==pgno ){
+ if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
assert( iFrame>iRead || CORRUPT_DB );
iRead = iFrame;
}
@@ -55841,8 +51342,7 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
{
u32 iRead2 = 0;
u32 iTest;
- assert( pWal->minFrame>0 );
- for(iTest=iLast; iTest>=pWal->minFrame; iTest--){
+ for(iTest=iLast; iTest>0; iTest--){
if( walFramePgno(pWal, iTest)==pgno ){
iRead2 = iTest;
break;
@@ -55908,7 +51408,6 @@ SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
/* Cannot start a write transaction without first holding a read
** transaction. */
assert( pWal->readLock>=0 );
- assert( pWal->writeLock==0 && pWal->iReCksum==0 );
if( pWal->readOnly ){
return SQLITE_READONLY;
@@ -55917,7 +51416,7 @@ SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
/* Only one writer allowed at a time. Get the write lock. Return
** SQLITE_BUSY if unable.
*/
- rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1, 0);
if( rc ){
return rc;
}
@@ -55944,7 +51443,6 @@ SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){
if( pWal->writeLock ){
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
pWal->writeLock = 0;
- pWal->iReCksum = 0;
pWal->truncateOnCommit = 0;
}
return SQLITE_OK;
@@ -56063,7 +51561,7 @@ static int walRestartLog(Wal *pWal){
if( pInfo->nBackfill>0 ){
u32 salt1;
sqlite3_randomness(4, &salt1);
- rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1, 0);
if( rc==SQLITE_OK ){
/* If all readers are using WAL_READ_LOCK(0) (in other words if no
** readers are currently using the WAL), then the transactions
@@ -56151,7 +51649,7 @@ static int walWriteOneFrame(
void *pData; /* Data actually written */
u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */
#if defined(SQLITE_HAS_CODEC)
- if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT;
+ if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM;
#else
pData = pPage->pData;
#endif
@@ -56163,59 +51661,6 @@ static int walWriteOneFrame(
return rc;
}
-/*
-** This function is called as part of committing a transaction within which
-** one or more frames have been overwritten. It updates the checksums for
-** all frames written to the wal file by the current transaction starting
-** with the earliest to have been overwritten.
-**
-** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
-*/
-static int walRewriteChecksums(Wal *pWal, u32 iLast){
- const int szPage = pWal->szPage;/* Database page size */
- int rc = SQLITE_OK; /* Return code */
- u8 *aBuf; /* Buffer to load data from wal file into */
- u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-headers in */
- u32 iRead; /* Next frame to read from wal file */
- i64 iCksumOff;
-
- aBuf = sqlite3_malloc(szPage + WAL_FRAME_HDRSIZE);
- if( aBuf==0 ) return SQLITE_NOMEM_BKPT;
-
- /* Find the checksum values to use as input for the recalculating the
- ** first checksum. If the first frame is frame 1 (implying that the current
- ** transaction restarted the wal file), these values must be read from the
- ** wal-file header. Otherwise, read them from the frame header of the
- ** previous frame. */
- assert( pWal->iReCksum>0 );
- if( pWal->iReCksum==1 ){
- iCksumOff = 24;
- }else{
- iCksumOff = walFrameOffset(pWal->iReCksum-1, szPage) + 16;
- }
- rc = sqlite3OsRead(pWal->pWalFd, aBuf, sizeof(u32)*2, iCksumOff);
- pWal->hdr.aFrameCksum[0] = sqlite3Get4byte(aBuf);
- pWal->hdr.aFrameCksum[1] = sqlite3Get4byte(&aBuf[sizeof(u32)]);
-
- iRead = pWal->iReCksum;
- pWal->iReCksum = 0;
- for(; rc==SQLITE_OK && iRead<=iLast; iRead++){
- i64 iOff = walFrameOffset(iRead, szPage);
- rc = sqlite3OsRead(pWal->pWalFd, aBuf, szPage+WAL_FRAME_HDRSIZE, iOff);
- if( rc==SQLITE_OK ){
- u32 iPgno, nDbSize;
- iPgno = sqlite3Get4byte(aBuf);
- nDbSize = sqlite3Get4byte(&aBuf[4]);
-
- walEncodeFrame(pWal, iPgno, nDbSize, &aBuf[WAL_FRAME_HDRSIZE], aFrame);
- rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOff);
- }
- }
-
- sqlite3_free(aBuf);
- return rc;
-}
-
/*
** Write a set of frames to the log. The caller must hold the write-lock
** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
@@ -56236,8 +51681,6 @@ SQLITE_PRIVATE int sqlite3WalFrames(
int szFrame; /* The size of a single frame */
i64 iOffset; /* Next byte to write in WAL file */
WalWriter w; /* The writer */
- u32 iFirst = 0; /* First frame that may be overwritten */
- WalIndexHdr *pLive; /* Pointer to shared header */
assert( pList );
assert( pWal->writeLock );
@@ -56253,11 +51696,6 @@ SQLITE_PRIVATE int sqlite3WalFrames(
}
#endif
- pLive = (WalIndexHdr*)walIndexHdr(pWal);
- if( memcmp(&pWal->hdr, (void *)pLive, sizeof(WalIndexHdr))!=0 ){
- iFirst = pLive->mxFrame+1;
- }
-
/* See if it is possible to write these frames into the start of the
** log file, instead of appending to it at pWal->hdr.mxFrame.
*/
@@ -56322,33 +51760,6 @@ SQLITE_PRIVATE int sqlite3WalFrames(
/* Write all frames into the log file exactly once */
for(p=pList; p; p=p->pDirty){
int nDbSize; /* 0 normally. Positive == commit flag */
-
- /* Check if this page has already been written into the wal file by
- ** the current transaction. If so, overwrite the existing frame and
- ** set Wal.writeLock to WAL_WRITELOCK_RECKSUM - indicating that
- ** checksums must be recomputed when the transaction is committed. */
- if( iFirst && (p->pDirty || isCommit==0) ){
- u32 iWrite = 0;
- VVA_ONLY(rc =) sqlite3WalFindFrame(pWal, p->pgno, &iWrite);
- assert( rc==SQLITE_OK || iWrite==0 );
- if( iWrite>=iFirst ){
- i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE;
- void *pData;
- if( pWal->iReCksum==0 || iWrite<pWal->iReCksum ){
- pWal->iReCksum = iWrite;
- }
-#if defined(SQLITE_HAS_CODEC)
- if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM;
-#else
- pData = p->pData;
-#endif
- rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff);
- if( rc ) return rc;
- p->flags &= ~PGHDR_WAL_APPEND;
- continue;
- }
- }
-
iFrame++;
assert( iOffset==walFrameOffset(iFrame, szPage) );
nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0;
@@ -56356,13 +51767,6 @@ SQLITE_PRIVATE int sqlite3WalFrames(
if( rc ) return rc;
pLast = p;
iOffset += szFrame;
- p->flags |= PGHDR_WAL_APPEND;
- }
-
- /* Recalculate checksums within the wal file if required. */
- if( isCommit && pWal->iReCksum ){
- rc = walRewriteChecksums(pWal, iFrame);
- if( rc ) return rc;
}
/* If this is the end of a transaction, then we might need to pad
@@ -56414,7 +51818,6 @@ SQLITE_PRIVATE int sqlite3WalFrames(
*/
iFrame = pWal->hdr.mxFrame;
for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){
- if( (p->flags & PGHDR_WAL_APPEND)==0 ) continue;
iFrame++;
rc = walIndexAppend(pWal, iFrame, p->pgno);
}
@@ -56483,7 +51886,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
/* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
** "checkpoint" lock on the database file. */
- rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
+ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1, 0);
if( rc ){
/* EVIDENCE-OF: R-10421-19736 If any other process is running a
** checkpoint operation at the same time, the lock cannot be obtained and
@@ -56527,7 +51930,6 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
/* Copy data from the log to the database file. */
if( rc==SQLITE_OK ){
-
if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
rc = SQLITE_CORRUPT_BKPT;
}else{
@@ -56643,52 +52045,6 @@ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
}
-#ifdef SQLITE_ENABLE_SNAPSHOT
-/* Create a snapshot object. The content of a snapshot is opaque to
-** every other subsystem, so the WAL module can put whatever it needs
-** in the object.
-*/
-SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot){
- int rc = SQLITE_OK;
- WalIndexHdr *pRet;
-
- assert( pWal->readLock>=0 && pWal->writeLock==0 );
-
- pRet = (WalIndexHdr*)sqlite3_malloc(sizeof(WalIndexHdr));
- if( pRet==0 ){
- rc = SQLITE_NOMEM_BKPT;
- }else{
- memcpy(pRet, &pWal->hdr, sizeof(WalIndexHdr));
- *ppSnapshot = (sqlite3_snapshot*)pRet;
- }
-
- return rc;
-}
-
-/* Try to open on pSnapshot when the next read-transaction starts
-*/
-SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){
- pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
-}
-
-/*
-** Return a +ve value if snapshot p1 is newer than p2. A -ve value if
-** p1 is older than p2 and zero if p1 and p2 are the same snapshot.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){
- WalIndexHdr *pHdr1 = (WalIndexHdr*)p1;
- WalIndexHdr *pHdr2 = (WalIndexHdr*)p2;
-
- /* aSalt[0] is a copy of the value stored in the wal file header. It
- ** is incremented each time the wal file is restarted. */
- if( pHdr1->aSalt[0]<pHdr2->aSalt[0] ) return -1;
- if( pHdr1->aSalt[0]>pHdr2->aSalt[0] ) return +1;
- if( pHdr1->mxFrame<pHdr2->mxFrame ) return -1;
- if( pHdr1->mxFrame>pHdr2->mxFrame ) return +1;
- return 0;
-}
-#endif /* SQLITE_ENABLE_SNAPSHOT */
-
#ifdef SQLITE_ENABLE_ZIPVFS
/*
** If the argument is not NULL, it points to a Wal object that holds a
@@ -56701,12 +52057,6 @@ SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){
}
#endif
-/* Return the sqlite3_file object for the WAL file
-*/
-SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){
- return pWal->pWalFd;
-}
-
#endif /* #ifndef SQLITE_OMIT_WAL */
/************** End of wal.c *************************************************/
@@ -56945,7 +52295,6 @@ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){
** 4 Number of leaf pointers on this page
** * zero or more pages numbers of leaves
*/
-/* #include "sqliteInt.h" */
/* The following value is the maximum cell size assuming a maximum page
@@ -56963,7 +52312,6 @@ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){
/* Forward declarations */
typedef struct MemPage MemPage;
typedef struct BtLock BtLock;
-typedef struct CellInfo CellInfo;
/*
** This is a magic string that appears at the beginning of every
@@ -57008,6 +52356,7 @@ struct MemPage {
u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
u8 intKey; /* True if table b-trees. False for index b-trees */
u8 intKeyLeaf; /* True if the leaf of an intKey table */
+ u8 noPayload; /* True if internal intKey page (thus w/o data) */
u8 leaf; /* True if a leaf page */
u8 hdrOffset; /* 100 for page 1. 0 otherwise */
u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
@@ -57026,10 +52375,7 @@ struct MemPage {
u8 *aData; /* Pointer to disk image of the page data */
u8 *aDataEnd; /* One byte past the end of usable data */
u8 *aCellIdx; /* The cell index area */
- u8 *aDataOfst; /* Same as aData for leaves. aData+4 for interior */
DbPage *pDbPage; /* Pager page handle */
- u16 (*xCellSize)(MemPage*,u8*); /* cellSizePtr method */
- void (*xParseCell)(MemPage*,u8*,CellInfo*); /* btreeParseCell method */
Pgno pgno; /* Page number for this page */
};
@@ -57085,7 +52431,6 @@ struct Btree {
u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
u8 sharable; /* True if we can share pBt with another db */
u8 locked; /* True if db currently has pBt locked */
- u8 hasIncrblobCur; /* True if there are one or more Incrblob cursors */
int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */
int nBackup; /* Number of backup operations reading this btree */
u32 iDataVersion; /* Combines with pBt->pPager->iDataVersion */
@@ -57196,11 +52541,13 @@ struct BtShared {
** about a cell. The parseCellPtr() function fills in this structure
** based on information extract from the raw disk page.
*/
+typedef struct CellInfo CellInfo;
struct CellInfo {
i64 nKey; /* The key for INTKEY tables, or nPayload otherwise */
u8 *pPayload; /* Pointer to the start of payload */
u32 nPayload; /* Bytes of payload */
u16 nLocal; /* Amount of payload held locally, not on overflow */
+ u16 iOverflow; /* Offset to overflow page number. Zero if no overflow */
u16 nSize; /* Size of the cell content on the main b-tree page */
};
@@ -57237,7 +52584,8 @@ struct CellInfo {
struct BtCursor {
Btree *pBtree; /* The Btree to which this cursor belongs */
BtShared *pBt; /* The BtShared this cursor points to */
- BtCursor *pNext; /* Forms a linked list of all cursors */
+ BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
+ struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
Pgno *aOverflow; /* Cache of overflow page locations */
CellInfo info; /* A parse of the cell we are pointing at */
i64 nKey; /* Size of pKey, or last integer key */
@@ -57247,16 +52595,9 @@ struct BtCursor {
int skipNext; /* Prev() is noop if negative. Next() is noop if positive.
** Error code if eState==CURSOR_FAULT */
u8 curFlags; /* zero or more BTCF_* flags defined below */
- u8 curPagerFlags; /* Flags to send to sqlite3PagerGet() */
u8 eState; /* One of the CURSOR_XXX constants (see below) */
- u8 hints; /* As configured by CursorSetHints() */
- /* All fields above are zeroed when the cursor is allocated. See
- ** sqlite3BtreeCursorZero(). Fields that follow must be manually
- ** initialized. */
- i8 iPage; /* Index of current page in apPage */
- u8 curIntKey; /* Value of apPage[0]->intKey */
- struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
- void *padding1; /* Make object size a multiple of 16 */
+ u8 hints; /* As configured by CursorSetHints() */
+ i16 iPage; /* Index of current page in apPage */
u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
};
@@ -57269,7 +52610,6 @@ struct BtCursor {
#define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */
#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */
#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */
-#define BTCF_Multiple 0x20 /* Maybe another cursor on the same btree */
/*
** Potential values for BtCursor.eState.
@@ -57412,7 +52752,6 @@ struct IntegrityCk {
const char *zPfx; /* Error message prefix */
int v1, v2; /* Values for up to two %d fields in zPfx */
StrAccum errMsg; /* Accumulate the error message text here */
- u32 *heap; /* Min-heap used for analyzing cell coverage */
};
/*
@@ -57423,23 +52762,6 @@ struct IntegrityCk {
#define get4byte sqlite3Get4byte
#define put4byte sqlite3Put4byte
-/*
-** get2byteAligned(), unlike get2byte(), requires that its argument point to a
-** two-byte aligned address. get2bytea() is only used for accessing the
-** cell addresses in a btree header.
-*/
-#if SQLITE_BYTEORDER==4321
-# define get2byteAligned(x) (*(u16*)(x))
-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
- && GCC_VERSION>=4008000
-# define get2byteAligned(x) __builtin_bswap16(*(u16*)(x))
-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
- && defined(_MSC_VER) && _MSC_VER>=1300
-# define get2byteAligned(x) _byteswap_ushort(*(u16*)(x))
-#else
-# define get2byteAligned(x) ((x)[0]<<8 | (x)[1])
-#endif
-
/************** End of btreeInt.h ********************************************/
/************** Continuing where we left off in btmutex.c ********************/
#ifndef SQLITE_OMIT_SHARED_CACHE
@@ -57595,6 +52917,21 @@ SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree *p){
#endif
+#ifndef SQLITE_OMIT_INCRBLOB
+/*
+** Enter and leave a mutex on a Btree given a cursor owned by that
+** Btree. These entry points are used by incremental I/O and can be
+** omitted if that module is not used.
+*/
+SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){
+ sqlite3BtreeEnter(pCur->pBtree);
+}
+SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){
+ sqlite3BtreeLeave(pCur->pBtree);
+}
+#endif /* SQLITE_OMIT_INCRBLOB */
+
+
/*
** Enter the mutex on every Btree associated with a database
** connection. This is needed (for example) prior to parsing
@@ -57628,6 +52965,14 @@ SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){
}
}
+/*
+** Return true if a particular Btree requires a lock. Return FALSE if
+** no lock is ever required since it is not sharable.
+*/
+SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){
+ return p->sharable;
+}
+
#ifndef NDEBUG
/*
** Return true if the current thread holds the database connection
@@ -57701,25 +53046,6 @@ SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){
}
}
#endif /* if SQLITE_THREADSAFE */
-
-#ifndef SQLITE_OMIT_INCRBLOB
-/*
-** Enter a mutex on a Btree given a cursor owned by that Btree.
-**
-** These entry points are used by incremental I/O only. Enter() is required
-** any time OMIT_SHARED_CACHE is not defined, regardless of whether or not
-** the build is threadsafe. Leave() is only required by threadsafe builds.
-*/
-SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){
- sqlite3BtreeEnter(pCur->pBtree);
-}
-# if SQLITE_THREADSAFE
-SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){
- sqlite3BtreeLeave(pCur->pBtree);
-}
-# endif
-#endif /* ifndef SQLITE_OMIT_INCRBLOB */
-
#endif /* ifndef SQLITE_OMIT_SHARED_CACHE */
/************** End of btmutex.c *********************************************/
@@ -57739,7 +53065,6 @@ SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor *pCur){
** See the header comment on "btreeInt.h" for additional information.
** Including a description of file format and an overview of operation.
*/
-/* #include "btreeInt.h" */
/*
** The header string that appears at the beginning of every
@@ -58076,7 +53401,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
if( !pLock ){
pLock = (BtLock *)sqlite3MallocZero(sizeof(BtLock));
if( !pLock ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
pLock->iTable = iTable;
pLock->pBtree = p;
@@ -58176,10 +53501,6 @@ static void releasePage(MemPage *pPage); /* Forward reference */
static int cursorHoldsMutex(BtCursor *p){
return sqlite3_mutex_held(p->pBt->mutex);
}
-static int cursorOwnsBtShared(BtCursor *p){
- assert( cursorHoldsMutex(p) );
- return (p->pBtree->db==p->pBt->db);
-}
#endif
/*
@@ -58220,15 +53541,13 @@ static void invalidateIncrblobCursors(
int isClearTable /* True if all rows are being deleted */
){
BtCursor *p;
- if( pBtree->hasIncrblobCur==0 ) return;
+ BtShared *pBt = pBtree->pBt;
assert( sqlite3BtreeHoldsMutex(pBtree) );
- pBtree->hasIncrblobCur = 0;
- for(p=pBtree->pBt->pCursor; p; p=p->pNext){
- if( (p->curFlags & BTCF_Incrblob)!=0 ){
- pBtree->hasIncrblobCur = 1;
- if( isClearTable || p->info.nKey==iRow ){
- p->eState = CURSOR_INVALID;
- }
+ for(p=pBt->pCursor; p; p=p->pNext){
+ if( (p->curFlags & BTCF_Incrblob)!=0
+ && (isClearTable || p->info.nKey==iRow)
+ ){
+ p->eState = CURSOR_INVALID;
}
}
}
@@ -58279,7 +53598,7 @@ static int btreeSetHasContent(BtShared *pBt, Pgno pgno){
assert( pgno<=pBt->nPage );
pBt->pHasContent = sqlite3BitvecCreate(pBt->nPage);
if( !pBt->pHasContent ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}
}
if( rc==SQLITE_OK && pgno<=sqlite3BitvecSize(pBt->pHasContent) ){
@@ -58321,25 +53640,26 @@ static void btreeReleaseAllCursorPages(BtCursor *pCur){
pCur->iPage = -1;
}
+
/*
-** The cursor passed as the only argument must point to a valid entry
-** when this function is called (i.e. have eState==CURSOR_VALID). This
-** function saves the current cursor key in variables pCur->nKey and
-** pCur->pKey. SQLITE_OK is returned if successful or an SQLite error
-** code otherwise.
+** Save the current cursor position in the variables BtCursor.nKey
+** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
**
-** If the cursor is open on an intkey table, then the integer key
-** (the rowid) is stored in pCur->nKey and pCur->pKey is left set to
-** NULL. If the cursor is open on a non-intkey table, then pCur->pKey is
-** set to point to a malloced buffer pCur->nKey bytes in size containing
-** the key.
+** The caller must ensure that the cursor is valid (has eState==CURSOR_VALID)
+** prior to calling this routine.
*/
-static int saveCursorKey(BtCursor *pCur){
+static int saveCursorPosition(BtCursor *pCur){
int rc;
- assert( CURSOR_VALID==pCur->eState );
+
+ assert( CURSOR_VALID==pCur->eState || CURSOR_SKIPNEXT==pCur->eState );
assert( 0==pCur->pKey );
assert( cursorHoldsMutex(pCur) );
+ if( pCur->eState==CURSOR_SKIPNEXT ){
+ pCur->eState = CURSOR_VALID;
+ }else{
+ pCur->skipNext = 0;
+ }
rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
assert( rc==SQLITE_OK ); /* KeySize() cannot fail */
@@ -58347,8 +53667,9 @@ static int saveCursorKey(BtCursor *pCur){
** stores the integer key in pCur->nKey. In this case this value is
** all that is required. Otherwise, if pCur is not open on an intKey
** table, then malloc space for and store the pCur->nKey bytes of key
- ** data. */
- if( 0==pCur->curIntKey ){
+ ** data.
+ */
+ if( 0==pCur->apPage[0]->intKey ){
void *pKey = sqlite3Malloc( pCur->nKey );
if( pKey ){
rc = sqlite3BtreeKey(pCur, 0, (int)pCur->nKey, pKey);
@@ -58358,40 +53679,17 @@ static int saveCursorKey(BtCursor *pCur){
sqlite3_free(pKey);
}
}else{
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}
}
- assert( !pCur->curIntKey || !pCur->pKey );
- return rc;
-}
+ assert( !pCur->apPage[0]->intKey || !pCur->pKey );
-/*
-** Save the current cursor position in the variables BtCursor.nKey
-** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
-**
-** The caller must ensure that the cursor is valid (has eState==CURSOR_VALID)
-** prior to calling this routine.
-*/
-static int saveCursorPosition(BtCursor *pCur){
- int rc;
-
- assert( CURSOR_VALID==pCur->eState || CURSOR_SKIPNEXT==pCur->eState );
- assert( 0==pCur->pKey );
- assert( cursorHoldsMutex(pCur) );
-
- if( pCur->eState==CURSOR_SKIPNEXT ){
- pCur->eState = CURSOR_VALID;
- }else{
- pCur->skipNext = 0;
- }
-
- rc = saveCursorKey(pCur);
if( rc==SQLITE_OK ){
btreeReleaseAllCursorPages(pCur);
pCur->eState = CURSOR_REQUIRESEEK;
}
- pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl|BTCF_AtLast);
+ invalidateOverflowCache(pCur);
return rc;
}
@@ -58406,15 +53704,6 @@ static int SQLITE_NOINLINE saveCursorsOnList(BtCursor*,Pgno,BtCursor*);
** routine is called just before cursor pExcept is used to modify the
** table, for example in BtreeDelete() or BtreeInsert().
**
-** If there are two or more cursors on the same btree, then all such
-** cursors should have their BTCF_Multiple flag set. The btreeCursor()
-** routine enforces that rule. This routine only needs to be called in
-** the uncommon case when pExpect has the BTCF_Multiple flag set.
-**
-** If pExpect!=NULL and if no other cursors are found on the same root-page,
-** then the BTCF_Multiple flag on pExpect is cleared, to avoid another
-** pointless call to this routine.
-**
** Implementation note: This routine merely checks to see if any cursors
** need to be saved. It calls out to saveCursorsOnList() in the (unusual)
** event that cursors are in need to being saved.
@@ -58426,9 +53715,7 @@ static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){
for(p=pBt->pCursor; p; p=p->pNext){
if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ) break;
}
- if( p ) return saveCursorsOnList(p, iRoot, pExcept);
- if( pExcept ) pExcept->curFlags &= ~BTCF_Multiple;
- return SQLITE_OK;
+ return p ? saveCursorsOnList(p, iRoot, pExcept) : SQLITE_OK;
}
/* This helper routine to saveAllCursors does the actual work of saving
@@ -58490,7 +53777,7 @@ static int btreeMoveto(
pIdxKey = sqlite3VdbeAllocUnpackedRecord(
pCur->pKeyInfo, aSpace, sizeof(aSpace), &pFree
);
- if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT;
+ if( pIdxKey==0 ) return SQLITE_NOMEM;
sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey);
if( pIdxKey->nField==0 ){
sqlite3DbFree(pCur->pKeyInfo->db, pFree);
@@ -58516,7 +53803,7 @@ static int btreeMoveto(
static int btreeRestoreCursorPosition(BtCursor *pCur){
int rc;
int skipNext;
- assert( cursorOwnsBtShared(pCur) );
+ assert( cursorHoldsMutex(pCur) );
assert( pCur->eState>=CURSOR_REQUIRESEEK );
if( pCur->eState==CURSOR_FAULT ){
return pCur->skipNext;
@@ -58588,26 +53875,6 @@ SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow)
return SQLITE_OK;
}
-#ifdef SQLITE_ENABLE_CURSOR_HINTS
-/*
-** Provide hints to the cursor. The particular hint given (and the type
-** and number of the varargs parameters) is determined by the eHintType
-** parameter. See the definitions of the BTREE_HINT_* macros for details.
-*/
-SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor *pCur, int eHintType, ...){
- /* Used only by system that substitute their own storage engine */
-}
-#endif
-
-/*
-** Provide flag hints to the cursor.
-*/
-SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor *pCur, unsigned x){
- assert( x==BTREE_SEEK_EQ || x==BTREE_BULKLOAD || x==0 );
- pCur->hints = x;
-}
-
-
#ifndef SQLITE_OMIT_AUTOVACUUM
/*
** Given a page number of a regular database page, return the page
@@ -58661,7 +53928,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
return;
}
iPtrmap = PTRMAP_PAGENO(pBt, key);
- rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage, 0);
+ rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage);
if( rc!=SQLITE_OK ){
*pRC = rc;
return;
@@ -58704,7 +53971,7 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
assert( sqlite3_mutex_held(pBt->mutex) );
iPtrmap = PTRMAP_PAGENO(pBt, key);
- rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage, 0);
+ rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage);
if( rc!=0 ){
return rc;
}
@@ -58736,85 +54003,39 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
** the page, 1 means the second cell, and so forth) return a pointer
** to the cell content.
**
-** findCellPastPtr() does the same except it skips past the initial
-** 4-byte child pointer found on interior pages, if there is one.
-**
** This routine works only for pages that do not contain overflow cells.
*/
#define findCell(P,I) \
- ((P)->aData + ((P)->maskPage & get2byteAligned(&(P)->aCellIdx[2*(I)])))
-#define findCellPastPtr(P,I) \
- ((P)->aDataOfst + ((P)->maskPage & get2byteAligned(&(P)->aCellIdx[2*(I)])))
+ ((P)->aData + ((P)->maskPage & get2byte(&(P)->aCellIdx[2*(I)])))
+#define findCellv2(D,M,O,I) (D+(M&get2byte(D+(O+2*(I)))))
/*
-** This is common tail processing for btreeParseCellPtr() and
-** btreeParseCellPtrIndex() for the case when the cell does not fit entirely
-** on a single B-tree page. Make necessary adjustments to the CellInfo
-** structure.
+** This a more complex version of findCell() that works for
+** pages that do contain overflow cells.
*/
-static SQLITE_NOINLINE void btreeParseCellAdjustSizeForOverflow(
- MemPage *pPage, /* Page containing the cell */
- u8 *pCell, /* Pointer to the cell text. */
- CellInfo *pInfo /* Fill in this structure */
-){
- /* 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
- ** overflow pages. The strategy is to minimize the amount of unused
- ** space on overflow pages while keeping the amount of local storage
- ** in between minLocal and maxLocal.
- **
- ** Warning: changing the way overflow payload is distributed in any
- ** way will result in an incompatible file format.
- */
- int minLocal; /* Minimum amount of payload held locally */
- int maxLocal; /* Maximum amount of payload held locally */
- int surplus; /* Overflow payload available for local storage */
-
- minLocal = pPage->minLocal;
- maxLocal = pPage->maxLocal;
- surplus = minLocal + (pInfo->nPayload - minLocal)%(pPage->pBt->usableSize-4);
- testcase( surplus==maxLocal );
- testcase( surplus==maxLocal+1 );
- if( surplus <= maxLocal ){
- pInfo->nLocal = (u16)surplus;
- }else{
- pInfo->nLocal = (u16)minLocal;
+static u8 *findOverflowCell(MemPage *pPage, int iCell){
+ int i;
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
+ for(i=pPage->nOverflow-1; i>=0; i--){
+ int k;
+ k = pPage->aiOvfl[i];
+ if( k<=iCell ){
+ if( k==iCell ){
+ return pPage->apOvfl[i];
+ }
+ iCell--;
+ }
}
- pInfo->nSize = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell) + 4;
+ return findCell(pPage, iCell);
}
/*
-** The following routines are implementations of the MemPage.xParseCell()
-** method.
-**
-** Parse a cell content block and fill in the CellInfo structure.
-**
-** btreeParseCellPtr() => table btree leaf nodes
-** btreeParseCellNoPayload() => table btree internal nodes
-** btreeParseCellPtrIndex() => index btree nodes
-**
-** There is also a wrapper function btreeParseCell() that works for
-** all MemPage types and that references the cell by index rather than
-** by pointer.
+** Parse a cell content block and fill in the CellInfo structure. There
+** are two versions of this function. btreeParseCell() takes a
+** cell index as the second argument and btreeParseCellPtr()
+** takes a pointer to the body of the cell as its second argument.
*/
-static void btreeParseCellPtrNoPayload(
- MemPage *pPage, /* Page containing the cell */
- u8 *pCell, /* Pointer to the cell text. */
- CellInfo *pInfo /* Fill in this structure */
-){
- assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- assert( pPage->leaf==0 );
- assert( pPage->childPtrSize==4 );
-#ifndef SQLITE_DEBUG
- UNUSED_PARAMETER(pPage);
-#endif
- pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey);
- pInfo->nPayload = 0;
- pInfo->nLocal = 0;
- pInfo->pPayload = 0;
- return;
-}
static void btreeParseCellPtr(
MemPage *pPage, /* Page containing the cell */
u8 *pCell, /* Pointer to the cell text. */
@@ -58822,89 +54043,26 @@ static void btreeParseCellPtr(
){
u8 *pIter; /* For scanning through pCell */
u32 nPayload; /* Number of bytes of cell payload */
- u64 iKey; /* Extracted Key value */
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( pPage->leaf==0 || pPage->leaf==1 );
- assert( pPage->intKeyLeaf );
- assert( pPage->childPtrSize==0 );
- pIter = pCell;
-
- /* The next block of code is equivalent to:
- **
- ** pIter += getVarint32(pIter, nPayload);
- **
- ** The code is inlined to avoid a function call.
- */
- nPayload = *pIter;
- if( nPayload>=0x80 ){
- u8 *pEnd = &pIter[8];
- nPayload &= 0x7f;
- do{
- nPayload = (nPayload<<7) | (*++pIter & 0x7f);
- }while( (*pIter)>=0x80 && pIter<pEnd );
- }
- pIter++;
-
- /* The next block of code is equivalent to:
- **
- ** pIter += getVarint(pIter, (u64*)&pInfo->nKey);
- **
- ** The code is inlined to avoid a function call.
- */
- iKey = *pIter;
- if( iKey>=0x80 ){
- u8 *pEnd = &pIter[7];
- iKey &= 0x7f;
- while(1){
- iKey = (iKey<<7) | (*++pIter & 0x7f);
- if( (*pIter)<0x80 ) break;
- if( pIter>=pEnd ){
- iKey = (iKey<<8) | *++pIter;
- break;
- }
- }
- }
- pIter++;
-
- pInfo->nKey = *(i64*)&iKey;
- pInfo->nPayload = nPayload;
- pInfo->pPayload = pIter;
- testcase( nPayload==pPage->maxLocal );
- testcase( nPayload==pPage->maxLocal+1 );
- if( nPayload<=pPage->maxLocal ){
- /* This is the (easy) common case where the entire payload fits
- ** on the local page. No overflow is required.
- */
- pInfo->nSize = nPayload + (u16)(pIter - pCell);
- if( pInfo->nSize<4 ) pInfo->nSize = 4;
- pInfo->nLocal = (u16)nPayload;
+ if( pPage->intKeyLeaf ){
+ assert( pPage->childPtrSize==0 );
+ pIter = pCell + getVarint32(pCell, nPayload);
+ pIter += getVarint(pIter, (u64*)&pInfo->nKey);
+ }else if( pPage->noPayload ){
+ assert( pPage->childPtrSize==4 );
+ pInfo->nSize = 4 + getVarint(&pCell[4], (u64*)&pInfo->nKey);
+ pInfo->nPayload = 0;
+ pInfo->nLocal = 0;
+ pInfo->iOverflow = 0;
+ pInfo->pPayload = 0;
+ return;
}else{
- btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo);
- }
-}
-static void btreeParseCellPtrIndex(
- MemPage *pPage, /* Page containing the cell */
- u8 *pCell, /* Pointer to the cell text. */
- CellInfo *pInfo /* Fill in this structure */
-){
- u8 *pIter; /* For scanning through pCell */
- u32 nPayload; /* Number of bytes of cell payload */
-
- assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- assert( pPage->leaf==0 || pPage->leaf==1 );
- assert( pPage->intKeyLeaf==0 );
- pIter = pCell + pPage->childPtrSize;
- nPayload = *pIter;
- if( nPayload>=0x80 ){
- u8 *pEnd = &pIter[8];
- nPayload &= 0x7f;
- do{
- nPayload = (nPayload<<7) | (*++pIter & 0x7f);
- }while( *(pIter)>=0x80 && pIter<pEnd );
+ pIter = pCell + pPage->childPtrSize;
+ pIter += getVarint32(pIter, nPayload);
+ pInfo->nKey = nPayload;
}
- pIter++;
- pInfo->nKey = nPayload;
pInfo->nPayload = nPayload;
pInfo->pPayload = pIter;
testcase( nPayload==pPage->maxLocal );
@@ -58916,8 +54074,33 @@ static void btreeParseCellPtrIndex(
pInfo->nSize = nPayload + (u16)(pIter - pCell);
if( pInfo->nSize<4 ) pInfo->nSize = 4;
pInfo->nLocal = (u16)nPayload;
+ pInfo->iOverflow = 0;
}else{
- btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo);
+ /* 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
+ ** overflow pages. The strategy is to minimize the amount of unused
+ ** space on overflow pages while keeping the amount of local storage
+ ** in between minLocal and maxLocal.
+ **
+ ** Warning: changing the way overflow payload is distributed in any
+ ** way will result in an incompatible file format.
+ */
+ int minLocal; /* Minimum amount of payload held locally */
+ int maxLocal; /* Maximum amount of payload held locally */
+ int surplus; /* Overflow payload available for local storage */
+
+ minLocal = pPage->minLocal;
+ maxLocal = pPage->maxLocal;
+ surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize - 4);
+ testcase( surplus==maxLocal );
+ testcase( surplus==maxLocal+1 );
+ if( surplus <= maxLocal ){
+ pInfo->nLocal = (u16)surplus;
+ }else{
+ pInfo->nLocal = (u16)minLocal;
+ }
+ pInfo->iOverflow = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell);
+ pInfo->nSize = pInfo->iOverflow + 4;
}
}
static void btreeParseCell(
@@ -58925,20 +54108,14 @@ static void btreeParseCell(
int iCell, /* The cell index. First cell is 0 */
CellInfo *pInfo /* Fill in this structure */
){
- pPage->xParseCell(pPage, findCell(pPage, iCell), pInfo);
+ btreeParseCellPtr(pPage, findCell(pPage, iCell), pInfo);
}
/*
-** The following routines are implementations of the MemPage.xCellSize
-** method.
-**
** Compute the total number of bytes that a Cell needs in the cell
** data area of the btree-page. The return number includes the cell
** data header and the local payload, but not any overflow page or
** the space used by the cell pointer.
-**
-** cellSizePtrNoPayload() => table internal nodes
-** cellSizePtr() => all index nodes & table leaf nodes
*/
static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
u8 *pIter = pCell + pPage->childPtrSize; /* For looping over bytes of pCell */
@@ -58951,12 +54128,18 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of
** this function verifies that this invariant is not violated. */
CellInfo debuginfo;
- pPage->xParseCell(pPage, pCell, &debuginfo);
+ btreeParseCellPtr(pPage, pCell, &debuginfo);
#endif
+ if( pPage->noPayload ){
+ pEnd = &pIter[9];
+ while( (*pIter++)&0x80 && pIter<pEnd );
+ assert( pPage->childPtrSize==4 );
+ return (u16)(pIter - pCell);
+ }
nSize = *pIter;
if( nSize>=0x80 ){
- pEnd = &pIter[8];
+ pEnd = &pIter[9];
nSize &= 0x7f;
do{
nSize = (nSize<<7) | (*++pIter & 0x7f);
@@ -58988,34 +54171,12 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
assert( nSize==debuginfo.nSize || CORRUPT_DB );
return (u16)nSize;
}
-static u16 cellSizePtrNoPayload(MemPage *pPage, u8 *pCell){
- u8 *pIter = pCell + 4; /* For looping over bytes of pCell */
- u8 *pEnd; /* End mark for a varint */
-
-#ifdef SQLITE_DEBUG
- /* The value returned by this function should always be the same as
- ** the (CellInfo.nSize) value found by doing a full parse of the
- ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of
- ** this function verifies that this invariant is not violated. */
- CellInfo debuginfo;
- pPage->xParseCell(pPage, pCell, &debuginfo);
-#else
- UNUSED_PARAMETER(pPage);
-#endif
-
- assert( pPage->childPtrSize==4 );
- pEnd = pIter + 9;
- while( (*pIter++)&0x80 && pIter<pEnd );
- assert( debuginfo.nSize==(u16)(pIter - pCell) || CORRUPT_DB );
- return (u16)(pIter - pCell);
-}
-
#ifdef SQLITE_DEBUG
/* This variation on cellSizePtr() is used inside of assert() statements
** only. */
static u16 cellSize(MemPage *pPage, int iCell){
- return pPage->xCellSize(pPage, findCell(pPage, iCell));
+ return cellSizePtr(pPage, findCell(pPage, iCell));
}
#endif
@@ -59029,9 +54190,9 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
CellInfo info;
if( *pRC ) return;
assert( pCell!=0 );
- pPage->xParseCell(pPage, pCell, &info);
- if( info.nLocal<info.nPayload ){
- Pgno ovfl = get4byte(&pCell[info.nSize-4]);
+ btreeParseCellPtr(pPage, pCell, &info);
+ if( info.iOverflow ){
+ Pgno ovfl = get4byte(&pCell[info.iOverflow]);
ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC);
}
}
@@ -59086,18 +54247,26 @@ static int defragmentPage(MemPage *pPage){
pc = get2byte(pAddr);
testcase( pc==iCellFirst );
testcase( pc==iCellLast );
+#if !defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK)
/* These conditions have already been verified in btreeInitPage()
- ** if PRAGMA cell_size_check=ON.
+ ** if SQLITE_ENABLE_OVERSIZE_CELL_CHECK is defined
*/
if( pc<iCellFirst || pc>iCellLast ){
return SQLITE_CORRUPT_BKPT;
}
+#endif
assert( pc>=iCellFirst && pc<=iCellLast );
- size = pPage->xCellSize(pPage, &src[pc]);
+ size = cellSizePtr(pPage, &src[pc]);
cbrk -= size;
+#if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK)
+ if( cbrk<iCellFirst ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+#else
if( cbrk<iCellFirst || pc+size>usableSize ){
return SQLITE_CORRUPT_BKPT;
}
+#endif
assert( cbrk+size<=usableSize && cbrk>=iCellFirst );
testcase( cbrk+size==usableSize );
testcase( pc+size==usableSize );
@@ -59135,20 +54304,18 @@ static int defragmentPage(MemPage *pPage){
** This function may detect corruption within pPg. If corruption is
** detected then *pRc is set to SQLITE_CORRUPT and NULL is returned.
**
-** Slots on the free list that are between 1 and 3 bytes larger than nByte
-** will be ignored if adding the extra space to the fragmentation count
-** causes the fragmentation count to exceed 60.
+** If a slot of at least nByte bytes is found but cannot be used because
+** there are already at least 60 fragmented bytes on the page, return NULL.
+** In this case, if pbDefrag parameter is not NULL, set *pbDefrag to true.
*/
-static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
+static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc, int *pbDefrag){
const int hdr = pPg->hdrOffset;
u8 * const aData = pPg->aData;
- int iAddr = hdr + 1;
- int pc = get2byte(&aData[iAddr]);
- int x;
+ int iAddr;
+ int pc;
int usableSize = pPg->pBt->usableSize;
- assert( pc>0 );
- do{
+ for(iAddr=hdr+1; (pc = get2byte(&aData[iAddr]))>0; iAddr=pc){
int size; /* Size of the free slot */
/* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of
** increasing offset. */
@@ -59160,21 +54327,24 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
** freeblock form a big-endian integer which is the size of the freeblock
** in bytes, including the 4-byte header. */
size = get2byte(&aData[pc+2]);
- if( (x = size - nByte)>=0 ){
+ if( size>=nByte ){
+ int x = size - nByte;
testcase( x==4 );
testcase( x==3 );
- if( pc < pPg->cellOffset+2*pPg->nCell || size+pc > usableSize ){
- *pRc = SQLITE_CORRUPT_BKPT;
- return 0;
- }else if( x<4 ){
+ if( x<4 ){
/* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total
** number of bytes in fragments may not exceed 60. */
- if( aData[hdr+7]>57 ) return 0;
-
+ if( aData[hdr+7]>=60 ){
+ if( pbDefrag ) *pbDefrag = 1;
+ return 0;
+ }
/* Remove the slot from the free-list. Update the number of
** fragmented bytes within the page. */
memcpy(&aData[iAddr], &aData[pc], 2);
aData[hdr+7] += (u8)x;
+ }else if( size+pc > usableSize ){
+ *pRc = SQLITE_CORRUPT_BKPT;
+ return 0;
}else{
/* The slot remains on the free-list. Reduce its size to account
** for the portion used by the new allocation. */
@@ -59182,9 +54352,7 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
}
return &aData[pc + x];
}
- iAddr = pc;
- pc = get2byte(&aData[pc]);
- }while( pc );
+ }
return 0;
}
@@ -59225,15 +54393,8 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
** then the cell content offset of an empty page wants to be 65536.
** However, that integer is too large to be stored in a 2-byte unsigned
** integer, so a value of 0 is used in its place. */
- top = get2byte(&data[hdr+5]);
- assert( top<=(int)pPage->pBt->usableSize ); /* Prevent by getAndInitPage() */
- if( gap>top ){
- if( top==0 && pPage->pBt->usableSize==65536 ){
- top = 65536;
- }else{
- return SQLITE_CORRUPT_BKPT;
- }
- }
+ top = get2byteNotZero(&data[hdr+5]);
+ if( gap>top ) return SQLITE_CORRUPT_BKPT;
/* If there is enough space between gap and top for one more cell pointer
** array entry offset, and if the freelist is not empty, then search the
@@ -59242,14 +54403,15 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
testcase( gap+2==top );
testcase( gap+1==top );
testcase( gap==top );
- if( (data[hdr+2] || data[hdr+1]) && gap+2<=top ){
- u8 *pSpace = pageFindSlot(pPage, nByte, &rc);
+ if( gap+2<=top && (data[hdr+1] || data[hdr+2]) ){
+ int bDefrag = 0;
+ u8 *pSpace = pageFindSlot(pPage, nByte, &rc, &bDefrag);
+ if( rc ) return rc;
+ if( bDefrag ) goto defragment_page;
if( pSpace ){
assert( pSpace>=data && (pSpace - data)<65536 );
*pIdx = (int)(pSpace - data);
return SQLITE_OK;
- }else if( rc ){
- return rc;
}
}
@@ -59258,6 +54420,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
*/
testcase( gap+2+nByte==top );
if( gap+2+nByte>top ){
+ defragment_page:
assert( pPage->nCell>0 || CORRUPT_DB );
rc = defragmentPage(pPage);
if( rc ) return rc;
@@ -59304,7 +54467,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
assert( pPage->pBt!=0 );
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
- assert( CORRUPT_DB || iStart>=pPage->hdrOffset+6+pPage->childPtrSize );
+ assert( iStart>=pPage->hdrOffset+6+pPage->childPtrSize );
assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( iSize>=4 ); /* Minimum cell size is 4 */
@@ -59333,7 +54496,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
/* At this point:
** iFreeBlk: First freeblock after iStart, or zero if none
- ** iPtr: The address of a pointer to iFreeBlk
+ ** iPtr: The address of a pointer iFreeBlk
**
** Check to see if iFreeBlk should be coalesced onto the end of iStart.
*/
@@ -59341,7 +54504,6 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
nFrag = iFreeBlk - iEnd;
if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_BKPT;
iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
- if( iEnd > pPage->pBt->usableSize ) return SQLITE_CORRUPT_BKPT;
iSize = iEnd - iStart;
iFreeBlk = get2byte(&data[iFreeBlk]);
}
@@ -59399,36 +54561,29 @@ static int decodeFlags(MemPage *pPage, int flagByte){
pPage->leaf = (u8)(flagByte>>3); assert( PTF_LEAF == 1<<3 );
flagByte &= ~PTF_LEAF;
pPage->childPtrSize = 4-4*pPage->leaf;
- pPage->xCellSize = cellSizePtr;
pBt = pPage->pBt;
if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
- /* EVIDENCE-OF: R-07291-35328 A value of 5 (0x05) means the page is an
- ** interior table b-tree page. */
+ /* EVIDENCE-OF: R-03640-13415 A value of 5 means the page is an interior
+ ** table b-tree page. */
assert( (PTF_LEAFDATA|PTF_INTKEY)==5 );
- /* EVIDENCE-OF: R-26900-09176 A value of 13 (0x0d) means the page is a
- ** leaf table b-tree page. */
+ /* EVIDENCE-OF: R-20501-61796 A value of 13 means the page is a leaf
+ ** table b-tree page. */
assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
pPage->intKey = 1;
- if( pPage->leaf ){
- pPage->intKeyLeaf = 1;
- pPage->xParseCell = btreeParseCellPtr;
- }else{
- pPage->intKeyLeaf = 0;
- pPage->xCellSize = cellSizePtrNoPayload;
- pPage->xParseCell = btreeParseCellPtrNoPayload;
- }
+ pPage->intKeyLeaf = pPage->leaf;
+ pPage->noPayload = !pPage->leaf;
pPage->maxLocal = pBt->maxLeaf;
pPage->minLocal = pBt->minLeaf;
}else if( flagByte==PTF_ZERODATA ){
- /* EVIDENCE-OF: R-43316-37308 A value of 2 (0x02) means the page is an
- ** interior index b-tree page. */
+ /* EVIDENCE-OF: R-27225-53936 A value of 2 means the page is an interior
+ ** index b-tree page. */
assert( (PTF_ZERODATA)==2 );
- /* EVIDENCE-OF: R-59615-42828 A value of 10 (0x0a) means the page is a
- ** leaf index b-tree page. */
+ /* EVIDENCE-OF: R-16571-11615 A value of 10 means the page is a leaf
+ ** index b-tree page. */
assert( (PTF_ZERODATA|PTF_LEAF)==10 );
pPage->intKey = 0;
pPage->intKeyLeaf = 0;
- pPage->xParseCell = btreeParseCellPtrIndex;
+ pPage->noPayload = 0;
pPage->maxLocal = pBt->maxLocal;
pPage->minLocal = pBt->minLocal;
}else{
@@ -59452,7 +54607,6 @@ static int decodeFlags(MemPage *pPage, int flagByte){
static int btreeInitPage(MemPage *pPage){
assert( pPage->pBt!=0 );
- assert( pPage->pBt->db!=0 );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) );
assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) );
@@ -59484,7 +54638,6 @@ static int btreeInitPage(MemPage *pPage){
pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize;
pPage->aDataEnd = &data[usableSize];
pPage->aCellIdx = &data[cellOffset];
- pPage->aDataOfst = &data[pPage->childPtrSize];
/* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates
** the start of the cell content area. A zero value for this integer is
** interpreted as 65536. */
@@ -59512,19 +54665,20 @@ static int btreeInitPage(MemPage *pPage){
*/
iCellFirst = cellOffset + 2*pPage->nCell;
iCellLast = usableSize - 4;
- if( pBt->db->flags & SQLITE_CellSizeCk ){
+#if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK)
+ {
int i; /* Index into the cell pointer array */
int sz; /* Size of a cell */
if( !pPage->leaf ) iCellLast--;
for(i=0; i<pPage->nCell; i++){
- pc = get2byteAligned(&data[cellOffset+i*2]);
+ pc = get2byte(&data[cellOffset+i*2]);
testcase( pc==iCellFirst );
testcase( pc==iCellLast );
if( pc<iCellFirst || pc>iCellLast ){
return SQLITE_CORRUPT_BKPT;
}
- sz = pPage->xCellSize(pPage, &data[pc]);
+ sz = cellSizePtr(pPage, &data[pc]);
testcase( pc+sz==usableSize );
if( pc+sz>usableSize ){
return SQLITE_CORRUPT_BKPT;
@@ -59532,6 +54686,7 @@ static int btreeInitPage(MemPage *pPage){
}
if( !pPage->leaf ) iCellLast++;
}
+#endif
/* Compute the total free space on the page
** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the
@@ -59604,7 +54759,6 @@ static void zeroPage(MemPage *pPage, int flags){
pPage->cellOffset = first;
pPage->aDataEnd = &data[pBt->usableSize];
pPage->aCellIdx = &data[first];
- pPage->aDataOfst = &data[pPage->childPtrSize];
pPage->nOverflow = 0;
assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
pPage->maskPage = (u16)(pBt->pageSize - 1);
@@ -59619,23 +54773,20 @@ static void zeroPage(MemPage *pPage, int flags){
*/
static MemPage *btreePageFromDbPage(DbPage *pDbPage, Pgno pgno, BtShared *pBt){
MemPage *pPage = (MemPage*)sqlite3PagerGetExtra(pDbPage);
- if( pgno!=pPage->pgno ){
- pPage->aData = sqlite3PagerGetData(pDbPage);
- pPage->pDbPage = pDbPage;
- pPage->pBt = pBt;
- pPage->pgno = pgno;
- pPage->hdrOffset = pgno==1 ? 100 : 0;
- }
- assert( pPage->aData==sqlite3PagerGetData(pDbPage) );
+ pPage->aData = sqlite3PagerGetData(pDbPage);
+ pPage->pDbPage = pDbPage;
+ pPage->pBt = pBt;
+ pPage->pgno = pgno;
+ pPage->hdrOffset = pPage->pgno==1 ? 100 : 0;
return pPage;
}
/*
** Get a page from the pager. Initialize the MemPage.pBt and
-** MemPage.aData elements if needed. See also: btreeGetUnusedPage().
+** MemPage.aData elements if needed.
**
-** If the PAGER_GET_NOCONTENT flag is set, it means that we do not care
-** about the content of the page at this time. So do not go to the disk
+** If the noContent flag is set, it means that we do not care about
+** the content of the page at this time. So do not go to the disk
** to fetch the content. Just fill in the content with zeros for now.
** If in the future we call sqlite3PagerWrite() on this page, that
** means we have started to be concerned about content and the disk
@@ -59652,7 +54803,7 @@ static int btreeGetPage(
assert( flags==0 || flags==PAGER_GET_NOCONTENT || flags==PAGER_GET_READONLY );
assert( sqlite3_mutex_held(pBt->mutex) );
- rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, flags);
+ rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, flags);
if( rc ) return rc;
*ppPage = btreePageFromDbPage(pDbPage, pgno, pBt);
return SQLITE_OK;
@@ -59687,63 +54838,35 @@ SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){
}
/*
-** Get a page from the pager and initialize it.
-**
-** If pCur!=0 then the page is being fetched as part of a moveToChild()
-** call. Do additional sanity checking on the page in this case.
-** And if the fetch fails, this routine must decrement pCur->iPage.
+** Get a page from the pager and initialize it. This routine is just a
+** convenience wrapper around separate calls to btreeGetPage() and
+** btreeInitPage().
**
-** The page is fetched as read-write unless pCur is not NULL and is
-** a read-only cursor.
-**
-** If an error occurs, then *ppPage is undefined. It
+** If an error occurs, then the value *ppPage is set to is undefined. It
** may remain unchanged, or it may be set to an invalid value.
*/
static int getAndInitPage(
BtShared *pBt, /* The database file */
Pgno pgno, /* Number of the page to get */
MemPage **ppPage, /* Write the page pointer here */
- BtCursor *pCur, /* Cursor to receive the page, or NULL */
- int bReadOnly /* True for a read-only page */
+ int bReadonly /* PAGER_GET_READONLY or 0 */
){
int rc;
- DbPage *pDbPage;
assert( sqlite3_mutex_held(pBt->mutex) );
- assert( pCur==0 || ppPage==&pCur->apPage[pCur->iPage] );
- assert( pCur==0 || bReadOnly==pCur->curPagerFlags );
- assert( pCur==0 || pCur->iPage>0 );
+ assert( bReadonly==PAGER_GET_READONLY || bReadonly==0 );
if( pgno>btreePagecount(pBt) ){
rc = SQLITE_CORRUPT_BKPT;
- goto getAndInitPage_error;
- }
- rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly);
- if( rc ){
- goto getAndInitPage_error;
- }
- *ppPage = (MemPage*)sqlite3PagerGetExtra(pDbPage);
- if( (*ppPage)->isInit==0 ){
- btreePageFromDbPage(pDbPage, pgno, pBt);
- rc = btreeInitPage(*ppPage);
- if( rc!=SQLITE_OK ){
- releasePage(*ppPage);
- goto getAndInitPage_error;
+ }else{
+ rc = btreeGetPage(pBt, pgno, ppPage, bReadonly);
+ if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){
+ rc = btreeInitPage(*ppPage);
+ if( rc!=SQLITE_OK ){
+ releasePage(*ppPage);
+ }
}
}
- assert( (*ppPage)->pgno==pgno );
- assert( (*ppPage)->aData==sqlite3PagerGetData(pDbPage) );
-
- /* If obtaining a child page for a cursor, we must verify that the page is
- ** compatible with the root page. */
- if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){
- rc = SQLITE_CORRUPT_BKPT;
- releasePage(*ppPage);
- goto getAndInitPage_error;
- }
- return SQLITE_OK;
-getAndInitPage_error:
- if( pCur ) pCur->iPage--;
testcase( pgno==0 );
assert( pgno!=0 || rc==SQLITE_CORRUPT );
return rc;
@@ -59753,49 +54876,18 @@ getAndInitPage_error:
** Release a MemPage. This should be called once for each prior
** call to btreeGetPage.
*/
-static void releasePageNotNull(MemPage *pPage){
- assert( pPage->aData );
- assert( pPage->pBt );
- assert( pPage->pDbPage!=0 );
- assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage );
- assert( sqlite3PagerGetData(pPage->pDbPage)==pPage->aData );
- assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- sqlite3PagerUnrefNotNull(pPage->pDbPage);
-}
static void releasePage(MemPage *pPage){
- if( pPage ) releasePageNotNull(pPage);
-}
-
-/*
-** Get an unused page.
-**
-** This works just like btreeGetPage() with the addition:
-**
-** * If the page is already in use for some other purpose, immediately
-** release it and return an SQLITE_CURRUPT error.
-** * Make sure the isInit flag is clear
-*/
-static int btreeGetUnusedPage(
- BtShared *pBt, /* The btree */
- Pgno pgno, /* Number of the page to fetch */
- MemPage **ppPage, /* Return the page in this parameter */
- int flags /* PAGER_GET_NOCONTENT or PAGER_GET_READONLY */
-){
- int rc = btreeGetPage(pBt, pgno, ppPage, flags);
- if( rc==SQLITE_OK ){
- if( sqlite3PagerPageRefcount((*ppPage)->pDbPage)>1 ){
- releasePage(*ppPage);
- *ppPage = 0;
- return SQLITE_CORRUPT_BKPT;
- }
- (*ppPage)->isInit = 0;
- }else{
- *ppPage = 0;
+ if( pPage ){
+ assert( pPage->aData );
+ assert( pPage->pBt );
+ assert( pPage->pDbPage!=0 );
+ assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage );
+ assert( sqlite3PagerGetData(pPage->pDbPage)==pPage->aData );
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
+ sqlite3PagerUnrefNotNull(pPage->pDbPage);
}
- return rc;
}
-
/*
** During a rollback, when the pager reloads information into the cache
** so that the cache is restored to its original state at the start of
@@ -59902,7 +54994,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
}
p = sqlite3MallocZero(sizeof(Btree));
if( !p ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
p->inTrans = TRANS_NONE;
p->db = db;
@@ -59926,7 +55018,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
p->sharable = 1;
if( !zFullPathname ){
sqlite3_free(p);
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
if( isMemdb ){
memcpy(zFullPathname, zFilename, nFilename);
@@ -59994,7 +55086,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
pBt = sqlite3MallocZero( sizeof(*pBt) );
if( pBt==0 ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
goto btree_open_out;
}
rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename,
@@ -60063,7 +55155,8 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){
pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST);
if( pBt->mutex==0 ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
+ db->mallocFailed = 0;
goto btree_open_out;
}
}
@@ -60086,12 +55179,12 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
for(i=0; i<db->nDb; i++){
if( (pSib = db->aDb[i].pBt)!=0 && pSib->sharable ){
while( pSib->pPrev ){ pSib = pSib->pPrev; }
- if( (uptr)p->pBt<(uptr)pSib->pBt ){
+ if( p->pBt<pSib->pBt ){
p->pNext = pSib;
p->pPrev = 0;
pSib->pPrev = p;
}else{
- while( pSib->pNext && (uptr)pSib->pNext->pBt<(uptr)p->pBt ){
+ while( pSib->pNext && pSib->pNext->pBt<p->pBt ){
pSib = pSib->pNext;
}
p->pNext = pSib->pNext;
@@ -60273,11 +55366,19 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
}
/*
-** Change the "soft" limit on the number of pages in the cache.
-** Unused and unmodified pages will be recycled when the number of
-** pages in the cache exceeds this soft limit. But the size of the
-** cache is allowed to grow larger than this limit if it contains
-** dirty pages or pages still in active use.
+** Change the limit on the number of pages allowed in the cache.
+**
+** The maximum number of cache pages is set to the absolute
+** value of mxPage. If mxPage is negative, the pager will
+** operate asynchronously - it will not stop to do fsync()s
+** to insure data is written to the disk surface before
+** continuing. Transactions still work if synchronous is off,
+** and the database cannot be corrupted if this program
+** crashes. But if the operating system crashes or there is
+** an abrupt power failure when synchronous is off, the database
+** could be left in an inconsistent and unrecoverable state.
+** Synchronous is on by default so database corruption is not
+** normally a worry.
*/
SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
BtShared *pBt = p->pBt;
@@ -60288,26 +55389,6 @@ SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
return SQLITE_OK;
}
-/*
-** Change the "spill" limit on the number of pages in the cache.
-** If the number of pages exceeds this limit during a write transaction,
-** the pager might attempt to "spill" pages to the journal early in
-** order to free up memory.
-**
-** The value returned is the current spill size. If zero is passed
-** as an argument, no changes are made to the spill size setting, so
-** using mxPage of 0 is a way to query the current spill size.
-*/
-SQLITE_PRIVATE int sqlite3BtreeSetSpillSize(Btree *p, int mxPage){
- BtShared *pBt = p->pBt;
- int res;
- assert( sqlite3_mutex_held(p->db->mutex) );
- sqlite3BtreeEnter(p);
- res = sqlite3PagerSetSpillsize(pBt->pPager, mxPage);
- sqlite3BtreeLeave(p);
- return res;
-}
-
#if SQLITE_MAX_MMAP_SIZE>0
/*
** Change the limit on the amount of the database file that may be
@@ -60346,6 +55427,21 @@ SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(
#endif
/*
+** Return TRUE if the given btree is set to safety level 1. In other
+** words, return TRUE if no sync() occurs on the disk files.
+*/
+SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree *p){
+ BtShared *pBt = p->pBt;
+ int rc;
+ assert( sqlite3_mutex_held(p->db->mutex) );
+ sqlite3BtreeEnter(p);
+ assert( pBt && pBt->pPager );
+ rc = sqlite3PagerNosync(pBt->pPager);
+ sqlite3BtreeLeave(p);
+ return rc;
+}
+
+/*
** Change the default pages size and the number of reserved bytes per page.
** Or, if the page size has already been fixed, return SQLITE_READONLY
** without changing anything.
@@ -60590,25 +55686,9 @@ static int lockBtree(BtShared *pBt){
rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen);
if( rc!=SQLITE_OK ){
goto page1_init_failed;
- }else{
-#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS
- sqlite3 *db;
- Db *pDb;
- if( (db=pBt->db)!=0 && (pDb=db->aDb)!=0 ){
- while( pDb->pBt==0 || pDb->pBt->pBt!=pBt ){ pDb++; }
- if( pDb->bSyncSet==0
- && pDb->safety_level==SQLITE_DEFAULT_SYNCHRONOUS+1
- ){
- pDb->safety_level = SQLITE_DEFAULT_WAL_SYNCHRONOUS+1;
- sqlite3PagerSetFlags(pBt->pPager,
- pDb->safety_level | (db->flags & PAGER_FLAGS_MASK));
- }
- }
-#endif
- if( isOpen==0 ){
- releasePage(pPage1);
- return SQLITE_OK;
- }
+ }else if( isOpen==0 ){
+ releasePage(pPage1);
+ return SQLITE_OK;
}
rc = SQLITE_NOTADB;
}
@@ -60750,7 +55830,7 @@ static void unlockBtreeIfUnused(BtShared *pBt){
assert( pPage1->aData );
assert( sqlite3PagerRefcount(pBt->pPager)==1 );
pBt->pPage1 = 0;
- releasePageNotNull(pPage1);
+ releasePage(pPage1);
}
}
@@ -60848,6 +55928,7 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){
** proceed.
*/
SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
+ sqlite3 *pBlock = 0;
BtShared *pBt = p->pBt;
int rc = SQLITE_OK;
@@ -60870,30 +55951,27 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
}
#ifndef SQLITE_OMIT_SHARED_CACHE
- {
- sqlite3 *pBlock = 0;
- /* If another database handle has already opened a write transaction
- ** on this shared-btree structure and a second write transaction is
- ** requested, return SQLITE_LOCKED.
- */
- if( (wrflag && pBt->inTransaction==TRANS_WRITE)
- || (pBt->btsFlags & BTS_PENDING)!=0
- ){
- pBlock = pBt->pWriter->db;
- }else if( wrflag>1 ){
- BtLock *pIter;
- for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
- if( pIter->pBtree!=p ){
- pBlock = pIter->pBtree->db;
- break;
- }
+ /* If another database handle has already opened a write transaction
+ ** on this shared-btree structure and a second write transaction is
+ ** requested, return SQLITE_LOCKED.
+ */
+ if( (wrflag && pBt->inTransaction==TRANS_WRITE)
+ || (pBt->btsFlags & BTS_PENDING)!=0
+ ){
+ pBlock = pBt->pWriter->db;
+ }else if( wrflag>1 ){
+ BtLock *pIter;
+ for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
+ if( pIter->pBtree!=p ){
+ pBlock = pIter->pBtree->db;
+ break;
}
}
- if( pBlock ){
- sqlite3ConnectionBlocked(p->db, pBlock);
- rc = SQLITE_LOCKED_SHAREDCACHE;
- goto trans_begun;
- }
+ }
+ if( pBlock ){
+ sqlite3ConnectionBlocked(p->db, pBlock);
+ rc = SQLITE_LOCKED_SHAREDCACHE;
+ goto trans_begun;
}
#endif
@@ -61057,22 +56135,20 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
u8 isInitOrig = pPage->isInit;
int i;
int nCell;
- int rc;
- rc = btreeInitPage(pPage);
- if( rc ) return rc;
+ btreeInitPage(pPage);
nCell = pPage->nCell;
for(i=0; i<nCell; i++){
u8 *pCell = findCell(pPage, i);
if( eType==PTRMAP_OVERFLOW1 ){
CellInfo info;
- pPage->xParseCell(pPage, pCell, &info);
- if( info.nLocal<info.nPayload
- && pCell+info.nSize-1<=pPage->aData+pPage->maskPage
- && iFrom==get4byte(pCell+info.nSize-4)
+ btreeParseCellPtr(pPage, pCell, &info);
+ if( info.iOverflow
+ && pCell+info.iOverflow+3<=pPage->aData+pPage->maskPage
+ && iFrom==get4byte(&pCell[info.iOverflow])
){
- put4byte(pCell+info.nSize-4, iTo);
+ put4byte(&pCell[info.iOverflow], iTo);
break;
}
}else{
@@ -61366,7 +56442,7 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){
static int autoVacuumCommit(BtShared *pBt){
int rc = SQLITE_OK;
Pager *pPager = pBt->pPager;
- VVA_ONLY( int nRef = sqlite3PagerRefcount(pPager); )
+ VVA_ONLY( int nRef = sqlite3PagerRefcount(pPager) );
assert( sqlite3_mutex_held(pBt->mutex) );
invalidateAllOverflowCache(pBt);
@@ -61775,13 +56851,13 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
** on the database already. If a write-cursor is requested, then
** the caller is assumed to have an open write transaction.
**
-** If the BTREE_WRCSR bit of wrFlag is clear, then the cursor can only
-** be used for reading. If the BTREE_WRCSR bit is set, then the cursor
-** can be used for reading or for writing if other conditions for writing
-** are also met. These are the conditions that must be met in order
-** for writing to be allowed:
+** If wrFlag==0, then the cursor can only be used for reading.
+** If wrFlag==1, then the cursor can be used for reading or for
+** writing if other conditions for writing are also met. These
+** are the conditions that must be met in order for writing to
+** be allowed:
**
-** 1: The cursor must have been opened with wrFlag containing BTREE_WRCSR
+** 1: The cursor must have been opened with wrFlag==1
**
** 2: Other database connections that share the same pager cache
** but which are not in the READ_UNCOMMITTED state may not have
@@ -61793,16 +56869,6 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
**
** 4: There must be an active transaction.
**
-** The BTREE_FORDELETE bit of wrFlag may optionally be set if BTREE_WRCSR
-** is set. If FORDELETE is set, that is a hint to the implementation that
-** this cursor will only be used to seek to and delete entries of an index
-** as part of a larger DELETE statement. The FORDELETE hint is not used by
-** this implementation. But in a hypothetical alternative storage engine
-** in which index entries are automatically deleted when corresponding table
-** rows are deleted, the FORDELETE flag is a hint that all SEEK and DELETE
-** operations on this cursor can be no-ops and all READ operations can
-** return a null row (2-bytes: 0x01 0x00).
-**
** No checking is done to make sure that page iTable really is the
** root page of a b-tree. If it is not, then the cursor acquired
** will not work correctly.
@@ -61818,30 +56884,28 @@ static int btreeCursor(
BtCursor *pCur /* Space for new cursor */
){
BtShared *pBt = p->pBt; /* Shared b-tree handle */
- BtCursor *pX; /* Looping over other all cursors */
assert( sqlite3BtreeHoldsMutex(p) );
- assert( wrFlag==0
- || wrFlag==BTREE_WRCSR
- || wrFlag==(BTREE_WRCSR|BTREE_FORDELETE)
- );
+ assert( wrFlag==0 || wrFlag==1 );
/* The following assert statements verify that if this is a sharable
** b-tree database, the connection is holding the required table locks,
** and that no other connection has any open cursor that conflicts with
** this lock. */
- assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, (wrFlag?2:1)) );
+ assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, wrFlag+1) );
assert( wrFlag==0 || !hasReadConflicts(p, iTable) );
/* Assert that the caller has opened the required transaction. */
assert( p->inTrans>TRANS_NONE );
assert( wrFlag==0 || p->inTrans==TRANS_WRITE );
assert( pBt->pPage1 && pBt->pPage1->aData );
- assert( wrFlag==0 || (pBt->btsFlags & BTS_READ_ONLY)==0 );
+ if( NEVER(wrFlag && (pBt->btsFlags & BTS_READ_ONLY)!=0) ){
+ return SQLITE_READONLY;
+ }
if( wrFlag ){
allocateTempSpace(pBt);
- if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM_BKPT;
+ if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM;
}
if( iTable==1 && btreePagecount(pBt)==0 ){
assert( wrFlag==0 );
@@ -61855,17 +56919,12 @@ static int btreeCursor(
pCur->pKeyInfo = pKeyInfo;
pCur->pBtree = p;
pCur->pBt = pBt;
- pCur->curFlags = wrFlag ? BTCF_WriteFlag : 0;
- pCur->curPagerFlags = wrFlag ? 0 : PAGER_GET_READONLY;
- /* If there are two or more cursors on the same btree, then all such
- ** cursors *must* have the BTCF_Multiple flag set. */
- for(pX=pBt->pCursor; pX; pX=pX->pNext){
- if( pX->pgnoRoot==(Pgno)iTable ){
- pX->curFlags |= BTCF_Multiple;
- pCur->curFlags |= BTCF_Multiple;
- }
- }
+ assert( wrFlag==0 || wrFlag==BTCF_WriteFlag );
+ pCur->curFlags = wrFlag;
pCur->pNext = pBt->pCursor;
+ if( pCur->pNext ){
+ pCur->pNext->pPrev = pCur;
+ }
pBt->pCursor = pCur;
pCur->eState = CURSOR_INVALID;
return SQLITE_OK;
@@ -61878,13 +56937,9 @@ SQLITE_PRIVATE int sqlite3BtreeCursor(
BtCursor *pCur /* Write new cursor here */
){
int rc;
- if( iTable<1 ){
- rc = SQLITE_CORRUPT_BKPT;
- }else{
- sqlite3BtreeEnter(p);
- rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur);
- sqlite3BtreeLeave(p);
- }
+ sqlite3BtreeEnter(p);
+ rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur);
+ sqlite3BtreeLeave(p);
return rc;
}
@@ -61923,18 +56978,13 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
BtShared *pBt = pCur->pBt;
sqlite3BtreeEnter(pBtree);
sqlite3BtreeClearCursor(pCur);
- assert( pBt->pCursor!=0 );
- if( pBt->pCursor==pCur ){
- pBt->pCursor = pCur->pNext;
+ if( pCur->pPrev ){
+ pCur->pPrev->pNext = pCur->pNext;
}else{
- BtCursor *pPrev = pBt->pCursor;
- do{
- if( pPrev->pNext==pCur ){
- pPrev->pNext = pCur->pNext;
- break;
- }
- pPrev = pPrev->pNext;
- }while( ALWAYS(pPrev) );
+ pBt->pCursor = pCur->pNext;
+ }
+ if( pCur->pNext ){
+ pCur->pNext->pPrev = pCur->pPrev;
}
for(i=0; i<=pCur->iPage; i++){
releasePage(pCur->apPage[i]);
@@ -61954,6 +57004,13 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
**
** BtCursor.info is a cache of the information in the current cell.
** Using this cache reduces the number of calls to btreeParseCell().
+**
+** 2007-06-25: There is a bug in some versions of MSVC that cause the
+** compiler to crash when getCellInfo() is implemented as a macro.
+** But there is a measureable speed advantage to using the macro on gcc
+** (when less compiler optimizations like -Os or -O0 are used and the
+** compiler is not doing aggressive inlining.) So we use a real function
+** for MSVC and a macro for everything else. Ticket #2457.
*/
#ifndef NDEBUG
static void assertCellInfo(BtCursor *pCur){
@@ -61966,15 +57023,28 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
#else
#define assertCellInfo(x)
#endif
-static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){
- if( pCur->info.nSize==0 ){
- int iPage = pCur->iPage;
- pCur->curFlags |= BTCF_ValidNKey;
- btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
- }else{
- assertCellInfo(pCur);
+#ifdef _MSC_VER
+ /* Use a real function in MSVC to work around bugs in that compiler. */
+ static void getCellInfo(BtCursor *pCur){
+ if( pCur->info.nSize==0 ){
+ int iPage = pCur->iPage;
+ btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
+ pCur->curFlags |= BTCF_ValidNKey;
+ }else{
+ assertCellInfo(pCur);
+ }
}
-}
+#else /* if not _MSC_VER */
+ /* Use a macro in all other compilers so that the function is inlined */
+#define getCellInfo(pCur) \
+ if( pCur->info.nSize==0 ){ \
+ int iPage = pCur->iPage; \
+ btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \
+ pCur->curFlags |= BTCF_ValidNKey; \
+ }else{ \
+ assertCellInfo(pCur); \
+ }
+#endif /* _MSC_VER */
#ifndef NDEBUG /* The next routine used only within assert() statements */
/*
@@ -62020,7 +57090,7 @@ SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
** to return an integer result code for historical reasons.
*/
SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
- assert( cursorOwnsBtShared(pCur) );
+ assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage>=0 );
assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
@@ -62198,13 +57268,8 @@ static int accessPayload(
#endif
assert( offset+amt <= pCur->info.nPayload );
- assert( aPayload > pPage->aData );
- if( (uptr)(aPayload - pPage->aData) > (pBt->usableSize - pCur->info.nLocal) ){
- /* Trying to read or write past the end of the data is an error. The
- ** conditional above is really:
- ** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
- ** but is recast into its current form to avoid integer overflow problems
- */
+ if( &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] ){
+ /* Trying to read or write past the end of the data is an error */
return SQLITE_CORRUPT_BKPT;
}
@@ -62244,7 +57309,7 @@ static int accessPayload(
pCur->aOverflow, nOvfl*2*sizeof(Pgno)
);
if( aNew==0 ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}else{
pCur->nOvflAlloc = nOvfl*2;
pCur->aOverflow = aNew;
@@ -62272,9 +57337,7 @@ static int accessPayload(
/* If required, populate the overflow page-list cache. */
if( (pCur->curFlags & BTCF_ValidOvfl)!=0 ){
- assert( pCur->aOverflow[iIdx]==0
- || pCur->aOverflow[iIdx]==nextPage
- || CORRUPT_DB );
+ assert(!pCur->aOverflow[iIdx] || pCur->aOverflow[iIdx]==nextPage);
pCur->aOverflow[iIdx] = nextPage;
}
@@ -62344,7 +57407,7 @@ static int accessPayload(
{
DbPage *pDbPage;
- rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage,
+ rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage,
((eOp&0x01)==0 ? PAGER_GET_READONLY : 0)
);
if( rc==SQLITE_OK ){
@@ -62405,7 +57468,7 @@ SQLITE_PRIVATE int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *p
}
#endif
- assert( cursorOwnsBtShared(pCur) );
+ assert( cursorHoldsMutex(pCur) );
rc = restoreCursorPosition(pCur);
if( rc==SQLITE_OK ){
assert( pCur->eState==CURSOR_VALID );
@@ -62443,7 +57506,7 @@ static const void *fetchPayload(
assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
assert( pCur->eState==CURSOR_VALID );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
- assert( cursorOwnsBtShared(pCur) );
+ assert( cursorHoldsMutex(pCur) );
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
assert( pCur->info.nSize>0 );
assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB );
@@ -62487,21 +57550,31 @@ SQLITE_PRIVATE const void *sqlite3BtreeDataFetch(BtCursor *pCur, u32 *pAmt){
** vice-versa).
*/
static int moveToChild(BtCursor *pCur, u32 newPgno){
+ int rc;
+ int i = pCur->iPage;
+ MemPage *pNewPage;
BtShared *pBt = pCur->pBt;
- assert( cursorOwnsBtShared(pCur) );
+ assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
assert( pCur->iPage>=0 );
if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
return SQLITE_CORRUPT_BKPT;
}
+ rc = getAndInitPage(pBt, newPgno, &pNewPage,
+ (pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
+ if( rc ) return rc;
+ pCur->apPage[i+1] = pNewPage;
+ pCur->aiIdx[i+1] = 0;
+ pCur->iPage++;
+
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
- pCur->iPage++;
- pCur->aiIdx[pCur->iPage] = 0;
- return getAndInitPage(pBt, newPgno, &pCur->apPage[pCur->iPage],
- pCur, pCur->curPagerFlags);
+ if( pNewPage->nCell<1 || pNewPage->intKey!=pCur->apPage[i]->intKey ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+ return SQLITE_OK;
}
#if SQLITE_DEBUG
@@ -62535,7 +57608,7 @@ static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){
** the largest cell index.
*/
static void moveToParent(BtCursor *pCur){
- assert( cursorOwnsBtShared(pCur) );
+ assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage>0 );
assert( pCur->apPage[pCur->iPage] );
@@ -62545,9 +57618,11 @@ static void moveToParent(BtCursor *pCur){
pCur->apPage[pCur->iPage]->pgno
);
testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
+
+ releasePage(pCur->apPage[pCur->iPage]);
+ pCur->iPage--;
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
- releasePageNotNull(pCur->apPage[pCur->iPage--]);
}
/*
@@ -62575,7 +57650,7 @@ static int moveToRoot(BtCursor *pCur){
MemPage *pRoot;
int rc = SQLITE_OK;
- assert( cursorOwnsBtShared(pCur) );
+ assert( cursorHoldsMutex(pCur) );
assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
assert( CURSOR_VALID < CURSOR_REQUIRESEEK );
assert( CURSOR_FAULT > CURSOR_REQUIRESEEK );
@@ -62588,23 +57663,18 @@ static int moveToRoot(BtCursor *pCur){
}
if( pCur->iPage>=0 ){
- while( pCur->iPage ){
- assert( pCur->apPage[pCur->iPage]!=0 );
- releasePageNotNull(pCur->apPage[pCur->iPage--]);
- }
+ while( pCur->iPage ) releasePage(pCur->apPage[pCur->iPage--]);
}else if( pCur->pgnoRoot==0 ){
pCur->eState = CURSOR_INVALID;
return SQLITE_OK;
}else{
- assert( pCur->iPage==(-1) );
rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
- 0, pCur->curPagerFlags);
+ (pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
return rc;
}
pCur->iPage = 0;
- pCur->curIntKey = pCur->apPage[0]->intKey;
}
pRoot = pCur->apPage[0];
assert( pRoot->pgno==pCur->pgnoRoot );
@@ -62654,7 +57724,7 @@ static int moveToLeftmost(BtCursor *pCur){
int rc = SQLITE_OK;
MemPage *pPage;
- assert( cursorOwnsBtShared(pCur) );
+ assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){
assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
@@ -62679,7 +57749,7 @@ static int moveToRightmost(BtCursor *pCur){
int rc = SQLITE_OK;
MemPage *pPage = 0;
- assert( cursorOwnsBtShared(pCur) );
+ assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
@@ -62700,7 +57770,7 @@ static int moveToRightmost(BtCursor *pCur){
SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
int rc;
- assert( cursorOwnsBtShared(pCur) );
+ assert( cursorHoldsMutex(pCur) );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
rc = moveToRoot(pCur);
if( rc==SQLITE_OK ){
@@ -62723,7 +57793,7 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
int rc;
- assert( cursorOwnsBtShared(pCur) );
+ assert( cursorHoldsMutex(pCur) );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
/* If the cursor already points to the last entry, this is a no-op. */
@@ -62788,8 +57858,6 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
** *pRes>0 The cursor is left pointing at an entry that
** is larger than intKey/pIdxKey.
**
-** For index tables, the pIdxKey->eqSeen field is set to 1 if there
-** exists an entry in the table that exactly matches pIdxKey.
*/
SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
BtCursor *pCur, /* The cursor to be moved */
@@ -62801,7 +57869,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
int rc;
RecordCompare xRecordCompare;
- assert( cursorOwnsBtShared(pCur) );
+ assert( cursorHoldsMutex(pCur) );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
assert( pRes );
assert( (pIdxKey==0)==(pCur->pKeyInfo==0) );
@@ -62809,7 +57877,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
/* If the cursor is already positioned at the point we are trying
** to move to, then just return without doing any work */
if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0
- && pCur->curIntKey
+ && pCur->apPage[0]->intKey
){
if( pCur->info.nKey==intKey ){
*pRes = 0;
@@ -62844,8 +57912,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
return SQLITE_OK;
}
- assert( pCur->apPage[0]->intKey==pCur->curIntKey );
- assert( pCur->curIntKey || pIdxKey );
+ assert( pCur->apPage[0]->intKey || pIdxKey );
for(;;){
int lwr, upr, idx, c;
Pgno chldPg;
@@ -62868,7 +57935,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
if( xRecordCompare==0 ){
for(;;){
i64 nCellKey;
- pCell = findCellPastPtr(pPage, idx);
+ pCell = findCell(pPage, idx) + pPage->childPtrSize;
if( pPage->intKeyLeaf ){
while( 0x80 <= *(pCell++) ){
if( pCell>=pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT;
@@ -62900,8 +57967,8 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
}
}else{
for(;;){
- int nCell; /* Size of the pCell cell in bytes */
- pCell = findCellPastPtr(pPage, idx);
+ int nCell;
+ pCell = findCell(pPage, idx) + pPage->childPtrSize;
/* The maximum supported page-size is 65536 bytes. This means that
** the maximum number of record bytes stored on an index B-Tree
@@ -62929,27 +57996,14 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
/* The record flows over onto one or more overflow pages. In
** this case the whole cell needs to be parsed, a buffer allocated
** and accessPayload() used to retrieve the record into the
- ** buffer before VdbeRecordCompare() can be called.
- **
- ** If the record is corrupt, the xRecordCompare routine may read
- ** up to two varints past the end of the buffer. An extra 18
- ** bytes of padding is allocated at the end of the buffer in
- ** case this happens. */
+ ** buffer before VdbeRecordCompare() can be called. */
void *pCellKey;
u8 * const pCellBody = pCell - pPage->childPtrSize;
- pPage->xParseCell(pPage, pCellBody, &pCur->info);
+ btreeParseCellPtr(pPage, pCellBody, &pCur->info);
nCell = (int)pCur->info.nKey;
- testcase( nCell<0 ); /* True if key size is 2^32 or more */
- testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */
- testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */
- testcase( nCell==2 ); /* Minimum legal index key size */
- if( nCell<2 ){
- rc = SQLITE_CORRUPT_BKPT;
- goto moveto_finish;
- }
- pCellKey = sqlite3Malloc( nCell+18 );
+ pCellKey = sqlite3Malloc( nCell );
if( pCellKey==0 ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
goto moveto_finish;
}
pCur->aiIdx[pCur->iPage] = (u16)idx;
@@ -63049,7 +58103,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
int idx;
MemPage *pPage;
- assert( cursorOwnsBtShared(pCur) );
+ assert( cursorHoldsMutex(pCur) );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
assert( *pRes==0 );
if( pCur->eState!=CURSOR_VALID ){
@@ -63113,7 +58167,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
}
SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
MemPage *pPage;
- assert( cursorOwnsBtShared(pCur) );
+ assert( cursorHoldsMutex(pCur) );
assert( pRes!=0 );
assert( *pRes==0 || *pRes==1 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
@@ -63158,7 +58212,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
int rc;
MemPage *pPage;
- assert( cursorOwnsBtShared(pCur) );
+ assert( cursorHoldsMutex(pCur) );
assert( pRes!=0 );
assert( *pRes==0 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
@@ -63214,7 +58268,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
return rc;
}
SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
- assert( cursorOwnsBtShared(pCur) );
+ assert( cursorHoldsMutex(pCur) );
assert( pRes!=0 );
assert( *pRes==0 || *pRes==1 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
@@ -63240,7 +58294,8 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
** sqlite3PagerUnref() on the new page when it is done.
**
** SQLITE_OK is returned on success. Any other return value indicates
-** an error. *ppPage is set to NULL in the event of an error.
+** an error. *ppPage and *pPgno are undefined in the event of an error.
+** Do not invoke sqlite3PagerUnref() on *ppPage if an error is returned.
**
** If the "nearby" parameter is not 0, then an effort is made to
** locate a page close to the page number "nearby". This can be used in an
@@ -63283,7 +58338,6 @@ static int allocateBtreePage(
/* There are pages on the freelist. Reuse one of those pages. */
Pgno iTrunk;
u8 searchList = 0; /* If the free-list must be searched for 'nearby' */
- u32 nSearch = 0; /* Count of the number of search attempts */
/* If eMode==BTALLOC_EXACT and a query of the pointer-map
** shows that the page 'nearby' is somewhere on the free-list, then
@@ -63332,10 +58386,10 @@ static int allocateBtreePage(
iTrunk = get4byte(&pPage1->aData[32]);
}
testcase( iTrunk==mxPage );
- if( iTrunk>mxPage || nSearch++ > n ){
+ if( iTrunk>mxPage ){
rc = SQLITE_CORRUPT_BKPT;
}else{
- rc = btreeGetUnusedPage(pBt, iTrunk, &pTrunk, 0);
+ rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0);
}
if( rc ){
pTrunk = 0;
@@ -63400,7 +58454,7 @@ static int allocateBtreePage(
goto end_allocate_page;
}
testcase( iNewTrunk==mxPage );
- rc = btreeGetUnusedPage(pBt, iNewTrunk, &pNewTrunk, 0);
+ rc = btreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0);
if( rc!=SQLITE_OK ){
goto end_allocate_page;
}
@@ -63480,12 +58534,11 @@ static int allocateBtreePage(
}
put4byte(&aData[4], k-1);
noContent = !btreeGetHasContent(pBt, *pPgno)? PAGER_GET_NOCONTENT : 0;
- rc = btreeGetUnusedPage(pBt, *pPgno, ppPage, noContent);
+ rc = btreeGetPage(pBt, *pPgno, ppPage, noContent);
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){
releasePage(*ppPage);
- *ppPage = 0;
}
}
searchList = 0;
@@ -63529,7 +58582,7 @@ static int allocateBtreePage(
MemPage *pPg = 0;
TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
- rc = btreeGetUnusedPage(pBt, pBt->nPage, &pPg, bNoContent);
+ rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent);
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pPg->pDbPage);
releasePage(pPg);
@@ -63543,12 +58596,11 @@ static int allocateBtreePage(
*pPgno = pBt->nPage;
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
- rc = btreeGetUnusedPage(pBt, *pPgno, ppPage, bNoContent);
+ rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent);
if( rc ) return rc;
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){
releasePage(*ppPage);
- *ppPage = 0;
}
TRACE(("ALLOCATE: %d from end of file\n", *pPgno));
}
@@ -63558,8 +58610,17 @@ static int allocateBtreePage(
end_allocate_page:
releasePage(pTrunk);
releasePage(pPrevTrunk);
- assert( rc!=SQLITE_OK || sqlite3PagerPageRefcount((*ppPage)->pDbPage)<=1 );
- assert( rc!=SQLITE_OK || (*ppPage)->isInit==0 );
+ if( rc==SQLITE_OK ){
+ if( sqlite3PagerPageRefcount((*ppPage)->pDbPage)>1 ){
+ releasePage(*ppPage);
+ *ppPage = 0;
+ return SQLITE_CORRUPT_BKPT;
+ }
+ (*ppPage)->isInit = 0;
+ }else{
+ *ppPage = 0;
+ }
+ assert( rc!=SQLITE_OK || sqlite3PagerIswriteable((*ppPage)->pDbPage) );
return rc;
}
@@ -63584,10 +58645,9 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
int nFree; /* Initial number of pages on free-list */
assert( sqlite3_mutex_held(pBt->mutex) );
- assert( CORRUPT_DB || iPage>1 );
+ assert( iPage>1 );
assert( !pMemPage || pMemPage->pgno==iPage );
- if( iPage<2 ) return SQLITE_CORRUPT_BKPT;
if( pMemPage ){
pPage = pMemPage;
sqlite3PagerRef(pPage->pDbPage);
@@ -63727,21 +58787,19 @@ static int clearCell(
u32 ovflPageSize;
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- pPage->xParseCell(pPage, pCell, &info);
+ btreeParseCellPtr(pPage, pCell, &info);
*pnSize = info.nSize;
- if( info.nLocal==info.nPayload ){
+ if( info.iOverflow==0 ){
return SQLITE_OK; /* No overflow pages. Return without doing anything */
}
- if( pCell+info.nSize-1 > pPage->aData+pPage->maskPage ){
+ if( pCell+info.iOverflow+3 > pPage->aData+pPage->maskPage ){
return SQLITE_CORRUPT_BKPT; /* Cell extends past end of page */
}
- ovflPgno = get4byte(pCell + info.nSize - 4);
+ ovflPgno = get4byte(&pCell[info.iOverflow]);
assert( pBt->usableSize > 4 );
ovflPageSize = pBt->usableSize - 4;
nOvfl = (info.nPayload - info.nLocal + ovflPageSize - 1)/ovflPageSize;
- assert( nOvfl>0 ||
- (CORRUPT_DB && (info.nPayload + ovflPageSize)<ovflPageSize)
- );
+ assert( ovflPgno==0 || nOvfl>0 );
while( nOvfl-- ){
Pgno iNext = 0;
MemPage *pOvfl = 0;
@@ -63839,7 +58897,9 @@ static int fillInCell(
nSrc = nData;
nData = 0;
}else{
- assert( nKey<=0x7fffffff && pKey!=0 );
+ if( NEVER(nKey>0x7fffffff || pKey==0) ){
+ return SQLITE_CORRUPT_BKPT;
+ }
nPayload = (int)nKey;
pSrc = pKey;
nSrc = (int)nKey;
@@ -63879,11 +58939,12 @@ static int fillInCell(
#if SQLITE_DEBUG
{
CellInfo info;
- pPage->xParseCell(pPage, pCell, &info);
- assert( nHeader==(int)(info.pPayload - pCell) );
+ btreeParseCellPtr(pPage, pCell, &info);
+ assert( nHeader=(int)(info.pPayload - pCell) );
assert( info.nKey==nKey );
assert( *pnSize == info.nSize );
assert( spaceLeft == info.nLocal );
+ assert( pPrior == &pCell[info.iOverflow] );
}
#endif
@@ -63993,7 +59054,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
if( *pRC ) return;
assert( idx>=0 && idx<pPage->nCell );
- assert( CORRUPT_DB || sz==cellSize(pPage, idx) );
+ assert( sz==cellSize(pPage, idx) );
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
data = pPage->aData;
@@ -64048,8 +59109,10 @@ static void insertCell(
){
int idx = 0; /* Where to write new cell content in data[] */
int j; /* Loop counter */
+ int end; /* First byte past the last cell pointer in data[] */
+ int ins; /* Index in data[] where new cell pointer is inserted */
+ int cellOffset; /* Address of first cell pointer in data[] */
u8 *data; /* The content of the whole page */
- u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */
if( *pRC ) return;
@@ -64064,7 +59127,7 @@ static void insertCell(
** wanted to be less than 4 but got rounded up to 4 on the leaf, then size
** might be less than 8 (leaf-size + pointer) on the interior node. Hence
** the term after the || in the following assert(). */
- assert( sz==pPage->xCellSize(pPage, pCell) || (sz==8 && iChild>0) );
+ assert( sz==cellSizePtr(pPage, pCell) || (sz==8 && iChild>0) );
if( pPage->nOverflow || sz+2>pPage->nFree ){
if( pTemp ){
memcpy(pTemp, pCell, sz);
@@ -64077,14 +59140,6 @@ static void insertCell(
assert( j<(int)(sizeof(pPage->apOvfl)/sizeof(pPage->apOvfl[0])) );
pPage->apOvfl[j] = pCell;
pPage->aiOvfl[j] = (u16)i;
-
- /* When multiple overflows occur, they are always sequential and in
- ** sorted order. This invariants arise because multiple overflows can
- ** only occur when inserting divider cells into the parent page during
- ** balancing, and the dividers are adjacent and sorted.
- */
- assert( j==0 || pPage->aiOvfl[j-1]<(u16)i ); /* Overflows in sorted order */
- assert( j==0 || i==pPage->aiOvfl[j-1]+1 ); /* Overflows are sequential */
}else{
int rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc!=SQLITE_OK ){
@@ -64093,26 +59148,24 @@ static void insertCell(
}
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
data = pPage->aData;
- assert( &data[pPage->cellOffset]==pPage->aCellIdx );
+ cellOffset = pPage->cellOffset;
+ end = cellOffset + 2*pPage->nCell;
+ ins = cellOffset + 2*i;
rc = allocateSpace(pPage, sz, &idx);
if( rc ){ *pRC = rc; return; }
- /* The allocateSpace() routine guarantees the following properties
- ** if it returns successfully */
- assert( idx >= 0 );
- assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB );
+ /* The allocateSpace() routine guarantees the following two properties
+ ** if it returns success */
+ assert( idx >= end+2 );
assert( idx+sz <= (int)pPage->pBt->usableSize );
+ pPage->nCell++;
pPage->nFree -= (u16)(2 + sz);
memcpy(&data[idx], pCell, sz);
if( iChild ){
put4byte(&data[idx], iChild);
}
- pIns = pPage->aCellIdx + i*2;
- memmove(pIns+2, pIns, 2*(pPage->nCell - i));
- put2byte(pIns, idx);
- pPage->nCell++;
- /* increment the cell count */
- if( (++data[pPage->hdrOffset+4])==0 ) data[pPage->hdrOffset+3]++;
- assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell );
+ memmove(&data[ins+2], &data[ins], end-ins);
+ put2byte(&data[ins], idx);
+ put2byte(&data[pPage->hdrOffset+3], pPage->nCell);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pPage->pBt->autoVacuum ){
/* The cell may contain a pointer to an overflow page. If so, write
@@ -64125,52 +59178,6 @@ static void insertCell(
}
/*
-** A CellArray object contains a cache of pointers and sizes for a
-** consecutive sequence of cells that might be held multiple pages.
-*/
-typedef struct CellArray CellArray;
-struct CellArray {
- int nCell; /* Number of cells in apCell[] */
- MemPage *pRef; /* Reference page */
- u8 **apCell; /* All cells begin balanced */
- u16 *szCell; /* Local size of all cells in apCell[] */
-};
-
-/*
-** Make sure the cell sizes at idx, idx+1, ..., idx+N-1 have been
-** computed.
-*/
-static void populateCellCache(CellArray *p, int idx, int N){
- assert( idx>=0 && idx+N<=p->nCell );
- while( N>0 ){
- assert( p->apCell[idx]!=0 );
- if( p->szCell[idx]==0 ){
- p->szCell[idx] = p->pRef->xCellSize(p->pRef, p->apCell[idx]);
- }else{
- assert( CORRUPT_DB ||
- p->szCell[idx]==p->pRef->xCellSize(p->pRef, p->apCell[idx]) );
- }
- idx++;
- N--;
- }
-}
-
-/*
-** Return the size of the Nth element of the cell array
-*/
-static SQLITE_NOINLINE u16 computeCellSize(CellArray *p, int N){
- assert( N>=0 && N<p->nCell );
- assert( p->szCell[N]==0 );
- p->szCell[N] = p->pRef->xCellSize(p->pRef, p->apCell[N]);
- return p->szCell[N];
-}
-static u16 cachedCellSize(CellArray *p, int N){
- assert( N>=0 && N<p->nCell );
- if( p->szCell[N] ) return p->szCell[N];
- return computeCellSize(p, N);
-}
-
-/*
** Array apCell[] contains pointers to nCell b-tree page cells. The
** szCell[] array contains the size in bytes of each cell. This function
** replaces the current contents of page pPg with the contents of the cell
@@ -64183,7 +59190,7 @@ static u16 cachedCellSize(CellArray *p, int N){
** The MemPage.nFree field is invalidated by this function. It is the
** responsibility of the caller to set it correctly.
*/
-static int rebuildPage(
+static void rebuildPage(
MemPage *pPg, /* Edit this page */
int nCell, /* Final number of cells on page */
u8 **apCell, /* Array of cells */
@@ -64204,16 +59211,14 @@ static int rebuildPage(
pData = pEnd;
for(i=0; i<nCell; i++){
u8 *pCell = apCell[i];
- if( SQLITE_WITHIN(pCell,aData,pEnd) ){
+ if( pCell>aData && pCell<pEnd ){
pCell = &pTmp[pCell - aData];
}
pData -= szCell[i];
+ memcpy(pData, pCell, szCell[i]);
put2byte(pCellptr, (pData - aData));
pCellptr += 2;
- if( pData < pCellptr ) return SQLITE_CORRUPT_BKPT;
- memcpy(pData, pCell, szCell[i]);
- assert( szCell[i]==pPg->xCellSize(pPg, pCell) || CORRUPT_DB );
- testcase( szCell[i]!=pPg->xCellSize(pPg,pCell) );
+ assert( szCell[i]==cellSizePtr(pPg, pCell) );
}
/* The pPg->nFree field is now set incorrectly. The caller will fix it. */
@@ -64224,7 +59229,6 @@ static int rebuildPage(
put2byte(&aData[hdr+3], pPg->nCell);
put2byte(&aData[hdr+5], pData - aData);
aData[hdr+7] = 0x00;
- return SQLITE_OK;
}
/*
@@ -64257,31 +59261,25 @@ static int pageInsertArray(
u8 *pBegin, /* End of cell-pointer array */
u8 **ppData, /* IN/OUT: Page content -area pointer */
u8 *pCellptr, /* Pointer to cell-pointer area */
- int iFirst, /* Index of first cell to add */
int nCell, /* Number of cells to add to pPg */
- CellArray *pCArray /* Array of cells */
+ u8 **apCell, /* Array of cells */
+ u16 *szCell /* Array of cell sizes */
){
int i;
u8 *aData = pPg->aData;
u8 *pData = *ppData;
- int iEnd = iFirst + nCell;
+ const int bFreelist = aData[1] || aData[2];
assert( CORRUPT_DB || pPg->hdrOffset==0 ); /* Never called on page 1 */
- for(i=iFirst; i<iEnd; i++){
- int sz, rc;
+ for(i=0; i<nCell; i++){
+ int sz = szCell[i];
+ int rc;
u8 *pSlot;
- sz = cachedCellSize(pCArray, i);
- if( (aData[1]==0 && aData[2]==0) || (pSlot = pageFindSlot(pPg,sz,&rc))==0 ){
- if( (pData - pBegin)<sz ) return 1;
+ if( bFreelist==0 || (pSlot = pageFindSlot(pPg, sz, &rc, 0))==0 ){
pData -= sz;
+ if( pData<pBegin ) return 1;
pSlot = pData;
}
- /* pSlot and pCArray->apCell[i] will never overlap on a well-formed
- ** database. But they might for a corrupt database. Hence use memmove()
- ** since memcpy() sends SIGABORT with overlapping buffers on OpenBSD */
- assert( (pSlot+sz)<=pCArray->apCell[i]
- || pSlot>=(pCArray->apCell[i]+sz)
- || CORRUPT_DB );
- memmove(pSlot, pCArray->apCell[i], sz);
+ memcpy(pSlot, apCell[i], sz);
put2byte(pCellptr, (pSlot - aData));
pCellptr += 2;
}
@@ -64300,27 +59298,22 @@ static int pageInsertArray(
*/
static int pageFreeArray(
MemPage *pPg, /* Page to edit */
- int iFirst, /* First cell to delete */
int nCell, /* Cells to delete */
- CellArray *pCArray /* Array of cells */
+ u8 **apCell, /* Array of cells */
+ u16 *szCell /* Array of cell sizes */
){
u8 * const aData = pPg->aData;
u8 * const pEnd = &aData[pPg->pBt->usableSize];
u8 * const pStart = &aData[pPg->hdrOffset + 8 + pPg->childPtrSize];
int nRet = 0;
int i;
- int iEnd = iFirst + nCell;
u8 *pFree = 0;
int szFree = 0;
- for(i=iFirst; i<iEnd; i++){
- u8 *pCell = pCArray->apCell[i];
- if( SQLITE_WITHIN(pCell, pStart, pEnd) ){
- int sz;
- /* No need to use cachedCellSize() here. The sizes of all cells that
- ** are to be freed have already been computing while deciding which
- ** cells need freeing */
- sz = pCArray->szCell[i]; assert( sz>0 );
+ for(i=0; i<nCell; i++){
+ u8 *pCell = apCell[i];
+ if( pCell>=pStart && pCell<pEnd ){
+ int sz = szCell[i];
if( pFree!=(pCell + sz) ){
if( pFree ){
assert( pFree>aData && (pFree - aData)<65536 );
@@ -64355,12 +59348,13 @@ static int pageFreeArray(
** The pPg->nFree field is invalid when this function returns. It is the
** responsibility of the caller to set it correctly.
*/
-static int editPage(
+static void editPage(
MemPage *pPg, /* Edit this page */
int iOld, /* Index of first cell currently on page */
int iNew, /* Index of new first cell on page */
int nNew, /* Final number of cells on page */
- CellArray *pCArray /* Array of cells and sizes */
+ u8 **apCell, /* Array of cells */
+ u16 *szCell /* Array of cell sizes */
){
u8 * const aData = pPg->aData;
const int hdr = pPg->hdrOffset;
@@ -64379,12 +59373,16 @@ static int editPage(
/* Remove cells from the start and end of the page */
if( iOld<iNew ){
- int nShift = pageFreeArray(pPg, iOld, iNew-iOld, pCArray);
+ int nShift = pageFreeArray(
+ pPg, iNew-iOld, &apCell[iOld], &szCell[iOld]
+ );
memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2);
nCell -= nShift;
}
if( iNewEnd < iOldEnd ){
- nCell -= pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray);
+ nCell -= pageFreeArray(
+ pPg, iOldEnd-iNewEnd, &apCell[iNewEnd], &szCell[iNewEnd]
+ );
}
pData = &aData[get2byteNotZero(&aData[hdr+5])];
@@ -64398,7 +59396,7 @@ static int editPage(
memmove(&pCellptr[nAdd*2], pCellptr, nCell*2);
if( pageInsertArray(
pPg, pBegin, &pData, pCellptr,
- iNew, nAdd, pCArray
+ nAdd, &apCell[iNew], &szCell[iNew]
) ) goto editpage_fail;
nCell += nAdd;
}
@@ -64412,7 +59410,7 @@ static int editPage(
nCell++;
if( pageInsertArray(
pPg, pBegin, &pData, pCellptr,
- iCell+iNew, 1, pCArray
+ 1, &apCell[iCell + iNew], &szCell[iCell + iNew]
) ) goto editpage_fail;
}
}
@@ -64421,7 +59419,7 @@ static int editPage(
pCellptr = &pPg->aCellIdx[nCell*2];
if( pageInsertArray(
pPg, pBegin, &pData, pCellptr,
- iNew+nCell, nNew-nCell, pCArray
+ nNew-nCell, &apCell[iNew+nCell], &szCell[iNew+nCell]
) ) goto editpage_fail;
pPg->nCell = nNew;
@@ -64432,21 +59430,19 @@ static int editPage(
#ifdef SQLITE_DEBUG
for(i=0; i<nNew && !CORRUPT_DB; i++){
- u8 *pCell = pCArray->apCell[i+iNew];
- int iOff = get2byteAligned(&pPg->aCellIdx[i*2]);
- if( SQLITE_WITHIN(pCell, aData, &aData[pPg->pBt->usableSize]) ){
+ u8 *pCell = apCell[i+iNew];
+ int iOff = get2byte(&pPg->aCellIdx[i*2]);
+ if( pCell>=aData && pCell<&aData[pPg->pBt->usableSize] ){
pCell = &pTmp[pCell - aData];
}
- assert( 0==memcmp(pCell, &aData[iOff],
- pCArray->pRef->xCellSize(pCArray->pRef, pCArray->apCell[i+iNew])) );
+ assert( 0==memcmp(pCell, &aData[iOff], szCell[i+iNew]) );
}
#endif
- return SQLITE_OK;
+ return;
editpage_fail:
/* Unable to edit this page. Rebuild it from scratch instead. */
- populateCellCache(pCArray, iNew, nNew);
- return rebuildPage(pPg, nNew, &pCArray->apCell[iNew], &pCArray->szCell[iNew]);
+ rebuildPage(pPg, nNew, &apCell[iNew], &szCell[iNew]);
}
/*
@@ -64512,14 +59508,13 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
u8 *pOut = &pSpace[4];
u8 *pCell = pPage->apOvfl[0];
- u16 szCell = pPage->xCellSize(pPage, pCell);
+ u16 szCell = cellSizePtr(pPage, pCell);
u8 *pStop;
assert( sqlite3PagerIswriteable(pNew->pDbPage) );
assert( pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) );
zeroPage(pNew, PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF);
- rc = rebuildPage(pNew, 1, &pCell, &szCell);
- if( NEVER(rc) ) return rc;
+ rebuildPage(pNew, 1, &pCell, &szCell);
pNew->nFree = pBt->usableSize - pNew->cellOffset - 2 - szCell;
/* If this is an auto-vacuum database, update the pointer map
@@ -64592,9 +59587,9 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){
u8 *z;
z = findCell(pPage, j);
- pPage->xParseCell(pPage, z, &info);
- if( info.nLocal<info.nPayload ){
- Pgno ovfl = get4byte(&z[info.nSize-4]);
+ btreeParseCellPtr(pPage, z, &info);
+ if( info.iOverflow ){
+ Pgno ovfl = get4byte(&z[info.iOverflow]);
ptrmapGet(pBt, ovfl, &e, &n);
assert( n==pPage->pgno && e==PTRMAP_OVERFLOW1 );
}
@@ -64712,6 +59707,9 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
** If aOvflSpace is set to a null pointer, this function returns
** SQLITE_NOMEM.
*/
+#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_M_ARM)
+#pragma optimize("", off)
+#endif
static int balance_nonroot(
MemPage *pParent, /* Parent page of siblings being balanced */
int iParentIdx, /* Index of "the page" in pParent */
@@ -64720,6 +59718,7 @@ static int balance_nonroot(
int bBulk /* True if this call is part of a bulk load */
){
BtShared *pBt; /* The whole database */
+ int nCell = 0; /* Number of cells in apCell[] */
int nMaxCells = 0; /* Allocated size of apCell, szCell, aFrom. */
int nNew = 0; /* Number of pages in apNew[] */
int nOld; /* Number of pages in apOld[] */
@@ -64730,6 +59729,7 @@ static int balance_nonroot(
int leafData; /* True if pPage is a leaf of a LEAFDATA tree */
int usableSpace; /* Bytes in pPage beyond the header */
int pageFlags; /* Value of pPage->aData[0] */
+ int subtotal; /* Subtotal of bytes in cells on one page */
int iSpace1 = 0; /* First unused byte of aSpace1[] */
int iOvflSpace = 0; /* First unused byte of aOvflSpace[] */
int szScratch; /* Size of scratch memory requested */
@@ -64737,20 +59737,19 @@ static int balance_nonroot(
MemPage *apNew[NB+2]; /* pPage and up to NB siblings after balancing */
u8 *pRight; /* Location in parent of right-sibling pointer */
u8 *apDiv[NB-1]; /* Divider cells in pParent */
- int cntNew[NB+2]; /* Index in b.paCell[] of cell after i-th page */
- int cntOld[NB+2]; /* Old index in b.apCell[] */
+ int cntNew[NB+2]; /* Index in aCell[] of cell after i-th page */
+ int cntOld[NB+2]; /* Old index in aCell[] after i-th page */
int szNew[NB+2]; /* Combined size of cells placed on i-th page */
+ u8 **apCell = 0; /* All cells begin balanced */
+ u16 *szCell; /* Local size of all cells in apCell[] */
u8 *aSpace1; /* Space for copies of dividers cells */
Pgno pgno; /* Temp var to store a page number in */
u8 abDone[NB+2]; /* True after i'th new page is populated */
Pgno aPgno[NB+2]; /* Page numbers of new pages before shuffling */
Pgno aPgOrder[NB+2]; /* Copy of aPgno[] used for sorting pages */
u16 aPgFlags[NB+2]; /* flags field of new pages before shuffling */
- CellArray b; /* Parsed information on cells being balanced */
memset(abDone, 0, sizeof(abDone));
- b.nCell = 0;
- b.apCell = 0;
pBt = pParent->pBt;
assert( sqlite3_mutex_held(pBt->mutex) );
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
@@ -64768,7 +59767,7 @@ static int balance_nonroot(
assert( pParent->nOverflow==0 || pParent->aiOvfl[0]==iParentIdx );
if( !aOvflSpace ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
/* Find the sibling pages to balance. Also locate the cells in pParent
@@ -64804,7 +59803,7 @@ static int balance_nonroot(
}
pgno = get4byte(pRight);
while( 1 ){
- rc = getAndInitPage(pBt, pgno, &apOld[i], 0, 0);
+ rc = getAndInitPage(pBt, pgno, &apOld[i], 0);
if( rc ){
memset(apOld, 0, (i+1)*sizeof(MemPage*));
goto balance_cleanup;
@@ -64815,12 +59814,12 @@ static int balance_nonroot(
if( i+nxDiv==pParent->aiOvfl[0] && pParent->nOverflow ){
apDiv[i] = pParent->apOvfl[0];
pgno = get4byte(apDiv[i]);
- szNew[i] = pParent->xCellSize(pParent, apDiv[i]);
+ szNew[i] = cellSizePtr(pParent, apDiv[i]);
pParent->nOverflow = 0;
}else{
apDiv[i] = findCell(pParent, i+nxDiv-pParent->nOverflow);
pgno = get4byte(apDiv[i]);
- szNew[i] = pParent->xCellSize(pParent, apDiv[i]);
+ szNew[i] = cellSizePtr(pParent, apDiv[i]);
/* Drop the cell from the parent page. apDiv[i] still points to
** the cell within the parent, even though it has been dropped.
@@ -64859,200 +59858,130 @@ static int balance_nonroot(
** Allocate space for memory structures
*/
szScratch =
- nMaxCells*sizeof(u8*) /* b.apCell */
- + nMaxCells*sizeof(u16) /* b.szCell */
+ nMaxCells*sizeof(u8*) /* apCell */
+ + nMaxCells*sizeof(u16) /* szCell */
+ pBt->pageSize; /* aSpace1 */
/* EVIDENCE-OF: R-28375-38319 SQLite will never request a scratch buffer
** that is more than 6 times the database page size. */
assert( szScratch<=6*(int)pBt->pageSize );
- b.apCell = sqlite3ScratchMalloc( szScratch );
- if( b.apCell==0 ){
- rc = SQLITE_NOMEM_BKPT;
+ apCell = sqlite3ScratchMalloc( szScratch );
+ if( apCell==0 ){
+ rc = SQLITE_NOMEM;
goto balance_cleanup;
}
- b.szCell = (u16*)&b.apCell[nMaxCells];
- aSpace1 = (u8*)&b.szCell[nMaxCells];
+ szCell = (u16*)&apCell[nMaxCells];
+ aSpace1 = (u8*)&szCell[nMaxCells];
assert( EIGHT_BYTE_ALIGNMENT(aSpace1) );
/*
** Load pointers to all cells on sibling pages and the divider cells
- ** into the local b.apCell[] array. Make copies of the divider cells
+ ** into the local apCell[] array. Make copies of the divider cells
** into space obtained from aSpace1[]. The divider cells have already
** been removed from pParent.
**
** If the siblings are on leaf pages, then the child pointers of the
** divider cells are stripped from the cells before they are copied
- ** into aSpace1[]. In this way, all cells in b.apCell[] are without
+ ** into aSpace1[]. In this way, all cells in apCell[] are without
** child pointers. If siblings are not leaves, then all cell in
- ** b.apCell[] include child pointers. Either way, all cells in b.apCell[]
+ ** apCell[] include child pointers. Either way, all cells in apCell[]
** are alike.
**
** leafCorrection: 4 if pPage is a leaf. 0 if pPage is not a leaf.
** leafData: 1 if pPage holds key+data and pParent holds only keys.
*/
- b.pRef = apOld[0];
- leafCorrection = b.pRef->leaf*4;
- leafData = b.pRef->intKeyLeaf;
+ leafCorrection = apOld[0]->leaf*4;
+ leafData = apOld[0]->intKeyLeaf;
for(i=0; i<nOld; i++){
+ int limit;
MemPage *pOld = apOld[i];
- int limit = pOld->nCell;
- u8 *aData = pOld->aData;
- u16 maskPage = pOld->maskPage;
- u8 *piCell = aData + pOld->cellOffset;
- u8 *piEnd;
-
- /* Verify that all sibling pages are of the same "type" (table-leaf,
- ** table-interior, index-leaf, or index-interior).
- */
- if( pOld->aData[0]!=apOld[0]->aData[0] ){
- rc = SQLITE_CORRUPT_BKPT;
- goto balance_cleanup;
- }
- /* Load b.apCell[] with pointers to all cells in pOld. If pOld
- ** constains overflow cells, include them in the b.apCell[] array
- ** in the correct spot.
- **
- ** Note that when there are multiple overflow cells, it is always the
- ** case that they are sequential and adjacent. This invariant arises
- ** because multiple overflows can only occurs when inserting divider
- ** cells into a parent on a prior balance, and divider cells are always
- ** adjacent and are inserted in order. There is an assert() tagged
- ** with "NOTE 1" in the overflow cell insertion loop to prove this
- ** invariant.
- **
- ** This must be done in advance. Once the balance starts, the cell
- ** offset section of the btree page will be overwritten and we will no
- ** long be able to find the cells if a pointer to each cell is not saved
- ** first.
- */
- memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow));
+ limit = pOld->nCell+pOld->nOverflow;
if( pOld->nOverflow>0 ){
- limit = pOld->aiOvfl[0];
for(j=0; j<limit; j++){
- b.apCell[b.nCell] = aData + (maskPage & get2byteAligned(piCell));
- piCell += 2;
- b.nCell++;
+ assert( nCell<nMaxCells );
+ apCell[nCell] = findOverflowCell(pOld, j);
+ szCell[nCell] = cellSizePtr(pOld, apCell[nCell]);
+ nCell++;
}
- for(k=0; k<pOld->nOverflow; k++){
- assert( k==0 || pOld->aiOvfl[k-1]+1==pOld->aiOvfl[k] );/* NOTE 1 */
- b.apCell[b.nCell] = pOld->apOvfl[k];
- b.nCell++;
+ }else{
+ u8 *aData = pOld->aData;
+ u16 maskPage = pOld->maskPage;
+ u16 cellOffset = pOld->cellOffset;
+ for(j=0; j<limit; j++){
+ assert( nCell<nMaxCells );
+ apCell[nCell] = findCellv2(aData, maskPage, cellOffset, j);
+ szCell[nCell] = cellSizePtr(pOld, apCell[nCell]);
+ nCell++;
}
- }
- piEnd = aData + pOld->cellOffset + 2*pOld->nCell;
- while( piCell<piEnd ){
- assert( b.nCell<nMaxCells );
- b.apCell[b.nCell] = aData + (maskPage & get2byteAligned(piCell));
- piCell += 2;
- b.nCell++;
- }
-
- cntOld[i] = b.nCell;
+ }
+ cntOld[i] = nCell;
if( i<nOld-1 && !leafData){
u16 sz = (u16)szNew[i];
u8 *pTemp;
- assert( b.nCell<nMaxCells );
- b.szCell[b.nCell] = sz;
+ assert( nCell<nMaxCells );
+ szCell[nCell] = sz;
pTemp = &aSpace1[iSpace1];
iSpace1 += sz;
assert( sz<=pBt->maxLocal+23 );
assert( iSpace1 <= (int)pBt->pageSize );
memcpy(pTemp, apDiv[i], sz);
- b.apCell[b.nCell] = pTemp+leafCorrection;
+ apCell[nCell] = pTemp+leafCorrection;
assert( leafCorrection==0 || leafCorrection==4 );
- b.szCell[b.nCell] = b.szCell[b.nCell] - leafCorrection;
+ szCell[nCell] = szCell[nCell] - leafCorrection;
if( !pOld->leaf ){
assert( leafCorrection==0 );
assert( pOld->hdrOffset==0 );
/* The right pointer of the child page pOld becomes the left
** pointer of the divider cell */
- memcpy(b.apCell[b.nCell], &pOld->aData[8], 4);
+ memcpy(apCell[nCell], &pOld->aData[8], 4);
}else{
assert( leafCorrection==4 );
- while( b.szCell[b.nCell]<4 ){
+ if( szCell[nCell]<4 ){
/* Do not allow any cells smaller than 4 bytes. If a smaller cell
** does exist, pad it with 0x00 bytes. */
- assert( b.szCell[b.nCell]==3 || CORRUPT_DB );
- assert( b.apCell[b.nCell]==&aSpace1[iSpace1-3] || CORRUPT_DB );
+ assert( szCell[nCell]==3 );
+ assert( apCell[nCell]==&aSpace1[iSpace1-3] );
aSpace1[iSpace1++] = 0x00;
- b.szCell[b.nCell]++;
+ szCell[nCell] = 4;
}
}
- b.nCell++;
+ nCell++;
}
}
/*
- ** Figure out the number of pages needed to hold all b.nCell cells.
+ ** Figure out the number of pages needed to hold all nCell cells.
** Store this number in "k". Also compute szNew[] which is the total
** size of all cells on the i-th page and cntNew[] which is the index
- ** in b.apCell[] of the cell that divides page i from page i+1.
- ** cntNew[k] should equal b.nCell.
+ ** in apCell[] of the cell that divides page i from page i+1.
+ ** cntNew[k] should equal nCell.
**
** Values computed by this block:
**
** k: The total number of sibling pages
** szNew[i]: Spaced used on the i-th sibling page.
- ** cntNew[i]: Index in b.apCell[] and b.szCell[] for the first cell to
+ ** cntNew[i]: Index in apCell[] and szCell[] for the first cell to
** the right of the i-th sibling page.
** usableSpace: Number of bytes of space available on each sibling.
**
*/
usableSpace = pBt->usableSize - 12 + leafCorrection;
- for(i=0; i<nOld; i++){
- MemPage *p = apOld[i];
- szNew[i] = usableSpace - p->nFree;
- if( szNew[i]<0 ){ rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; }
- for(j=0; j<p->nOverflow; j++){
- szNew[i] += 2 + p->xCellSize(p, p->apOvfl[j]);
- }
- cntNew[i] = cntOld[i];
- }
- k = nOld;
- for(i=0; i<k; i++){
- int sz;
- while( szNew[i]>usableSpace ){
- if( i+1>=k ){
- k = i+2;
- if( k>NB+2 ){ rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; }
- szNew[k-1] = 0;
- cntNew[k-1] = b.nCell;
- }
- sz = 2 + cachedCellSize(&b, cntNew[i]-1);
- szNew[i] -= sz;
- if( !leafData ){
- if( cntNew[i]<b.nCell ){
- sz = 2 + cachedCellSize(&b, cntNew[i]);
- }else{
- sz = 0;
- }
- }
- szNew[i+1] += sz;
- cntNew[i]--;
- }
- while( cntNew[i]<b.nCell ){
- sz = 2 + cachedCellSize(&b, cntNew[i]);
- if( szNew[i]+sz>usableSpace ) break;
- szNew[i] += sz;
- cntNew[i]++;
- if( !leafData ){
- if( cntNew[i]<b.nCell ){
- sz = 2 + cachedCellSize(&b, cntNew[i]);
- }else{
- sz = 0;
- }
- }
- szNew[i+1] -= sz;
- }
- if( cntNew[i]>=b.nCell ){
- k = i+1;
- }else if( cntNew[i] <= (i>0 ? cntNew[i-1] : 0) ){
- rc = SQLITE_CORRUPT_BKPT;
- goto balance_cleanup;
- }
- }
+ for(subtotal=k=i=0; i<nCell; i++){
+ assert( i<nMaxCells );
+ subtotal += szCell[i] + 2;
+ if( subtotal > usableSpace ){
+ szNew[k] = subtotal - szCell[i] - 2;
+ cntNew[k] = i;
+ if( leafData ){ i--; }
+ subtotal = 0;
+ k++;
+ if( k>NB+1 ){ rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; }
+ }
+ }
+ szNew[k] = subtotal;
+ cntNew[k] = nCell;
+ k++;
/*
** The packing computed by the previous block is biased toward the siblings
@@ -65073,27 +60002,19 @@ static int balance_nonroot(
r = cntNew[i-1] - 1;
d = r + 1 - leafData;
- (void)cachedCellSize(&b, d);
- do{
- assert( d<nMaxCells );
- assert( r<nMaxCells );
- (void)cachedCellSize(&b, r);
- if( szRight!=0
- && (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+2)) ){
- break;
- }
- szRight += b.szCell[d] + 2;
- szLeft -= b.szCell[r] + 2;
- cntNew[i-1] = r;
- r--;
- d--;
- }while( r>=0 );
+ assert( d<nMaxCells );
+ assert( r<nMaxCells );
+ while( szRight==0
+ || (!bBulk && szRight+szCell[d]+2<=szLeft-(szCell[r]+2))
+ ){
+ szRight += szCell[d] + 2;
+ szLeft -= szCell[r] + 2;
+ cntNew[i-1]--;
+ r = cntNew[i-1] - 1;
+ d = r + 1 - leafData;
+ }
szNew[i] = szRight;
szNew[i-1] = szLeft;
- if( cntNew[i-1] <= (i>1 ? cntNew[i-2] : 0) ){
- rc = SQLITE_CORRUPT_BKPT;
- goto balance_cleanup;
- }
}
/* Sanity check: For a non-corrupt database file one of the follwing
@@ -65113,6 +60034,10 @@ static int balance_nonroot(
/*
** Allocate k new pages. Reuse old pages where possible.
*/
+ if( apOld[0]->pgno<=1 ){
+ rc = SQLITE_CORRUPT_BKPT;
+ goto balance_cleanup;
+ }
pageFlags = apOld[0]->aData[0];
for(i=0; i<k; i++){
MemPage *pNew;
@@ -65129,7 +60054,7 @@ static int balance_nonroot(
zeroPage(pNew, pageFlags);
apNew[i] = pNew;
nNew++;
- cntOld[i] = b.nCell;
+ cntOld[i] = nCell;
/* Set the pointer-map entry for the new sibling page. */
if( ISAUTOVACUUM ){
@@ -65234,8 +60159,8 @@ static int balance_nonroot(
int iNew = 0;
int iOld = 0;
- for(i=0; i<b.nCell; i++){
- u8 *pCell = b.apCell[i];
+ for(i=0; i<nCell; i++){
+ u8 *pCell = apCell[i];
if( i==cntOldNext ){
MemPage *pOld = (++iOld)<nNew ? apNew[iOld] : apOld[iOld];
cntOldNext += pOld->nCell + pOld->nOverflow + !leafData;
@@ -65254,15 +60179,15 @@ static int balance_nonroot(
** overflow cell), we can skip updating the pointer map entries. */
if( iOld>=nNew
|| pNew->pgno!=aPgno[iOld]
- || !SQLITE_WITHIN(pCell,aOld,&aOld[usableSize])
+ || pCell<aOld
+ || pCell>=&aOld[usableSize]
){
if( !leafCorrection ){
ptrmapPut(pBt, get4byte(pCell), PTRMAP_BTREE, pNew->pgno, &rc);
}
- if( cachedCellSize(&b,i)>pNew->minLocal ){
+ if( szCell[i]>pNew->minLocal ){
ptrmapPutOvflPtr(pNew, pCell, &rc);
}
- if( rc ) goto balance_cleanup;
}
}
}
@@ -65276,21 +60201,20 @@ static int balance_nonroot(
j = cntNew[i];
assert( j<nMaxCells );
- assert( b.apCell[j]!=0 );
- pCell = b.apCell[j];
- sz = b.szCell[j] + leafCorrection;
+ pCell = apCell[j];
+ sz = szCell[j] + leafCorrection;
pTemp = &aOvflSpace[iOvflSpace];
if( !pNew->leaf ){
memcpy(&pNew->aData[8], pCell, 4);
}else if( leafData ){
/* If the tree is a leaf-data tree, and the siblings are leaves,
- ** then there is no divider cell in b.apCell[]. Instead, the divider
+ ** then there is no divider cell in apCell[]. Instead, the divider
** cell consists of the integer key for the right-most cell of
** the sibling-page assembled above only.
*/
CellInfo info;
j--;
- pNew->xParseCell(pNew, b.apCell[j], &info);
+ btreeParseCellPtr(pNew, apCell[j], &info);
pCell = pTemp;
sz = 4 + putVarint(&pCell[4], info.nKey);
pTemp = 0;
@@ -65303,13 +60227,13 @@ static int balance_nonroot(
** any cell). But it is important to pass the correct size to
** insertCell(), so reparse the cell now.
**
- ** This can only happen for b-trees used to evaluate "IN (SELECT ...)"
- ** and WITHOUT ROWID tables with exactly one column which is the
- ** primary key.
+ ** Note that this can never happen in an SQLite data file, as all
+ ** cells are at least 4 bytes. It only happens in b-trees used
+ ** to evaluate "IN (SELECT ...)" and similar clauses.
*/
- if( b.szCell[j]==4 ){
+ if( szCell[j]==4 ){
assert(leafCorrection==4);
- sz = pParent->xCellSize(pParent, pCell);
+ sz = cellSizePtr(pParent, pCell);
}
}
iOvflSpace += sz;
@@ -65365,13 +60289,12 @@ static int balance_nonroot(
iNew = iOld = 0;
nNewCell = cntNew[0];
}else{
- iOld = iPg<nOld ? (cntOld[iPg-1] + !leafData) : b.nCell;
+ iOld = iPg<nOld ? (cntOld[iPg-1] + !leafData) : nCell;
iNew = cntNew[iPg-1] + !leafData;
nNewCell = cntNew[iPg] - iNew;
}
- rc = editPage(apNew[iPg], iOld, iNew, nNewCell, &b);
- if( rc ) goto balance_cleanup;
+ editPage(apNew[iPg], iOld, iNew, nNewCell, apCell, szCell);
abDone[iPg]++;
apNew[iPg]->nFree = usableSpace-szNew[iPg];
assert( apNew[iPg]->nOverflow==0 );
@@ -65401,7 +60324,7 @@ static int balance_nonroot(
** by smaller than the child due to the database header, and so all the
** free space needs to be up front.
*/
- assert( nNew==1 || CORRUPT_DB );
+ assert( nNew==1 );
rc = defragmentPage(apNew[0]);
testcase( rc!=SQLITE_OK );
assert( apNew[0]->nFree ==
@@ -65422,7 +60345,7 @@ static int balance_nonroot(
assert( pParent->isInit );
TRACE(("BALANCE: finished: old=%d new=%d cells=%d\n",
- nOld, nNew, b.nCell));
+ nOld, nNew, nCell));
/* Free any old pages that were not reused as new pages.
*/
@@ -65445,7 +60368,7 @@ static int balance_nonroot(
** Cleanup before returning.
*/
balance_cleanup:
- sqlite3ScratchFree(b.apCell);
+ sqlite3ScratchFree(apCell);
for(i=0; i<nOld; i++){
releasePage(apOld[i]);
}
@@ -65455,6 +60378,9 @@ balance_cleanup:
return rc;
}
+#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_M_ARM)
+#pragma optimize("", on)
+#endif
/*
@@ -65539,8 +60465,8 @@ static int balance(BtCursor *pCur){
u8 aBalanceQuickSpace[13];
u8 *pFree = 0;
- VVA_ONLY( int balance_quick_called = 0 );
- VVA_ONLY( int balance_deeper_called = 0 );
+ TESTONLY( int balance_quick_called = 0 );
+ TESTONLY( int balance_deeper_called = 0 );
do {
int iPage = pCur->iPage;
@@ -65553,8 +60479,7 @@ static int balance(BtCursor *pCur){
** and copy the current contents of the root-page to it. The
** next iteration of the do-loop will balance the child page.
*/
- assert( balance_deeper_called==0 );
- VVA_ONLY( balance_deeper_called++ );
+ assert( (balance_deeper_called++)==0 );
rc = balance_deeper(pPage, &pCur->apPage[1]);
if( rc==SQLITE_OK ){
pCur->iPage = 1;
@@ -65593,8 +60518,7 @@ static int balance(BtCursor *pCur){
** function. If this were not verified, a subtle bug involving reuse
** of the aBalanceQuickSpace[] might sneak in.
*/
- assert( balance_quick_called==0 );
- VVA_ONLY( balance_quick_called++ );
+ assert( (balance_quick_called++)==0 );
rc = balance_quick(pParent, pPage, aBalanceQuickSpace);
}else
#endif
@@ -65695,7 +60619,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
return pCur->skipNext;
}
- assert( cursorOwnsBtShared(pCur) );
+ assert( cursorHoldsMutex(pCur) );
assert( (pCur->curFlags & BTCF_WriteFlag)!=0
&& pBt->inTransaction==TRANS_WRITE
&& (pBt->btsFlags & BTS_READ_ONLY)==0 );
@@ -65719,28 +60643,24 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
** doing any work. To avoid thwarting these optimizations, it is important
** not to clear the cursor here.
*/
- if( pCur->curFlags & BTCF_Multiple ){
- rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur);
- if( rc ) return rc;
- }
+ rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur);
+ if( rc ) return rc;
if( pCur->pKeyInfo==0 ){
- assert( pKey==0 );
/* If this is an insert into a table b-tree, invalidate any incrblob
** cursors open on the row being replaced */
invalidateIncrblobCursors(p, nKey, 0);
/* If the cursor is currently on the last row and we are appending a
- ** new row onto the end, set the "loc" to avoid an unnecessary
- ** btreeMoveto() call */
+ ** new row onto the end, set the "loc" to avoid an unnecessary btreeMoveto()
+ ** call */
if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0
&& pCur->info.nKey==nKey-1 ){
- loc = -1;
- }else if( loc==0 ){
- rc = sqlite3BtreeMovetoUnpacked(pCur, 0, nKey, appendBias, &loc);
- if( rc ) return rc;
+ loc = -1;
}
- }else if( loc==0 ){
+ }
+
+ if( !loc ){
rc = btreeMoveto(pCur, pKey, nKey, appendBias, &loc);
if( rc ) return rc;
}
@@ -65758,7 +60678,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
assert( newCell!=0 );
rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew);
if( rc ) goto end_insert;
- assert( szNew==pPage->xCellSize(pPage, newCell) );
+ assert( szNew==cellSizePtr(pPage, newCell) );
assert( szNew <= MX_CELL_SIZE(pBt) );
idx = pCur->aiIdx[pCur->iPage];
if( loc==0 ){
@@ -65823,23 +60743,10 @@ end_insert:
}
/*
-** Delete the entry that the cursor is pointing to.
-**
-** If the BTREE_SAVEPOSITION bit of the flags parameter is zero, then
-** the cursor is left pointing at an arbitrary location after the delete.
-** But if that bit is set, then the cursor is left in a state such that
-** the next call to BtreeNext() or BtreePrev() moves it to the same row
-** as it would have been on if the call to BtreeDelete() had been omitted.
-**
-** The BTREE_AUXDELETE bit of flags indicates that is one of several deletes
-** associated with a single table entry and its indexes. Only one of those
-** deletes is considered the "primary" delete. The primary delete occurs
-** on a cursor that is not a BTREE_FORDELETE cursor. All but one delete
-** operation on non-FORDELETE cursors is tagged with the AUXDELETE flag.
-** The BTREE_AUXDELETE bit is a hint that is not used by this implementation,
-** but which might be used by alternative storage engines.
+** Delete the entry that the cursor is pointing to. The cursor
+** is left pointing at an arbitrary location.
*/
-SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
+SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
Btree *p = pCur->pBtree;
BtShared *pBt = p->pBt;
int rc; /* Return code */
@@ -65848,46 +60755,25 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
int iCellIdx; /* Index of cell to delete */
int iCellDepth; /* Depth of node containing pCell */
u16 szCell; /* Size of the cell being deleted */
- int bSkipnext = 0; /* Leaf cursor in SKIPNEXT state */
- u8 bPreserve = flags & BTREE_SAVEPOSITION; /* Keep cursor valid */
- assert( cursorOwnsBtShared(pCur) );
+ assert( cursorHoldsMutex(pCur) );
assert( pBt->inTransaction==TRANS_WRITE );
assert( (pBt->btsFlags & BTS_READ_ONLY)==0 );
assert( pCur->curFlags & BTCF_WriteFlag );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
- assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
- assert( pCur->eState==CURSOR_VALID );
- assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 );
+
+ if( NEVER(pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell)
+ || NEVER(pCur->eState!=CURSOR_VALID)
+ ){
+ return SQLITE_ERROR; /* Something has gone awry. */
+ }
iCellDepth = pCur->iPage;
iCellIdx = pCur->aiIdx[iCellDepth];
pPage = pCur->apPage[iCellDepth];
pCell = findCell(pPage, iCellIdx);
- /* If the bPreserve flag is set to true, then the cursor position must
- ** be preserved following this delete operation. If the current delete
- ** will cause a b-tree rebalance, then this is done by saving the cursor
- ** key and leaving the cursor in CURSOR_REQUIRESEEK state before
- ** returning.
- **
- ** Or, if the current delete will not cause a rebalance, then the cursor
- ** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
- ** before or after the deleted entry. In this case set bSkipnext to true. */
- if( bPreserve ){
- if( !pPage->leaf
- || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
- ){
- /* A b-tree rebalance will be required after deleting this entry.
- ** Save the cursor key. */
- rc = saveCursorKey(pCur);
- if( rc ) return rc;
- }else{
- bSkipnext = 1;
- }
- }
-
/* If the page containing the entry to delete is not a leaf page, move
** the cursor to the largest entry in the tree that is smaller than
** the entry being deleted. This cell will replace the cell being deleted
@@ -65902,11 +60788,12 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
}
/* Save the positions of any other cursors open on this table before
- ** making any modifications. */
- if( pCur->curFlags & BTCF_Multiple ){
- rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur);
- if( rc ) return rc;
- }
+ ** making any modifications. Make the page containing the entry to be
+ ** deleted writable. Then free any overflow pages associated with the
+ ** entry and finally remove the cell itself from within the page.
+ */
+ rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur);
+ if( rc ) return rc;
/* If this is a delete operation to remove a row from a table b-tree,
** invalidate any incrblob cursors open on the row being deleted. */
@@ -65914,9 +60801,6 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
invalidateIncrblobCursors(p, pCur->info.nKey, 0);
}
- /* Make the page containing the entry to be deleted writable. Then free any
- ** overflow pages associated with the entry and finally remove the cell
- ** itself from within the page. */
rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc ) return rc;
rc = clearCell(pPage, pCell, &szCell);
@@ -65935,8 +60819,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
unsigned char *pTmp;
pCell = findCell(pLeaf, pLeaf->nCell-1);
- if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT;
- nCell = pLeaf->xCellSize(pLeaf, pCell);
+ nCell = cellSizePtr(pLeaf, pCell);
assert( MX_CELL_SIZE(pBt) >= nCell );
pTmp = pBt->pTmpSpace;
assert( pTmp!=0 );
@@ -65970,23 +60853,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
}
if( rc==SQLITE_OK ){
- if( bSkipnext ){
- assert( bPreserve && (pCur->iPage==iCellDepth || CORRUPT_DB) );
- assert( pPage==pCur->apPage[pCur->iPage] || CORRUPT_DB );
- assert( (pPage->nCell>0 || CORRUPT_DB) && iCellIdx<=pPage->nCell );
- pCur->eState = CURSOR_SKIPNEXT;
- if( iCellIdx>=pPage->nCell ){
- pCur->skipNext = -1;
- pCur->aiIdx[iCellDepth] = pPage->nCell-1;
- }else{
- pCur->skipNext = 1;
- }
- }else{
- rc = moveToRoot(pCur);
- if( bPreserve ){
- pCur->eState = CURSOR_REQUIRESEEK;
- }
- }
+ moveToRoot(pCur);
}
return rc;
}
@@ -66044,8 +60911,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
pgnoRoot==PENDING_BYTE_PAGE(pBt) ){
pgnoRoot++;
}
- assert( pgnoRoot>=3 || CORRUPT_DB );
- testcase( pgnoRoot<3 );
+ assert( pgnoRoot>=3 );
/* Allocate a page. The page that currently resides at pgnoRoot will
** be moved to the allocated page (unless the allocated page happens
@@ -66174,7 +61040,7 @@ static int clearDatabasePage(
if( pgno>btreePagecount(pBt) ){
return SQLITE_CORRUPT_BKPT;
}
- rc = getAndInitPage(pBt, pgno, &pPage, 0, 0);
+ rc = getAndInitPage(pBt, pgno, &pPage, 0);
if( rc ) return rc;
if( pPage->bBusy ){
rc = SQLITE_CORRUPT_BKPT;
@@ -66195,8 +61061,7 @@ static int clearDatabasePage(
rc = clearDatabasePage(pBt, get4byte(&pPage->aData[hdr+8]), 1, pnChange);
if( rc ) goto cleardatabasepage_out;
}else if( pnChange ){
- assert( pPage->intKey || CORRUPT_DB );
- testcase( !pPage->intKey );
+ assert( pPage->intKey );
*pnChange += pPage->nCell;
}
if( freePageFlag ){
@@ -66293,14 +61158,6 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
return SQLITE_LOCKED_SHAREDCACHE;
}
- /*
- ** It is illegal to drop the sqlite_master table on page 1. But again,
- ** this error is caught long before reaching this point.
- */
- if( NEVER(iTable<2) ){
- return SQLITE_CORRUPT_BKPT;
- }
-
rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
if( rc ) return rc;
rc = sqlite3BtreeClearTable(p, iTable, 0);
@@ -66311,67 +61168,76 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
*piMoved = 0;
+ if( iTable>1 ){
#ifdef SQLITE_OMIT_AUTOVACUUM
- freePage(pPage, &rc);
- releasePage(pPage);
+ freePage(pPage, &rc);
+ releasePage(pPage);
#else
- if( pBt->autoVacuum ){
- Pgno maxRootPgno;
- sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &maxRootPgno);
+ if( pBt->autoVacuum ){
+ Pgno maxRootPgno;
+ sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &maxRootPgno);
- if( iTable==maxRootPgno ){
- /* If the table being dropped is the table with the largest root-page
- ** number in the database, put the root page on the free list.
- */
- freePage(pPage, &rc);
- releasePage(pPage);
- if( rc!=SQLITE_OK ){
- return rc;
+ if( iTable==maxRootPgno ){
+ /* If the table being dropped is the table with the largest root-page
+ ** number in the database, put the root page on the free list.
+ */
+ freePage(pPage, &rc);
+ releasePage(pPage);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ }else{
+ /* The table being dropped does not have the largest root-page
+ ** number in the database. So move the page that does into the
+ ** gap left by the deleted root-page.
+ */
+ MemPage *pMove;
+ releasePage(pPage);
+ rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0);
+ releasePage(pMove);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ pMove = 0;
+ rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
+ freePage(pMove, &rc);
+ releasePage(pMove);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ *piMoved = maxRootPgno;
}
- }else{
- /* The table being dropped does not have the largest root-page
- ** number in the database. So move the page that does into the
- ** gap left by the deleted root-page.
+
+ /* Set the new 'max-root-page' value in the database header. This
+ ** is the old value less one, less one more if that happens to
+ ** be a root-page number, less one again if that is the
+ ** PENDING_BYTE_PAGE.
*/
- MemPage *pMove;
- releasePage(pPage);
- rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0);
- releasePage(pMove);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- pMove = 0;
- rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
- freePage(pMove, &rc);
- releasePage(pMove);
- if( rc!=SQLITE_OK ){
- return rc;
+ maxRootPgno--;
+ while( maxRootPgno==PENDING_BYTE_PAGE(pBt)
+ || PTRMAP_ISPAGE(pBt, maxRootPgno) ){
+ maxRootPgno--;
}
- *piMoved = maxRootPgno;
- }
+ assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) );
- /* Set the new 'max-root-page' value in the database header. This
- ** is the old value less one, less one more if that happens to
- ** be a root-page number, less one again if that is the
- ** PENDING_BYTE_PAGE.
- */
- maxRootPgno--;
- while( maxRootPgno==PENDING_BYTE_PAGE(pBt)
- || PTRMAP_ISPAGE(pBt, maxRootPgno) ){
- maxRootPgno--;
+ rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno);
+ }else{
+ freePage(pPage, &rc);
+ releasePage(pPage);
}
- assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) );
-
- rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno);
+#endif
}else{
- freePage(pPage, &rc);
+ /* If sqlite3BtreeDropTable was called on page 1.
+ ** This really never should happen except in a corrupt
+ ** database.
+ */
+ zeroPage(pPage, PTF_INTKEY|PTF_LEAF );
releasePage(pPage);
}
-#endif
return rc;
}
SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
@@ -66550,6 +61416,7 @@ static void checkAppendMsg(
...
){
va_list ap;
+ char zBuf[200];
if( !pCheck->mxErr ) return;
pCheck->mxErr--;
pCheck->nErr++;
@@ -66558,9 +61425,10 @@ static void checkAppendMsg(
sqlite3StrAccumAppend(&pCheck->errMsg, "\n", 1);
}
if( pCheck->zPfx ){
- sqlite3XPrintf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, pCheck->zPfx, pCheck->v1, pCheck->v2);
+ sqlite3StrAccumAppendAll(&pCheck->errMsg, zBuf);
}
- sqlite3VXPrintf(&pCheck->errMsg, zFormat, ap);
+ sqlite3VXPrintf(&pCheck->errMsg, 1, zFormat, ap);
va_end(ap);
if( pCheck->errMsg.accError==STRACCUM_NOMEM ){
pCheck->mallocFailed = 1;
@@ -66664,7 +61532,7 @@ static void checkList(
break;
}
if( checkRef(pCheck, iPage) ) break;
- if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){
+ if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage) ){
checkAppendMsg(pCheck, "failed to get page %d", iPage);
break;
}
@@ -66707,10 +61575,6 @@ static void checkList(
#endif
iPage = get4byte(pOvflData);
sqlite3PagerUnref(pOvflPage);
-
- if( isFreeList && N<(iPage!=0) ){
- checkAppendMsg(pCheck, "free-page count in header is too small");
- }
}
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -66776,42 +61640,35 @@ static int btreeHeapPull(u32 *aHeap, u32 *pOut){
**
** 1. Make sure that cells and freeblocks do not overlap
** but combine to completely cover the page.
-** 2. Make sure integer cell keys are in order.
-** 3. Check the integrity of overflow pages.
-** 4. Recursively call checkTreePage on all children.
-** 5. Verify that the depth of all children is the same.
+** NO 2. Make sure cell keys are in order.
+** NO 3. Make sure no key is less than or equal to zLowerBound.
+** NO 4. Make sure no key is greater than or equal to zUpperBound.
+** 5. Check the integrity of overflow pages.
+** 6. Recursively call checkTreePage on all children.
+** 7. Verify that the depth of all children is the same.
+** 8. Make sure this page is at least 33% full or else it is
+** the root of the tree.
*/
static int checkTreePage(
IntegrityCk *pCheck, /* Context for the sanity check */
int iPage, /* Page number of the page to check */
- i64 *piMinKey, /* Write minimum integer primary key here */
- i64 maxKey /* Error if integer primary key greater than this */
+ i64 *pnParentMinKey,
+ i64 *pnParentMaxKey
){
- MemPage *pPage = 0; /* The page being analyzed */
- int i; /* Loop counter */
- int rc; /* Result code from subroutine call */
- int depth = -1, d2; /* Depth of a subtree */
- int pgno; /* Page number */
- int nFrag; /* Number of fragmented bytes on the page */
- int hdr; /* Offset to the page header */
- int cellStart; /* Offset to the start of the cell pointer array */
- int nCell; /* Number of cells */
- int doCoverageCheck = 1; /* True if cell coverage checking should be done */
- int keyCanBeEqual = 1; /* True if IPK can be equal to maxKey
- ** False if IPK must be strictly less than maxKey */
- u8 *data; /* Page content */
- u8 *pCell; /* Cell content */
- u8 *pCellIdx; /* Next element of the cell pointer array */
- BtShared *pBt; /* The BtShared object that owns pPage */
- u32 pc; /* Address of a cell */
- u32 usableSize; /* Usable size of the page */
- u32 contentOffset; /* Offset to the start of the cell content area */
- u32 *heap = 0; /* Min-heap used for checking cell coverage */
- u32 x, prev = 0; /* Next and previous entry on the min-heap */
+ MemPage *pPage;
+ int i, rc, depth, d2, pgno, cnt;
+ int hdr, cellStart;
+ int nCell;
+ u8 *data;
+ BtShared *pBt;
+ int usableSize;
+ u32 *heap = 0;
+ u32 x, prev = 0;
+ i64 nMinKey = 0;
+ i64 nMaxKey = 0;
const char *saved_zPfx = pCheck->zPfx;
int saved_v1 = pCheck->v1;
int saved_v2 = pCheck->v2;
- u8 savedIsInit = 0;
/* Check that the page exists
*/
@@ -66824,95 +61681,54 @@ static int checkTreePage(
if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){
checkAppendMsg(pCheck,
"unable to get the page. error code=%d", rc);
+ depth = -1;
goto end_of_check;
}
/* Clear MemPage.isInit to make sure the corruption detection code in
** btreeInitPage() is executed. */
- savedIsInit = pPage->isInit;
pPage->isInit = 0;
if( (rc = btreeInitPage(pPage))!=0 ){
assert( rc==SQLITE_CORRUPT ); /* The only possible error from InitPage */
checkAppendMsg(pCheck,
"btreeInitPage() returns error code %d", rc);
+ releasePage(pPage);
+ depth = -1;
goto end_of_check;
}
- data = pPage->aData;
- hdr = pPage->hdrOffset;
-
- /* Set up for cell analysis */
- pCheck->zPfx = "On tree page %d cell %d: ";
- contentOffset = get2byteNotZero(&data[hdr+5]);
- assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
-
- /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
- ** number of cells on the page. */
- nCell = get2byte(&data[hdr+3]);
- assert( pPage->nCell==nCell );
- /* EVIDENCE-OF: R-23882-45353 The cell pointer array of a b-tree page
- ** immediately follows the b-tree page header. */
- cellStart = hdr + 12 - 4*pPage->leaf;
- assert( pPage->aCellIdx==&data[cellStart] );
- pCellIdx = &data[cellStart + 2*(nCell-1)];
-
- if( !pPage->leaf ){
- /* Analyze the right-child page of internal pages */
- pgno = get4byte(&data[hdr+8]);
-#ifndef SQLITE_OMIT_AUTOVACUUM
- if( pBt->autoVacuum ){
- pCheck->zPfx = "On page %d at right child: ";
- checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
- }
-#endif
- depth = checkTreePage(pCheck, pgno, &maxKey, maxKey);
- keyCanBeEqual = 0;
- }else{
- /* For leaf pages, the coverage check will occur in the same loop
- ** as the other cell checks, so initialize the heap. */
- heap = pCheck->heap;
- heap[0] = 0;
- }
-
- /* EVIDENCE-OF: R-02776-14802 The cell pointer array consists of K 2-byte
- ** integer offsets to the cell contents. */
- for(i=nCell-1; i>=0 && pCheck->mxErr; i--){
+ /* Check out all the cells.
+ */
+ depth = 0;
+ for(i=0; i<pPage->nCell && pCheck->mxErr; i++){
+ u8 *pCell;
+ u32 sz;
CellInfo info;
- /* Check cell size */
+ /* Check payload overflow pages
+ */
+ pCheck->zPfx = "On tree page %d cell %d: ";
+ pCheck->v1 = iPage;
pCheck->v2 = i;
- assert( pCellIdx==&data[cellStart + i*2] );
- pc = get2byteAligned(pCellIdx);
- pCellIdx -= 2;
- if( pc<contentOffset || pc>usableSize-4 ){
- checkAppendMsg(pCheck, "Offset %d out of range %d..%d",
- pc, contentOffset, usableSize-4);
- doCoverageCheck = 0;
- continue;
- }
- pCell = &data[pc];
- pPage->xParseCell(pPage, pCell, &info);
- if( pc+info.nSize>usableSize ){
- checkAppendMsg(pCheck, "Extends off end of page");
- doCoverageCheck = 0;
- continue;
- }
-
- /* Check for integer primary key out of range */
+ pCell = findCell(pPage,i);
+ btreeParseCellPtr(pPage, pCell, &info);
+ sz = info.nPayload;
+ /* For intKey pages, check that the keys are in order.
+ */
if( pPage->intKey ){
- if( keyCanBeEqual ? (info.nKey > maxKey) : (info.nKey >= maxKey) ){
- checkAppendMsg(pCheck, "Rowid %lld out of order", info.nKey);
+ if( i==0 ){
+ nMinKey = nMaxKey = info.nKey;
+ }else if( info.nKey <= nMaxKey ){
+ checkAppendMsg(pCheck,
+ "Rowid %lld out of order (previous was %lld)", info.nKey, nMaxKey);
}
- maxKey = info.nKey;
+ nMaxKey = info.nKey;
}
-
- /* Check the content overflow list */
- if( info.nPayload>info.nLocal ){
- int nPage; /* Number of pages on the overflow chain */
- Pgno pgnoOvfl; /* First page of the overflow chain */
- assert( pc + info.nSize - 4 <= usableSize );
- nPage = (info.nPayload - info.nLocal + usableSize - 5)/(usableSize - 4);
- pgnoOvfl = get4byte(&pCell[info.nSize - 4]);
+ if( (sz>info.nLocal)
+ && (&pCell[info.iOverflow]<=&pPage->aData[pBt->usableSize])
+ ){
+ int nPage = (sz - info.nLocal + usableSize - 5)/(usableSize - 4);
+ Pgno pgnoOvfl = get4byte(&pCell[info.iOverflow]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
checkPtrmap(pCheck, pgnoOvfl, PTRMAP_OVERFLOW1, iPage);
@@ -66921,57 +61737,118 @@ static int checkTreePage(
checkList(pCheck, 0, pgnoOvfl, nPage);
}
+ /* Check sanity of left child page.
+ */
if( !pPage->leaf ){
- /* Check sanity of left child page for internal pages */
pgno = get4byte(pCell);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
}
#endif
- d2 = checkTreePage(pCheck, pgno, &maxKey, maxKey);
- keyCanBeEqual = 0;
- if( d2!=depth ){
+ d2 = checkTreePage(pCheck, pgno, &nMinKey, i==0?NULL:&nMaxKey);
+ if( i>0 && d2!=depth ){
checkAppendMsg(pCheck, "Child page depth differs");
- depth = d2;
}
- }else{
- /* Populate the coverage-checking heap for leaf pages */
- btreeHeapInsert(heap, (pc<<16)|(pc+info.nSize-1));
+ depth = d2;
+ }
+ }
+
+ if( !pPage->leaf ){
+ pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
+ pCheck->zPfx = "On page %d at right child: ";
+ pCheck->v1 = iPage;
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ if( pBt->autoVacuum ){
+ checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
+ }
+#endif
+ checkTreePage(pCheck, pgno, NULL, !pPage->nCell?NULL:&nMaxKey);
+ }
+
+ /* For intKey leaf pages, check that the min/max keys are in order
+ ** with any left/parent/right pages.
+ */
+ pCheck->zPfx = "Page %d: ";
+ pCheck->v1 = iPage;
+ if( pPage->leaf && pPage->intKey ){
+ /* if we are a left child page */
+ if( pnParentMinKey ){
+ /* if we are the left most child page */
+ if( !pnParentMaxKey ){
+ if( nMaxKey > *pnParentMinKey ){
+ checkAppendMsg(pCheck,
+ "Rowid %lld out of order (max larger than parent min of %lld)",
+ nMaxKey, *pnParentMinKey);
+ }
+ }else{
+ if( nMinKey <= *pnParentMinKey ){
+ checkAppendMsg(pCheck,
+ "Rowid %lld out of order (min less than parent min of %lld)",
+ nMinKey, *pnParentMinKey);
+ }
+ if( nMaxKey > *pnParentMaxKey ){
+ checkAppendMsg(pCheck,
+ "Rowid %lld out of order (max larger than parent max of %lld)",
+ nMaxKey, *pnParentMaxKey);
+ }
+ *pnParentMinKey = nMaxKey;
+ }
+ /* else if we're a right child page */
+ } else if( pnParentMaxKey ){
+ if( nMinKey <= *pnParentMaxKey ){
+ checkAppendMsg(pCheck,
+ "Rowid %lld out of order (min less than parent max of %lld)",
+ nMinKey, *pnParentMaxKey);
+ }
}
}
- *piMinKey = maxKey;
/* Check for complete coverage of the page
*/
+ data = pPage->aData;
+ hdr = pPage->hdrOffset;
+ heap = (u32*)sqlite3PageMalloc( pBt->pageSize );
pCheck->zPfx = 0;
- if( doCoverageCheck && pCheck->mxErr>0 ){
- /* For leaf pages, the min-heap has already been initialized and the
- ** cells have already been inserted. But for internal pages, that has
- ** not yet been done, so do it now */
- if( !pPage->leaf ){
- heap = pCheck->heap;
- heap[0] = 0;
- for(i=nCell-1; i>=0; i--){
- u32 size;
- pc = get2byteAligned(&data[cellStart+i*2]);
- size = pPage->xCellSize(pPage, &data[pc]);
+ if( heap==0 ){
+ pCheck->mallocFailed = 1;
+ }else{
+ int contentOffset = get2byteNotZero(&data[hdr+5]);
+ assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
+ heap[0] = 0;
+ btreeHeapInsert(heap, contentOffset-1);
+ /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
+ ** number of cells on the page. */
+ nCell = get2byte(&data[hdr+3]);
+ /* EVIDENCE-OF: R-23882-45353 The cell pointer array of a b-tree page
+ ** immediately follows the b-tree page header. */
+ cellStart = hdr + 12 - 4*pPage->leaf;
+ /* EVIDENCE-OF: R-02776-14802 The cell pointer array consists of K 2-byte
+ ** integer offsets to the cell contents. */
+ for(i=0; i<nCell; i++){
+ int pc = get2byte(&data[cellStart+i*2]);
+ u32 size = 65536;
+ if( pc<=usableSize-4 ){
+ size = cellSizePtr(pPage, &data[pc]);
+ }
+ if( (int)(pc+size-1)>=usableSize ){
+ pCheck->zPfx = 0;
+ checkAppendMsg(pCheck,
+ "Corruption detected in cell %d on page %d",i,iPage);
+ }else{
btreeHeapInsert(heap, (pc<<16)|(pc+size-1));
}
}
- /* Add the freeblocks to the min-heap
- **
- ** EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header
+ /* EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header
** is the offset of the first freeblock, or zero if there are no
- ** freeblocks on the page.
- */
+ ** freeblocks on the page. */
i = get2byte(&data[hdr+1]);
while( i>0 ){
int size, j;
- assert( (u32)i<=usableSize-4 ); /* Enforced by btreeInitPage() */
+ assert( i<=usableSize-4 ); /* Enforced by btreeInitPage() */
size = get2byte(&data[i+2]);
- assert( (u32)(i+size)<=usableSize ); /* Enforced by btreeInitPage() */
- btreeHeapInsert(heap, (((u32)i)<<16)|(i+size-1));
+ assert( i+size<=usableSize ); /* Enforced by btreeInitPage() */
+ btreeHeapInsert(heap, (i<<16)|(i+size-1));
/* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a
** big-endian integer which is the offset in the b-tree page of the next
** freeblock in the chain, or zero if the freeblock is the last on the
@@ -66980,50 +61857,39 @@ static int checkTreePage(
/* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of
** increasing offset. */
assert( j==0 || j>i+size ); /* Enforced by btreeInitPage() */
- assert( (u32)j<=usableSize-4 ); /* Enforced by btreeInitPage() */
+ assert( j<=usableSize-4 ); /* Enforced by btreeInitPage() */
i = j;
}
- /* Analyze the min-heap looking for overlap between cells and/or
- ** freeblocks, and counting the number of untracked bytes in nFrag.
- **
- ** Each min-heap entry is of the form: (start_address<<16)|end_address.
- ** There is an implied first entry the covers the page header, the cell
- ** pointer index, and the gap between the cell pointer index and the start
- ** of cell content.
- **
- ** The loop below pulls entries from the min-heap in order and compares
- ** the start_address against the previous end_address. If there is an
- ** overlap, that means bytes are used multiple times. If there is a gap,
- ** that gap is added to the fragmentation count.
- */
- nFrag = 0;
- prev = contentOffset - 1; /* Implied first min-heap entry */
+ cnt = 0;
+ assert( heap[0]>0 );
+ assert( (heap[1]>>16)==0 );
+ btreeHeapPull(heap,&prev);
while( btreeHeapPull(heap,&x) ){
- if( (prev&0xffff)>=(x>>16) ){
+ if( (prev&0xffff)+1>(x>>16) ){
checkAppendMsg(pCheck,
"Multiple uses for byte %u of page %d", x>>16, iPage);
break;
}else{
- nFrag += (x>>16) - (prev&0xffff) - 1;
+ cnt += (x>>16) - (prev&0xffff) - 1;
prev = x;
}
}
- nFrag += usableSize - (prev&0xffff) - 1;
+ cnt += usableSize - (prev&0xffff) - 1;
/* EVIDENCE-OF: R-43263-13491 The total number of bytes in all fragments
** is stored in the fifth field of the b-tree page header.
** EVIDENCE-OF: R-07161-27322 The one-byte integer at offset 7 gives the
** number of fragmented free bytes within the cell content area.
*/
- if( heap[0]==0 && nFrag!=data[hdr+7] ){
+ if( heap[0]==0 && cnt!=data[hdr+7] ){
checkAppendMsg(pCheck,
"Fragmentation of %d bytes reported as %d on page %d",
- nFrag, data[hdr+7], iPage);
+ cnt, data[hdr+7], iPage);
}
}
+ sqlite3PageFree(heap);
+ releasePage(pPage);
end_of_check:
- if( !doCoverageCheck ) pPage->isInit = savedIsInit;
- releasePage(pPage);
pCheck->zPfx = saved_zPfx;
pCheck->v1 = saved_v1;
pCheck->v2 = saved_v2;
@@ -67053,16 +61919,14 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
int *pnErr /* Write number of errors seen to this variable */
){
Pgno i;
+ int nRef;
IntegrityCk sCheck;
BtShared *pBt = p->pBt;
- int savedDbFlags = pBt->db->flags;
char zErr[100];
- VVA_ONLY( int nRef );
sqlite3BtreeEnter(p);
assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE );
- VVA_ONLY( nRef = sqlite3PagerRefcount(pBt->pPager) );
- assert( nRef>=0 );
+ nRef = sqlite3PagerRefcount(pBt->pPager);
sCheck.pBt = pBt;
sCheck.pPager = pBt->pPager;
sCheck.nPage = btreePagecount(sCheck.pBt);
@@ -67072,27 +61936,21 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
sCheck.zPfx = 0;
sCheck.v1 = 0;
sCheck.v2 = 0;
- sCheck.aPgRef = 0;
- sCheck.heap = 0;
- sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH);
- sCheck.errMsg.printfFlags = SQLITE_PRINTF_INTERNAL;
+ *pnErr = 0;
if( sCheck.nPage==0 ){
- goto integrity_ck_cleanup;
+ sqlite3BtreeLeave(p);
+ return 0;
}
sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1);
if( !sCheck.aPgRef ){
- sCheck.mallocFailed = 1;
- goto integrity_ck_cleanup;
- }
- sCheck.heap = (u32*)sqlite3PageMalloc( pBt->pageSize );
- if( sCheck.heap==0 ){
- sCheck.mallocFailed = 1;
- goto integrity_ck_cleanup;
+ *pnErr = 1;
+ sqlite3BtreeLeave(p);
+ return 0;
}
-
i = PENDING_BYTE_PAGE(pBt);
if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i);
+ sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH);
/* Check the integrity of the freelist
*/
@@ -67103,19 +61961,17 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
/* Check all the tables.
*/
- testcase( pBt->db->flags & SQLITE_CellSizeCk );
- pBt->db->flags &= ~SQLITE_CellSizeCk;
for(i=0; (int)i<nRoot && sCheck.mxErr; i++){
- i64 notUsed;
if( aRoot[i]==0 ) continue;
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum && aRoot[i]>1 ){
checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
}
#endif
- checkTreePage(&sCheck, aRoot[i], &notUsed, LARGEST_INT64);
+ sCheck.zPfx = "List of tree roots: ";
+ checkTreePage(&sCheck, aRoot[i], NULL, NULL);
+ sCheck.zPfx = 0;
}
- pBt->db->flags = savedDbFlags;
/* Make sure every page in the file is referenced
*/
@@ -67139,20 +61995,28 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
#endif
}
+ /* Make sure this analysis did not leave any unref() pages.
+ ** This is an internal consistency check; an integrity check
+ ** of the integrity check.
+ */
+ if( NEVER(nRef != sqlite3PagerRefcount(pBt->pPager)) ){
+ checkAppendMsg(&sCheck,
+ "Outstanding page count goes from %d to %d during this analysis",
+ nRef, sqlite3PagerRefcount(pBt->pPager)
+ );
+ }
+
/* Clean up and report errors.
*/
-integrity_ck_cleanup:
- sqlite3PageFree(sCheck.heap);
+ sqlite3BtreeLeave(p);
sqlite3_free(sCheck.aPgRef);
if( sCheck.mallocFailed ){
sqlite3StrAccumReset(&sCheck.errMsg);
- sCheck.nErr++;
+ *pnErr = sCheck.nErr+1;
+ return 0;
}
*pnErr = sCheck.nErr;
if( sCheck.nErr==0 ) sqlite3StrAccumReset(&sCheck.errMsg);
- /* Make sure this analysis did not leave any unref() pages. */
- assert( nRef==sqlite3PagerRefcount(pBt->pPager) );
- sqlite3BtreeLeave(p);
return sqlite3StrAccumFinish(&sCheck.errMsg);
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -67315,7 +62179,7 @@ SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){
*/
SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
int rc;
- assert( cursorOwnsBtShared(pCsr) );
+ assert( cursorHoldsMutex(pCsr) );
assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) );
assert( pCsr->curFlags & BTCF_Incrblob );
@@ -67363,7 +62227,6 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void
*/
SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *pCur){
pCur->curFlags |= BTCF_Incrblob;
- pCur->pBtree->hasIncrblobCur = 1;
}
#endif
@@ -67404,12 +62267,22 @@ SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
}
/*
+** set the mask of hint flags for cursor pCsr.
+*/
+SQLITE_PRIVATE void sqlite3BtreeCursorHints(BtCursor *pCsr, unsigned int mask){
+ assert( mask==BTREE_BULKLOAD || mask==BTREE_SEEK_EQ || mask==0 );
+ pCsr->hints = mask;
+}
+
+#ifdef SQLITE_DEBUG
+/*
** Return true if the cursor has a hint specified. This routine is
** only used from within assert() statements
*/
SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor *pCsr, unsigned int mask){
return (pCsr->hints & mask)!=0;
}
+#endif
/*
** Return true if the given Btree is read-only.
@@ -67423,15 +62296,6 @@ SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *p){
*/
SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }
-#if !defined(SQLITE_OMIT_SHARED_CACHE)
-/*
-** Return true if the Btree passed as the only argument is sharable.
-*/
-SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){
- return p->sharable;
-}
-#endif
-
/************** End of btree.c ***********************************************/
/************** Begin file backup.c ******************************************/
/*
@@ -67448,8 +62312,6 @@ SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){
** This file contains the implementation of the sqlite3_backup_XXX()
** API functions and the related features.
*/
-/* #include "sqliteInt.h" */
-/* #include "btreeInt.h" */
/*
** Structure allocated for each backup operation.
@@ -67524,7 +62386,7 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
pParse = sqlite3StackAllocZero(pErrorDb, sizeof(*pParse));
if( pParse==0 ){
sqlite3ErrorWithMsg(pErrorDb, SQLITE_NOMEM, "out of memory");
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}else{
pParse->db = pDb;
if( sqlite3OpenTempDatabase(pParse) ){
@@ -67618,7 +62480,7 @@ SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
** sqlite3_backup_finish(). */
p = (sqlite3_backup *)sqlite3MallocZero(sizeof(sqlite3_backup));
if( !p ){
- sqlite3Error(pDestDb, SQLITE_NOMEM_BKPT);
+ sqlite3Error(pDestDb, SQLITE_NOMEM);
}
}
@@ -67729,7 +62591,7 @@ static int backupOnePage(
DbPage *pDestPg = 0;
Pgno iDest = (Pgno)(iOff/nDestPgsz)+1;
if( iDest==PENDING_BYTE_PAGE(p->pDest->pBt) ) continue;
- if( SQLITE_OK==(rc = sqlite3PagerGet(pDestPager, iDest, &pDestPg, 0))
+ if( SQLITE_OK==(rc = sqlite3PagerGet(pDestPager, iDest, &pDestPg))
&& SQLITE_OK==(rc = sqlite3PagerWrite(pDestPg))
){
const u8 *zIn = &zSrcData[iOff%nSrcPgsz];
@@ -67855,7 +62717,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
const Pgno iSrcPg = p->iNext; /* Source page number */
if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){
DbPage *pSrcPg; /* Source page object */
- rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg,PAGER_GET_READONLY);
+ rc = sqlite3PagerAcquire(pSrcPager, iSrcPg, &pSrcPg,
+ PAGER_GET_READONLY);
if( rc==SQLITE_OK ){
rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg), 0);
sqlite3PagerUnref(pSrcPg);
@@ -67955,7 +62818,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
for(iPg=nDestTruncate; rc==SQLITE_OK && iPg<=(Pgno)nDstPage; iPg++){
if( iPg!=PENDING_BYTE_PAGE(p->pDest->pBt) ){
DbPage *pPg;
- rc = sqlite3PagerGet(pDestPager, iPg, &pPg, 0);
+ rc = sqlite3PagerGet(pDestPager, iPg, &pPg);
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pPg);
sqlite3PagerUnref(pPg);
@@ -67975,7 +62838,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
){
PgHdr *pSrcPg = 0;
const Pgno iSrcPg = (Pgno)((iOff/pgszSrc)+1);
- rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg, 0);
+ rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
if( rc==SQLITE_OK ){
u8 *zData = sqlite3PagerGetData(pSrcPg);
rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
@@ -68017,7 +62880,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
}
if( rc==SQLITE_IOERR_NOMEM ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}
p->rc = rc;
}
@@ -68120,13 +62983,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p){
** corresponding to the source database is held when this function is
** called.
*/
-static SQLITE_NOINLINE void backupUpdate(
- sqlite3_backup *p,
- Pgno iPage,
- const u8 *aData
-){
- assert( p!=0 );
- do{
+SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *pBackup, Pgno iPage, const u8 *aData){
+ sqlite3_backup *p; /* Iterator variable */
+ for(p=pBackup; p; p=p->pNext){
assert( sqlite3_mutex_held(p->pSrc->pBt->mutex) );
if( !isFatalError(p->rc) && iPage<p->iNext ){
/* The backup process p has already copied page iPage. But now it
@@ -68143,10 +63002,7 @@ static SQLITE_NOINLINE void backupUpdate(
p->rc = rc;
}
}
- }while( (p = p->pNext)!=0 );
-}
-SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *pBackup, Pgno iPage, const u8 *aData){
- if( pBackup ) backupUpdate(pBackup, iPage, aData);
+ }
}
/*
@@ -68204,10 +63060,6 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
b.pDest = pTo;
b.iNext = 1;
-#ifdef SQLITE_HAS_CODEC
- sqlite3PagerAlignReserve(sqlite3BtreePager(pTo), sqlite3BtreePager(pFrom));
-#endif
-
/* 0x7FFFFFFF is the hard limit for the number of pages in a database
** file. By passing this as the number of pages to copy to
** sqlite3_backup_step(), we can guarantee that the copy finishes
@@ -68251,8 +63103,6 @@ copy_finished:
** only within the VDBE. Interface routines refer to a Mem using the
** name sqlite_value
*/
-/* #include "sqliteInt.h" */
-/* #include "vdbeInt.h" */
#ifdef SQLITE_DEBUG
/*
@@ -68352,7 +63202,6 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
assert( sqlite3VdbeCheckMemInvariants(pMem) );
assert( (pMem->flags&MEM_RowSet)==0 );
- testcase( pMem->db==0 );
/* If the bPreserve flag is set to true, then the memory cell must already
** contain a valid string or blob value. */
@@ -68374,7 +63223,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPre
sqlite3VdbeMemSetNull(pMem);
pMem->z = 0;
pMem->szMalloc = 0;
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}else{
pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
}
@@ -68432,7 +63281,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){
f = pMem->flags;
if( (f&(MEM_Str|MEM_Blob)) && (pMem->szMalloc==0 || pMem->z!=pMem->zMalloc) ){
if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
pMem->z[pMem->n] = 0;
pMem->z[pMem->n+1] = 0;
@@ -68464,7 +63313,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){
nByte = 1;
}
if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
memset(&pMem->z[pMem->n], 0, pMem->u.nZero);
@@ -68481,7 +63330,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){
*/
static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
pMem->z[pMem->n] = 0;
pMem->z[pMem->n+1] = 0;
@@ -68530,7 +63379,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
if( sqlite3VdbeMemClearAndResize(pMem, nByte) ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
/* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8
@@ -68825,7 +63674,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
if( pMem->flags & MEM_Null ) return;
switch( aff ){
- case SQLITE_AFF_BLOB: { /* Really a cast to BLOB */
+ case SQLITE_AFF_NONE: { /* Really a cast to BLOB */
if( (pMem->flags & MEM_Blob)==0 ){
sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding);
assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
@@ -68956,7 +63805,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem *pMem){
assert( db!=0 );
assert( (pMem->flags & MEM_RowSet)==0 );
sqlite3VdbeMemRelease(pMem);
- pMem->zMalloc = sqlite3DbMallocRawNN(db, 64);
+ pMem->zMalloc = sqlite3DbMallocRaw(db, 64);
if( db->mallocFailed ){
pMem->flags = MEM_Null;
pMem->szMalloc = 0;
@@ -68997,7 +63846,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){
SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
int i;
Mem *pX;
- for(i=0, pX=pVdbe->aMem; i<pVdbe->nMem; i++, pX++){
+ for(i=1, pX=&pVdbe->aMem[1]; i<=pVdbe->nMem; i++, pX++){
if( pX->pScopyFrom==pMem ){
pX->flags |= MEM_Undefined;
pX->pScopyFrom = 0;
@@ -69007,6 +63856,10 @@ SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
}
#endif /* SQLITE_DEBUG */
+/*
+** Size of struct Mem not including the Mem.zMalloc member.
+*/
+#define MEMCELLSIZE offsetof(Mem,zMalloc)
/*
** Make an shallow copy of pFrom into pTo. Prior contents of
@@ -69014,15 +63867,10 @@ SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
** pFrom->z is used, then pTo->z points to the same thing as pFrom->z
** and flags gets srcType (either MEM_Ephem or MEM_Static).
*/
-static SQLITE_NOINLINE void vdbeClrCopy(Mem *pTo, const Mem *pFrom, int eType){
- vdbeMemClearExternAndSetNull(pTo);
- assert( !VdbeMemDynamic(pTo) );
- sqlite3VdbeMemShallowCopy(pTo, pFrom, eType);
-}
SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
assert( (pFrom->flags & MEM_RowSet)==0 );
assert( pTo->db==pFrom->db );
- if( VdbeMemDynamic(pTo) ){ vdbeClrCopy(pTo,pFrom,srcType); return; }
+ if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo);
memcpy(pTo, pFrom, MEMCELLSIZE);
if( (pFrom->flags&MEM_Static)==0 ){
pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem);
@@ -69038,6 +63886,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int sr
SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
int rc = SQLITE_OK;
+ assert( pTo->db==pFrom->db );
assert( (pFrom->flags & MEM_RowSet)==0 );
if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo);
memcpy(pTo, pFrom, MEMCELLSIZE);
@@ -69137,7 +63986,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
testcase( nAlloc==31 );
testcase( nAlloc==32 );
if( sqlite3VdbeMemClearAndResize(pMem, MAX(nAlloc,32)) ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
memcpy(pMem->z, z, nAlloc);
}else if( xDel==SQLITE_DYNAMIC ){
@@ -69157,7 +64006,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
#ifndef SQLITE_OMIT_UTF16
if( pMem->enc!=SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
#endif
@@ -69184,32 +64033,6 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
** If this routine fails for any reason (malloc returns NULL or unable
** to read from the disk) then the pMem is left in an inconsistent state.
*/
-static SQLITE_NOINLINE int vdbeMemFromBtreeResize(
- BtCursor *pCur, /* Cursor pointing at record to retrieve. */
- u32 offset, /* Offset from the start of data to return bytes from. */
- u32 amt, /* Number of bytes to return. */
- int key, /* If true, retrieve from the btree key, not data. */
- Mem *pMem /* OUT: Return data in this Mem structure. */
-){
- int rc;
- pMem->flags = MEM_Null;
- if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){
- if( key ){
- rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
- }else{
- rc = sqlite3BtreeData(pCur, offset, amt, pMem->z);
- }
- if( rc==SQLITE_OK ){
- pMem->z[amt] = 0;
- pMem->z[amt+1] = 0;
- pMem->flags = MEM_Blob|MEM_Term;
- pMem->n = (int)amt;
- }else{
- sqlite3VdbeMemRelease(pMem);
- }
- }
- return rc;
-}
SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
BtCursor *pCur, /* Cursor pointing at record to retrieve. */
u32 offset, /* Offset from the start of data to return bytes from. */
@@ -69239,7 +64062,22 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
pMem->flags = MEM_Blob|MEM_Ephem;
pMem->n = (int)amt;
}else{
- rc = vdbeMemFromBtreeResize(pCur, offset, amt, key, pMem);
+ pMem->flags = MEM_Null;
+ if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){
+ if( key ){
+ rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
+ }else{
+ rc = sqlite3BtreeData(pCur, offset, amt, pMem->z);
+ }
+ if( rc==SQLITE_OK ){
+ pMem->z[amt] = 0;
+ pMem->z[amt+1] = 0;
+ pMem->flags = MEM_Blob|MEM_Term;
+ pMem->n = (int)amt;
+ }else{
+ sqlite3VdbeMemRelease(pMem);
+ }
+ }
}
return rc;
@@ -69388,7 +64226,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
** to be a scalar SQL function. If
**
** * all function arguments are SQL literals,
-** * one of the SQLITE_FUNC_CONSTANT or _SLOCHNG function flags is set, and
+** * the SQLITE_FUNC_CONSTANT function flag is set, and
** * the SQLITE_FUNC_NEEDCOLL function flag is not set,
**
** then this routine attempts to invoke the SQL function. Assuming no
@@ -69418,6 +64256,7 @@ static int valueFromFunction(
FuncDef *pFunc = 0; /* Function definition */
sqlite3_value *pVal = 0; /* New value */
int rc = SQLITE_OK; /* Return code */
+ int nName; /* Size of function name in bytes */
ExprList *pList = 0; /* Function arguments */
int i; /* Iterator variable */
@@ -69425,9 +64264,10 @@ static int valueFromFunction(
assert( (p->flags & EP_TokenOnly)==0 );
pList = p->x.pList;
if( pList ) nVal = pList->nExpr;
- pFunc = sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0);
+ nName = sqlite3Strlen30(p->u.zToken);
+ pFunc = sqlite3FindFunction(db, p->u.zToken, nName, nVal, enc, 0);
assert( pFunc );
- if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
+ if( (pFunc->funcFlags & SQLITE_FUNC_CONSTANT)==0
|| (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
){
return SQLITE_OK;
@@ -69436,7 +64276,7 @@ static int valueFromFunction(
if( pList ){
apVal = (sqlite3_value**)sqlite3DbMallocZero(db, sizeof(apVal[0]) * nVal);
if( apVal==0 ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
goto value_from_function_out;
}
for(i=0; i<nVal; i++){
@@ -69447,7 +64287,7 @@ static int valueFromFunction(
pVal = valueNew(db, pCtx);
if( pVal==0 ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
goto value_from_function_out;
}
@@ -69455,7 +64295,7 @@ static int valueFromFunction(
memset(&ctx, 0, sizeof(ctx));
ctx.pOut = pVal;
ctx.pFunc = pFunc;
- pFunc->xSFunc(&ctx, nVal, apVal);
+ pFunc->xFunc(&ctx, nVal, apVal);
if( ctx.isError ){
rc = ctx.isError;
sqlite3ErrorMsg(pCtx->pParse, "%s", sqlite3_value_text(pVal));
@@ -69517,7 +64357,7 @@ static int valueFromExpr(
*ppVal = 0;
return SQLITE_OK;
}
- while( (op = pExpr->op)==TK_UPLUS || op==TK_SPAN ) pExpr = pExpr->pLeft;
+ while( (op = pExpr->op)==TK_UPLUS ) pExpr = pExpr->pLeft;
if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
/* Compressed expressions only appear when parsing the DEFAULT clause
@@ -69558,7 +64398,7 @@ static int valueFromExpr(
if( zVal==0 ) goto no_mem;
sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
}
- if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_BLOB ){
+ if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){
sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8);
}else{
sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8);
@@ -69612,7 +64452,7 @@ static int valueFromExpr(
return rc;
no_mem:
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
sqlite3DbFree(db, zVal);
assert( *ppVal==0 );
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
@@ -69620,7 +64460,7 @@ no_mem:
#else
assert( pCtx==0 ); sqlite3ValueFree(pVal);
#endif
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
/*
@@ -69658,20 +64498,21 @@ static void recordFunc(
sqlite3_value **argv
){
const int file_format = 1;
- u32 iSerial; /* Serial type */
+ int iSerial; /* Serial type */
int nSerial; /* Bytes of space for iSerial as varint */
- u32 nVal; /* Bytes of space required for argv[0] */
+ int nVal; /* Bytes of space required for argv[0] */
int nRet;
sqlite3 *db;
u8 *aRet;
UNUSED_PARAMETER( argc );
- iSerial = sqlite3VdbeSerialType(argv[0], file_format, &nVal);
+ iSerial = sqlite3VdbeSerialType(argv[0], file_format);
nSerial = sqlite3VarintLen(iSerial);
+ nVal = sqlite3VdbeSerialTypeLen(iSerial);
db = sqlite3_context_db_handle(context);
nRet = 1 + nSerial + nVal;
- aRet = sqlite3DbMallocRawNN(db, nRet);
+ aRet = sqlite3DbMallocRaw(db, nRet);
if( aRet==0 ){
sqlite3_result_error_nomem(context);
}else{
@@ -69687,10 +64528,15 @@ static void recordFunc(
** Register built-in functions used to help read ANALYZE data.
*/
SQLITE_PRIVATE void sqlite3AnalyzeFunctions(void){
- static FuncDef aAnalyzeTableFuncs[] = {
+ static SQLITE_WSD FuncDef aAnalyzeTableFuncs[] = {
FUNCTION(sqlite_record, 1, 0, 0, recordFunc),
};
- sqlite3InsertBuiltinFuncs(aAnalyzeTableFuncs, ArraySize(aAnalyzeTableFuncs));
+ int i;
+ FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
+ FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAnalyzeTableFuncs);
+ for(i=0; i<ArraySize(aAnalyzeTableFuncs); i++){
+ sqlite3FuncDefInsert(pHash, &aFunc[i]);
+ }
}
/*
@@ -69869,7 +64715,7 @@ SQLITE_PRIVATE int sqlite3Stat4Column(
if( iField>nRec ) return SQLITE_CORRUPT_BKPT;
if( pMem==0 ){
pMem = *ppVal = sqlite3ValueNew(db);
- if( pMem==0 ) return SQLITE_NOMEM_BKPT;
+ if( pMem==0 ) return SQLITE_NOMEM;
}
sqlite3VdbeSerialGet(&a[iField-szField], t, pMem);
pMem->enc = ENC(db);
@@ -69919,28 +64765,19 @@ SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value *v){
}
/*
-** The sqlite3ValueBytes() routine returns the number of bytes in the
-** sqlite3_value object assuming that it uses the encoding "enc".
-** The valueBytes() routine is a helper function.
+** Return the number of bytes in the sqlite3_value object assuming
+** that it uses the encoding "enc"
*/
-static SQLITE_NOINLINE int valueBytes(sqlite3_value *pVal, u8 enc){
- return valueToText(pVal, enc)!=0 ? pVal->n : 0;
-}
SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
Mem *p = (Mem*)pVal;
- assert( (p->flags & MEM_Null)==0 || (p->flags & (MEM_Str|MEM_Blob))==0 );
- if( (p->flags & MEM_Str)!=0 && pVal->enc==enc ){
- return p->n;
- }
- if( (p->flags & MEM_Blob)!=0 ){
+ if( (p->flags & MEM_Blob)!=0 || sqlite3ValueText(pVal, enc) ){
if( p->flags & MEM_Zero ){
return p->n + p->u.nZero;
}else{
return p->n;
}
}
- if( p->flags & MEM_Null ) return 0;
- return valueBytes(pVal, enc);
+ return 0;
}
/************** End of vdbemem.c *********************************************/
@@ -69959,8 +64796,6 @@ SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
** This file contains code used for creating, destroying, and populating
** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.)
*/
-/* #include "sqliteInt.h" */
-/* #include "vdbeInt.h" */
/*
** Create a new virtual database engine.
@@ -69982,22 +64817,10 @@ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){
assert( pParse->aLabel==0 );
assert( pParse->nLabel==0 );
assert( pParse->nOpAlloc==0 );
- assert( pParse->szOpAlloc==0 );
return p;
}
/*
-** Change the error string stored in Vdbe.zErrMsg
-*/
-SQLITE_PRIVATE void sqlite3VdbeError(Vdbe *p, const char *zFormat, ...){
- va_list ap;
- sqlite3DbFree(p->db, p->zErrMsg);
- va_start(ap, zFormat);
- p->zErrMsg = sqlite3VMPrintf(p->db, zFormat, ap);
- va_end(ap);
-}
-
-/*
** Remember the SQL string for a prepared statement.
*/
SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
@@ -70016,7 +64839,7 @@ SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepa
*/
SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe *)pStmt;
- return p ? p->zSql : 0;
+ return (p && p->isPrepareV2) ? p->zSql : 0;
}
/*
@@ -70025,7 +64848,6 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt){
SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
Vdbe tmp, *pTmp;
char *zTmp;
- assert( pA->db==pB->db );
tmp = *pA;
*pA = *pB;
*pB = tmp;
@@ -70073,11 +64895,10 @@ static int growOpArray(Vdbe *v, int nOp){
assert( nNew>=(p->nOpAlloc+nOp) );
pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op));
if( pNew ){
- p->szOpAlloc = sqlite3DbMallocSize(p->db, pNew);
- p->nOpAlloc = p->szOpAlloc/sizeof(Op);
+ p->nOpAlloc = sqlite3DbMallocSize(p->db, pNew)/sizeof(Op);
v->aOp = pNew;
}
- return (pNew ? SQLITE_OK : SQLITE_NOMEM_BKPT);
+ return (pNew ? SQLITE_OK : SQLITE_NOMEM);
}
#ifdef SQLITE_DEBUG
@@ -70107,21 +64928,17 @@ static void test_addop_breakpoint(void){
** the sqlite3VdbeChangeP4() function to change the value of the P4
** operand.
*/
-static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){
- assert( p->pParse->nOpAlloc<=p->nOp );
- if( growOpArray(p, 1) ) return 1;
- assert( p->pParse->nOpAlloc>p->nOp );
- return sqlite3VdbeAddOp3(p, op, p1, p2, p3);
-}
SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
int i;
VdbeOp *pOp;
i = p->nOp;
assert( p->magic==VDBE_MAGIC_INIT );
- assert( op>=0 && op<0xff );
+ assert( op>0 && op<0xff );
if( p->pParse->nOpAlloc<=i ){
- return growOp3(p, op, p1, p2, p3);
+ if( growOpArray(p, 1) ){
+ return 1;
+ }
}
p->nOp++;
pOp = &p->aOp[i];
@@ -70169,43 +64986,6 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe *p, int op, int p1, int p2){
return sqlite3VdbeAddOp3(p, op, p1, p2, 0);
}
-/* Generate code for an unconditional jump to instruction iDest
-*/
-SQLITE_PRIVATE int sqlite3VdbeGoto(Vdbe *p, int iDest){
- return sqlite3VdbeAddOp3(p, OP_Goto, 0, iDest, 0);
-}
-
-/* Generate code to cause the string zStr to be loaded into
-** register iDest
-*/
-SQLITE_PRIVATE int sqlite3VdbeLoadString(Vdbe *p, int iDest, const char *zStr){
- return sqlite3VdbeAddOp4(p, OP_String8, 0, iDest, 0, zStr, 0);
-}
-
-/*
-** Generate code that initializes multiple registers to string or integer
-** constants. The registers begin with iDest and increase consecutively.
-** One register is initialized for each characgter in zTypes[]. For each
-** "s" character in zTypes[], the register is a string if the argument is
-** not NULL, or OP_Null if the value is a null pointer. For each "i" character
-** in zTypes[], the register is initialized to an integer.
-*/
-SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe *p, int iDest, const char *zTypes, ...){
- va_list ap;
- int i;
- char c;
- va_start(ap, zTypes);
- for(i=0; (c = zTypes[i])!=0; i++){
- if( c=='s' ){
- const char *z = va_arg(ap, const char*);
- sqlite3VdbeAddOp4(p, z==0 ? OP_Null : OP_String8, 0, iDest++, 0, z, 0);
- }else{
- assert( c=='i' );
- sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest++);
- }
- }
- va_end(ap);
-}
/*
** Add an opcode that includes the p4 value as a pointer.
@@ -70225,24 +65005,6 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4(
}
/*
-** Add an opcode that includes the p4 value with a P4_INT64 or
-** P4_REAL type.
-*/
-SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(
- Vdbe *p, /* Add the opcode to this VM */
- int op, /* The new opcode */
- int p1, /* The P1 operand */
- int p2, /* The P2 operand */
- int p3, /* The P3 operand */
- const u8 *zP4, /* The P4 operand */
- int p4type /* P4 operand type */
-){
- char *p4copy = sqlite3DbMallocRawNN(sqlite3VdbeDb(p), 8);
- if( p4copy ) memcpy(p4copy, zP4, 8);
- return sqlite3VdbeAddOp4(p, op, p1, p2, p3, p4copy, p4type);
-}
-
-/*
** Add an OP_ParseSchema opcode. This routine is broken out from
** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees
** as having been used.
@@ -70252,7 +65014,8 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(
*/
SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){
int j;
- sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
+ int addr = sqlite3VdbeAddOp3(p, OP_ParseSchema, iDb, 0, 0);
+ sqlite3VdbeChangeP4(p, addr, zWhere, P4_DYNAMIC);
for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
}
@@ -70272,21 +65035,6 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(
return addr;
}
-/* Insert the end of a co-routine
-*/
-SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe *v, int regYield){
- sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
-
- /* Clear the temporary register cache, thereby ensuring that each
- ** co-routine has its own independent set of registers, because co-routines
- ** might expect their registers to be preserved across an OP_Yield, and
- ** that could cause problems if two or more co-routines are using the same
- ** temporary register.
- */
- v->pParse->nTempReg = 0;
- v->pParse->nRangeReg = 0;
-}
-
/*
** Create a new symbolic label for an instruction that has yet to be
** coded. The symbolic label is really just a negative number. The
@@ -70312,7 +65060,7 @@ SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *v){
if( p->aLabel ){
p->aLabel[i] = -1;
}
- return ADDR(i);
+ return -1-i;
}
/*
@@ -70322,11 +65070,10 @@ SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *v){
*/
SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){
Parse *p = v->pParse;
- int j = ADDR(x);
+ int j = -1-x;
assert( v->magic==VDBE_MAGIC_INIT );
assert( j<p->nLabel );
- assert( j>=0 );
- if( p->aLabel ){
+ if( ALWAYS(j>=0) && p->aLabel ){
p->aLabel[j] = v->nOp;
}
p->iFixedOp = v->nOp - 1;
@@ -70339,13 +65086,6 @@ SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe *p){
p->runOnlyOnce = 1;
}
-/*
-** Mark the VDBE as one that can only be run multiple times.
-*/
-SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe *p){
- p->runOnlyOnce = 0;
-}
-
#ifdef SQLITE_DEBUG /* sqlite3AssertMayAbort() logic */
/*
@@ -70428,7 +65168,6 @@ static Op *opIterNext(VdbeOpIter *p){
** * OP_VUpdate
** * OP_VRename
** * OP_FkCounter with P2==0 (immediate foreign key constraint)
-** * OP_CreateTable and OP_InitCoroutine (for CREATE TABLE AS SELECT ...)
**
** Then check that the value of Parse.mayAbort is true if an
** ABORT may be thrown, or false otherwise. Return true if it does
@@ -70440,8 +65179,6 @@ static Op *opIterNext(VdbeOpIter *p){
SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
int hasAbort = 0;
int hasFkCounter = 0;
- int hasCreateTable = 0;
- int hasInitCoroutine = 0;
Op *pOp;
VdbeOpIter sIter;
memset(&sIter, 0, sizeof(sIter));
@@ -70456,8 +65193,6 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
hasAbort = 1;
break;
}
- if( opcode==OP_CreateTable ) hasCreateTable = 1;
- if( opcode==OP_InitCoroutine ) hasInitCoroutine = 1;
#ifndef SQLITE_OMIT_FOREIGN_KEY
if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){
hasFkCounter = 1;
@@ -70471,105 +65206,94 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
** through all opcodes and hasAbort may be set incorrectly. Return
** true for this case to prevent the assert() in the callers frame
** from failing. */
- return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter
- || (hasCreateTable && hasInitCoroutine) );
+ return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter );
}
#endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */
/*
-** This routine is called after all opcodes have been inserted. It loops
-** through all the opcodes and fixes up some details.
-**
-** (1) For each jump instruction with a negative P2 value (a label)
-** resolve the P2 value to an actual address.
+** Loop through the program looking for P2 values that are negative
+** on jump instructions. Each such value is a label. Resolve the
+** label by setting the P2 value to its correct non-zero value.
**
-** (2) Compute the maximum number of arguments used by any SQL function
-** and store that value in *pMaxFuncArgs.
+** This routine is called once after all opcodes have been inserted.
**
-** (3) Update the Vdbe.readOnly and Vdbe.bIsReader flags to accurately
-** indicate what the prepared statement actually does.
+** Variable *pMaxFuncArgs is set to the maximum value of any P2 argument
+** to an OP_Function, OP_AggStep or OP_VFilter opcode. This is used by
+** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array.
**
-** (4) Initialize the p4.xAdvance pointer on opcodes that use it.
-**
-** (5) Reclaim the memory allocated for storing labels.
-**
-** This routine will only function correctly if the mkopcodeh.tcl generator
-** script numbers the opcodes correctly. Changes to this routine must be
-** coordinated with changes to mkopcodeh.tcl.
+** The Op.opflags field is set on all opcodes.
*/
static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
+ int i;
int nMaxArgs = *pMaxFuncArgs;
Op *pOp;
Parse *pParse = p->pParse;
int *aLabel = pParse->aLabel;
p->readOnly = 1;
p->bIsReader = 0;
- pOp = &p->aOp[p->nOp-1];
- while(1){
-
- /* Only JUMP opcodes and the short list of special opcodes in the switch
- ** below need to be considered. The mkopcodeh.tcl generator script groups
- ** all these opcodes together near the front of the opcode list. Skip
- ** any opcode that does not need processing by virtual of the fact that
- ** it is larger than SQLITE_MX_JUMP_OPCODE, as a performance optimization.
- */
- if( pOp->opcode<=SQLITE_MX_JUMP_OPCODE ){
- /* NOTE: Be sure to update mkopcodeh.tcl when adding or removing
- ** cases from this switch! */
- switch( pOp->opcode ){
- case OP_Transaction: {
- if( pOp->p2!=0 ) p->readOnly = 0;
- /* fall thru */
- }
- case OP_AutoCommit:
- case OP_Savepoint: {
- p->bIsReader = 1;
- break;
- }
+ for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){
+ u8 opcode = pOp->opcode;
+
+ /* NOTE: Be sure to update mkopcodeh.awk when adding or removing
+ ** cases from this switch! */
+ switch( opcode ){
+ case OP_Function:
+ case OP_AggStep: {
+ if( pOp->p5>nMaxArgs ) nMaxArgs = pOp->p5;
+ break;
+ }
+ case OP_Transaction: {
+ if( pOp->p2!=0 ) p->readOnly = 0;
+ /* fall thru */
+ }
+ case OP_AutoCommit:
+ case OP_Savepoint: {
+ p->bIsReader = 1;
+ break;
+ }
#ifndef SQLITE_OMIT_WAL
- case OP_Checkpoint:
+ case OP_Checkpoint:
#endif
- case OP_Vacuum:
- case OP_JournalMode: {
- p->readOnly = 0;
- p->bIsReader = 1;
- break;
- }
+ case OP_Vacuum:
+ case OP_JournalMode: {
+ p->readOnly = 0;
+ p->bIsReader = 1;
+ break;
+ }
#ifndef SQLITE_OMIT_VIRTUALTABLE
- case OP_VUpdate: {
- if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
- break;
- }
- case OP_VFilter: {
- int n;
- assert( (pOp - p->aOp) >= 3 );
- assert( pOp[-1].opcode==OP_Integer );
- n = pOp[-1].p1;
- if( n>nMaxArgs ) nMaxArgs = n;
- break;
- }
+ case OP_VUpdate: {
+ if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
+ break;
+ }
+ case OP_VFilter: {
+ int n;
+ assert( p->nOp - i >= 3 );
+ assert( pOp[-1].opcode==OP_Integer );
+ n = pOp[-1].p1;
+ if( n>nMaxArgs ) nMaxArgs = n;
+ break;
+ }
#endif
- case OP_Next:
- case OP_NextIfOpen:
- case OP_SorterNext: {
- pOp->p4.xAdvance = sqlite3BtreeNext;
- pOp->p4type = P4_ADVANCE;
- break;
- }
- case OP_Prev:
- case OP_PrevIfOpen: {
- pOp->p4.xAdvance = sqlite3BtreePrevious;
- pOp->p4type = P4_ADVANCE;
- break;
- }
+ case OP_Next:
+ case OP_NextIfOpen:
+ case OP_SorterNext: {
+ pOp->p4.xAdvance = sqlite3BtreeNext;
+ pOp->p4type = P4_ADVANCE;
+ break;
}
- if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 && pOp->p2<0 ){
- assert( ADDR(pOp->p2)<pParse->nLabel );
- pOp->p2 = aLabel[ADDR(pOp->p2)];
+ case OP_Prev:
+ case OP_PrevIfOpen: {
+ pOp->p4.xAdvance = sqlite3BtreePrevious;
+ pOp->p4type = P4_ADVANCE;
+ break;
}
}
- if( pOp==p->aOp ) break;
- pOp--;
+
+ pOp->opflags = sqlite3OpcodeProperty[opcode];
+ if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){
+ assert( -1-pOp->p2<pParse->nLabel );
+ pOp->p2 = aLabel[-1-pOp->p2];
+ }
}
sqlite3DbFree(p->db, pParse->aLabel);
pParse->aLabel = 0;
@@ -70587,20 +65311,6 @@ SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){
}
/*
-** Verify that at least N opcode slots are available in p without
-** having to malloc for more space (except when compiled using
-** SQLITE_TEST_REALLOC_STRESS). This interface is used during testing
-** to verify that certain calls to sqlite3VdbeAddOpList() can never
-** fail due to a OOM fault and hence that the return value from
-** sqlite3VdbeAddOpList() will always be non-NULL.
-*/
-#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
-SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N){
- assert( p->nOp + N <= p->pParse->nOpAlloc );
-}
-#endif
-
-/*
** This function returns a pointer to the array of opcodes associated with
** the Vdbe passed as the first argument. It is the callers responsibility
** to arrange for the returned array to be eventually freed using the
@@ -70625,54 +65335,51 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg)
}
/*
-** Add a whole list of operations to the operation stack. Return a
-** pointer to the first operation inserted.
-**
-** Non-zero P2 arguments to jump instructions are automatically adjusted
-** so that the jump target is relative to the first operation inserted.
+** Add a whole list of operations to the operation stack. Return the
+** address of the first operation added.
*/
-SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(
- Vdbe *p, /* Add opcodes to the prepared statement */
- int nOp, /* Number of opcodes to add */
- VdbeOpList const *aOp, /* The opcodes to be added */
- int iLineno /* Source-file line number of first opcode */
-){
- int i;
- VdbeOp *pOut, *pFirst;
- assert( nOp>0 );
+SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){
+ int addr;
assert( p->magic==VDBE_MAGIC_INIT );
if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p, nOp) ){
return 0;
}
- pFirst = pOut = &p->aOp[p->nOp];
- for(i=0; i<nOp; i++, aOp++, pOut++){
- pOut->opcode = aOp->opcode;
- pOut->p1 = aOp->p1;
- pOut->p2 = aOp->p2;
- assert( aOp->p2>=0 );
- if( (sqlite3OpcodeProperty[aOp->opcode] & OPFLG_JUMP)!=0 && aOp->p2>0 ){
- pOut->p2 += p->nOp;
- }
- pOut->p3 = aOp->p3;
- pOut->p4type = P4_NOTUSED;
- pOut->p4.p = 0;
- pOut->p5 = 0;
+ addr = p->nOp;
+ if( ALWAYS(nOp>0) ){
+ int i;
+ VdbeOpList const *pIn = aOp;
+ for(i=0; i<nOp; i++, pIn++){
+ int p2 = pIn->p2;
+ VdbeOp *pOut = &p->aOp[i+addr];
+ pOut->opcode = pIn->opcode;
+ pOut->p1 = pIn->p1;
+ if( p2<0 ){
+ assert( sqlite3OpcodeProperty[pOut->opcode] & OPFLG_JUMP );
+ pOut->p2 = addr + ADDR(p2);
+ }else{
+ pOut->p2 = p2;
+ }
+ pOut->p3 = pIn->p3;
+ pOut->p4type = P4_NOTUSED;
+ pOut->p4.p = 0;
+ pOut->p5 = 0;
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
- pOut->zComment = 0;
+ pOut->zComment = 0;
#endif
#ifdef SQLITE_VDBE_COVERAGE
- pOut->iSrcLine = iLineno+i;
+ pOut->iSrcLine = iLineno+i;
#else
- (void)iLineno;
+ (void)iLineno;
#endif
#ifdef SQLITE_DEBUG
- if( p->db->flags & SQLITE_VdbeAddopTrace ){
- sqlite3VdbePrintOp(0, i+p->nOp, &p->aOp[i+p->nOp]);
- }
+ if( p->db->flags & SQLITE_VdbeAddopTrace ){
+ sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
+ }
#endif
+ }
+ p->nOp += nOp;
}
- p->nOp += nOp;
- return pFirst;
+ return addr;
}
#if defined(SQLITE_ENABLE_STMT_SCANSTATUS)
@@ -70704,23 +65411,49 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(
/*
-** Change the value of the opcode, or P1, P2, P3, or P5 operands
-** for a specific instruction.
+** Change the value of the P1 operand for a specific instruction.
+** This routine is useful when a large program is loaded from a
+** static array using sqlite3VdbeAddOpList but we want to make a
+** few minor changes to the program.
*/
-SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe *p, u32 addr, u8 iNewOpcode){
- sqlite3VdbeGetOp(p,addr)->opcode = iNewOpcode;
-}
SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe *p, u32 addr, int val){
- sqlite3VdbeGetOp(p,addr)->p1 = val;
+ assert( p!=0 );
+ if( ((u32)p->nOp)>addr ){
+ p->aOp[addr].p1 = val;
+ }
}
+
+/*
+** Change the value of the P2 operand for a specific instruction.
+** This routine is useful for setting a jump destination.
+*/
SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, u32 addr, int val){
- sqlite3VdbeGetOp(p,addr)->p2 = val;
+ assert( p!=0 );
+ if( ((u32)p->nOp)>addr ){
+ p->aOp[addr].p2 = val;
+ }
}
+
+/*
+** Change the value of the P3 operand for a specific instruction.
+*/
SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){
- sqlite3VdbeGetOp(p,addr)->p3 = val;
+ assert( p!=0 );
+ if( ((u32)p->nOp)>addr ){
+ p->aOp[addr].p3 = val;
+ }
}
-SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){
- if( !p->db->mallocFailed ) p->aOp[p->nOp-1].p5 = p5;
+
+/*
+** Change the value of the P5 operand for the most recently
+** added operation.
+*/
+SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 val){
+ assert( p!=0 );
+ if( p->aOp ){
+ assert( p->nOp>0 );
+ p->aOp[p->nOp-1].p5 = val;
+ }
}
/*
@@ -70728,8 +65461,8 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){
** the address of the next instruction to be coded.
*/
SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){
- p->pParse->iFixedOp = p->nOp - 1;
sqlite3VdbeChangeP2(p, addr, p->nOp);
+ p->pParse->iFixedOp = p->nOp - 1;
}
@@ -70749,50 +65482,42 @@ static void vdbeFreeOpArray(sqlite3 *, Op *, int);
** Delete a P4 value if necessary.
*/
static void freeP4(sqlite3 *db, int p4type, void *p4){
- assert( db );
- switch( p4type ){
- case P4_FUNCCTX: {
- freeEphemeralFunction(db, ((sqlite3_context*)p4)->pFunc);
- /* Fall through into the next case */
- }
- case P4_REAL:
- case P4_INT64:
- case P4_DYNAMIC:
- case P4_INTARRAY: {
- sqlite3DbFree(db, p4);
- break;
- }
- case P4_KEYINFO: {
- if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4);
- break;
- }
-#ifdef SQLITE_ENABLE_CURSOR_HINTS
- case P4_EXPR: {
- sqlite3ExprDelete(db, (Expr*)p4);
- break;
- }
-#endif
- case P4_MPRINTF: {
- if( db->pnBytesFreed==0 ) sqlite3_free(p4);
- break;
- }
- case P4_FUNCDEF: {
- freeEphemeralFunction(db, (FuncDef*)p4);
- break;
- }
- case P4_MEM: {
- if( db->pnBytesFreed==0 ){
- sqlite3ValueFree((sqlite3_value*)p4);
- }else{
- Mem *p = (Mem*)p4;
- if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
- sqlite3DbFree(db, p);
+ if( p4 ){
+ assert( db );
+ switch( p4type ){
+ case P4_REAL:
+ case P4_INT64:
+ case P4_DYNAMIC:
+ case P4_INTARRAY: {
+ sqlite3DbFree(db, p4);
+ break;
+ }
+ case P4_KEYINFO: {
+ if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4);
+ break;
+ }
+ case P4_MPRINTF: {
+ if( db->pnBytesFreed==0 ) sqlite3_free(p4);
+ break;
+ }
+ case P4_FUNCDEF: {
+ freeEphemeralFunction(db, (FuncDef*)p4);
+ break;
+ }
+ case P4_MEM: {
+ if( db->pnBytesFreed==0 ){
+ sqlite3ValueFree((sqlite3_value*)p4);
+ }else{
+ Mem *p = (Mem*)p4;
+ if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
+ sqlite3DbFree(db, p);
+ }
+ break;
+ }
+ case P4_VTAB : {
+ if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4);
+ break;
}
- break;
- }
- case P4_VTAB : {
- if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4);
- break;
}
}
}
@@ -70806,7 +65531,7 @@ static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
if( aOp ){
Op *pOp;
for(pOp=aOp; pOp<&aOp[nOp]; pOp++){
- if( pOp->p4type ) freeP4(db, pOp->p4type, pOp->p4.p);
+ freeP4(db, pOp->p4type, pOp->p4.p);
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
sqlite3DbFree(db, pOp->zComment);
#endif
@@ -70828,16 +65553,15 @@ SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){
/*
** Change the opcode at addr into OP_Noop
*/
-SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
- VdbeOp *pOp;
- if( p->db->mallocFailed ) return 0;
- assert( addr>=0 && addr<p->nOp );
- pOp = &p->aOp[addr];
- freeP4(p->db, pOp->p4type, pOp->p4.p);
- pOp->p4type = P4_NOTUSED;
- pOp->p4.z = 0;
- pOp->opcode = OP_Noop;
- return 1;
+SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
+ if( addr<p->nOp ){
+ VdbeOp *pOp = &p->aOp[addr];
+ sqlite3 *db = p->db;
+ freeP4(db, pOp->p4type, pOp->p4.p);
+ memset(pOp, 0, sizeof(pOp[0]));
+ pOp->opcode = OP_Noop;
+ if( addr==p->nOp-1 ) p->nOp--;
+ }
}
/*
@@ -70846,7 +65570,8 @@ SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
*/
SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){
if( (p->nOp-1)>(p->pParse->iFixedOp) && p->aOp[p->nOp-1].opcode==op ){
- return sqlite3VdbeChangeToNoop(p, p->nOp-1);
+ sqlite3VdbeChangeToNoop(p, p->nOp-1);
+ return 1;
}else{
return 0;
}
@@ -70869,34 +65594,16 @@ SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){
**
** If addr<0 then change P4 on the most recently inserted instruction.
*/
-static void SQLITE_NOINLINE vdbeChangeP4Full(
- Vdbe *p,
- Op *pOp,
- const char *zP4,
- int n
-){
- if( pOp->p4type ){
- freeP4(p->db, pOp->p4type, pOp->p4.p);
- pOp->p4type = 0;
- pOp->p4.p = 0;
- }
- if( n<0 ){
- sqlite3VdbeChangeP4(p, (int)(pOp - p->aOp), zP4, n);
- }else{
- if( n==0 ) n = sqlite3Strlen30(zP4);
- pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n);
- pOp->p4type = P4_DYNAMIC;
- }
-}
SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
Op *pOp;
sqlite3 *db;
assert( p!=0 );
db = p->db;
assert( p->magic==VDBE_MAGIC_INIT );
- assert( p->aOp!=0 || db->mallocFailed );
- if( db->mallocFailed ){
- if( n!=P4_VTAB ) freeP4(db, n, (void*)*(char**)&zP4);
+ if( p->aOp==0 || db->mallocFailed ){
+ if( n!=P4_VTAB ){
+ freeP4(db, n, (void*)*(char**)&zP4);
+ }
return;
}
assert( p->nOp>0 );
@@ -70905,20 +65612,34 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int
addr = p->nOp - 1;
}
pOp = &p->aOp[addr];
- if( n>=0 || pOp->p4type ){
- vdbeChangeP4Full(p, pOp, zP4, n);
- return;
- }
+ assert( pOp->p4type==P4_NOTUSED
+ || pOp->p4type==P4_INT32
+ || pOp->p4type==P4_KEYINFO );
+ freeP4(db, pOp->p4type, pOp->p4.p);
+ pOp->p4.p = 0;
if( n==P4_INT32 ){
/* Note: this cast is safe, because the origin data point was an int
** that was cast to a (const char *). */
pOp->p4.i = SQLITE_PTR_TO_INT(zP4);
pOp->p4type = P4_INT32;
- }else if( zP4!=0 ){
- assert( n<0 );
+ }else if( zP4==0 ){
+ pOp->p4.p = 0;
+ pOp->p4type = P4_NOTUSED;
+ }else if( n==P4_KEYINFO ){
+ pOp->p4.p = (void*)zP4;
+ pOp->p4type = P4_KEYINFO;
+ }else if( n==P4_VTAB ){
+ pOp->p4.p = (void*)zP4;
+ pOp->p4type = P4_VTAB;
+ sqlite3VtabLock((VTable *)zP4);
+ assert( ((VTable *)zP4)->db==p->db );
+ }else if( n<0 ){
pOp->p4.p = (void*)zP4;
pOp->p4type = (signed char)n;
- if( n==P4_VTAB ) sqlite3VtabLock((VTable*)zP4);
+ }else{
+ if( n==0 ) n = sqlite3Strlen30(zP4);
+ pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n);
+ pOp->p4type = P4_DYNAMIC;
}
}
@@ -71097,138 +65818,67 @@ static int displayComment(
}
#endif /* SQLITE_DEBUG */
-#if VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS)
-/*
-** Translate the P4.pExpr value for an OP_CursorHint opcode into text
-** that can be displayed in the P4 column of EXPLAIN output.
-*/
-static void displayP4Expr(StrAccum *p, Expr *pExpr){
- const char *zOp = 0;
- switch( pExpr->op ){
- case TK_STRING:
- sqlite3XPrintf(p, "%Q", pExpr->u.zToken);
- break;
- case TK_INTEGER:
- sqlite3XPrintf(p, "%d", pExpr->u.iValue);
- break;
- case TK_NULL:
- sqlite3XPrintf(p, "NULL");
- break;
- case TK_REGISTER: {
- sqlite3XPrintf(p, "r[%d]", pExpr->iTable);
- break;
- }
- case TK_COLUMN: {
- if( pExpr->iColumn<0 ){
- sqlite3XPrintf(p, "rowid");
- }else{
- sqlite3XPrintf(p, "c%d", (int)pExpr->iColumn);
- }
- break;
- }
- case TK_LT: zOp = "LT"; break;
- case TK_LE: zOp = "LE"; break;
- case TK_GT: zOp = "GT"; break;
- case TK_GE: zOp = "GE"; break;
- case TK_NE: zOp = "NE"; break;
- case TK_EQ: zOp = "EQ"; break;
- case TK_IS: zOp = "IS"; break;
- case TK_ISNOT: zOp = "ISNOT"; break;
- case TK_AND: zOp = "AND"; break;
- case TK_OR: zOp = "OR"; break;
- case TK_PLUS: zOp = "ADD"; break;
- case TK_STAR: zOp = "MUL"; break;
- case TK_MINUS: zOp = "SUB"; break;
- case TK_REM: zOp = "REM"; break;
- case TK_BITAND: zOp = "BITAND"; break;
- case TK_BITOR: zOp = "BITOR"; break;
- case TK_SLASH: zOp = "DIV"; break;
- case TK_LSHIFT: zOp = "LSHIFT"; break;
- case TK_RSHIFT: zOp = "RSHIFT"; break;
- case TK_CONCAT: zOp = "CONCAT"; break;
- case TK_UMINUS: zOp = "MINUS"; break;
- case TK_UPLUS: zOp = "PLUS"; break;
- case TK_BITNOT: zOp = "BITNOT"; break;
- case TK_NOT: zOp = "NOT"; break;
- case TK_ISNULL: zOp = "ISNULL"; break;
- case TK_NOTNULL: zOp = "NOTNULL"; break;
-
- default:
- sqlite3XPrintf(p, "%s", "expr");
- break;
- }
-
- if( zOp ){
- sqlite3XPrintf(p, "%s(", zOp);
- displayP4Expr(p, pExpr->pLeft);
- if( pExpr->pRight ){
- sqlite3StrAccumAppend(p, ",", 1);
- displayP4Expr(p, pExpr->pRight);
- }
- sqlite3StrAccumAppend(p, ")", 1);
- }
-}
-#endif /* VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS) */
-
-#if VDBE_DISPLAY_P4
+#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
+ || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
/*
** Compute a string that describes the P4 parameter for an opcode.
** Use zTemp for any required temporary buffer space.
*/
static char *displayP4(Op *pOp, char *zTemp, int nTemp){
char *zP4 = zTemp;
- StrAccum x;
assert( nTemp>=20 );
- sqlite3StrAccumInit(&x, 0, zTemp, nTemp, 0);
switch( pOp->p4type ){
case P4_KEYINFO: {
- int j;
+ int i, j;
KeyInfo *pKeyInfo = pOp->p4.pKeyInfo;
assert( pKeyInfo->aSortOrder!=0 );
- sqlite3XPrintf(&x, "k(%d", pKeyInfo->nField);
+ sqlite3_snprintf(nTemp, zTemp, "k(%d", pKeyInfo->nField);
+ i = sqlite3Strlen30(zTemp);
for(j=0; j<pKeyInfo->nField; j++){
CollSeq *pColl = pKeyInfo->aColl[j];
- const char *zColl = pColl ? pColl->zName : "";
- if( strcmp(zColl, "BINARY")==0 ) zColl = "B";
- sqlite3XPrintf(&x, ",%s%s", pKeyInfo->aSortOrder[j] ? "-" : "", zColl);
+ const char *zColl = pColl ? pColl->zName : "nil";
+ int n = sqlite3Strlen30(zColl);
+ if( n==6 && memcmp(zColl,"BINARY",6)==0 ){
+ zColl = "B";
+ n = 1;
+ }
+ if( i+n>nTemp-6 ){
+ memcpy(&zTemp[i],",...",4);
+ break;
+ }
+ zTemp[i++] = ',';
+ if( pKeyInfo->aSortOrder[j] ){
+ zTemp[i++] = '-';
+ }
+ memcpy(&zTemp[i], zColl, n+1);
+ i += n;
}
- sqlite3StrAccumAppend(&x, ")", 1);
+ zTemp[i++] = ')';
+ zTemp[i] = 0;
+ assert( i<nTemp );
break;
}
-#ifdef SQLITE_ENABLE_CURSOR_HINTS
- case P4_EXPR: {
- displayP4Expr(&x, pOp->p4.pExpr);
- break;
- }
-#endif
case P4_COLLSEQ: {
CollSeq *pColl = pOp->p4.pColl;
- sqlite3XPrintf(&x, "(%.20s)", pColl->zName);
+ sqlite3_snprintf(nTemp, zTemp, "(%.20s)", pColl->zName);
break;
}
case P4_FUNCDEF: {
FuncDef *pDef = pOp->p4.pFunc;
- sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg);
+ sqlite3_snprintf(nTemp, zTemp, "%s(%d)", pDef->zName, pDef->nArg);
break;
}
-#ifdef SQLITE_DEBUG
- case P4_FUNCCTX: {
- FuncDef *pDef = pOp->p4.pCtx->pFunc;
- sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg);
- break;
- }
-#endif
case P4_INT64: {
- sqlite3XPrintf(&x, "%lld", *pOp->p4.pI64);
+ sqlite3_snprintf(nTemp, zTemp, "%lld", *pOp->p4.pI64);
break;
}
case P4_INT32: {
- sqlite3XPrintf(&x, "%d", pOp->p4.i);
+ sqlite3_snprintf(nTemp, zTemp, "%d", pOp->p4.i);
break;
}
case P4_REAL: {
- sqlite3XPrintf(&x, "%.16g", *pOp->p4.pReal);
+ sqlite3_snprintf(nTemp, zTemp, "%.16g", *pOp->p4.pReal);
break;
}
case P4_MEM: {
@@ -71236,11 +65886,11 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
if( pMem->flags & MEM_Str ){
zP4 = pMem->z;
}else if( pMem->flags & MEM_Int ){
- sqlite3XPrintf(&x, "%lld", pMem->u.i);
+ sqlite3_snprintf(nTemp, zTemp, "%lld", pMem->u.i);
}else if( pMem->flags & MEM_Real ){
- sqlite3XPrintf(&x, "%.16g", pMem->u.r);
+ sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->u.r);
}else if( pMem->flags & MEM_Null ){
- zP4 = "NULL";
+ sqlite3_snprintf(nTemp, zTemp, "NULL");
}else{
assert( pMem->flags & MEM_Blob );
zP4 = "(blob)";
@@ -71250,34 +65900,22 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
#ifndef SQLITE_OMIT_VIRTUALTABLE
case P4_VTAB: {
sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab;
- sqlite3XPrintf(&x, "vtab:%p", pVtab);
+ sqlite3_snprintf(nTemp, zTemp, "vtab:%p", pVtab);
break;
}
#endif
case P4_INTARRAY: {
- int i;
- int *ai = pOp->p4.ai;
- int n = ai[0]; /* The first element of an INTARRAY is always the
- ** count of the number of elements to follow */
- for(i=1; i<n; i++){
- sqlite3XPrintf(&x, ",%d", ai[i]);
- }
- zTemp[0] = '[';
- sqlite3StrAccumAppend(&x, "]", 1);
+ sqlite3_snprintf(nTemp, zTemp, "intarray");
break;
}
case P4_SUBPROGRAM: {
- sqlite3XPrintf(&x, "program");
+ sqlite3_snprintf(nTemp, zTemp, "program");
break;
}
case P4_ADVANCE: {
zTemp[0] = 0;
break;
}
- case P4_TABLE: {
- sqlite3XPrintf(&x, "%s", pOp->p4.pTab->zName);
- break;
- }
default: {
zP4 = pOp->p4.z;
if( zP4==0 ){
@@ -71286,11 +65924,10 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
}
}
}
- sqlite3StrAccumFinish(&x);
assert( zP4!=0 );
return zP4;
}
-#endif /* VDBE_DISPLAY_P4 */
+#endif
/*
** Declare to the Vdbe that the BTree object at db->aDb[i] is used.
@@ -71309,7 +65946,7 @@ SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){
}
}
-#if !defined(SQLITE_OMIT_SHARED_CACHE)
+#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
/*
** If SQLite is compiled to support shared-cache mode and to be threadsafe,
** this routine obtains the mutex associated with each BtShared structure
@@ -71352,11 +65989,12 @@ SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe *p){
/*
** Unlock all of the btrees previously locked by a call to sqlite3VdbeEnter().
*/
-static SQLITE_NOINLINE void vdbeLeave(Vdbe *p){
+SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe *p){
int i;
sqlite3 *db;
Db *aDb;
int nDb;
+ if( DbMaskAllZero(p->lockMask) ) return; /* The common case */
db = p->db;
aDb = db->aDb;
nDb = db->nDb;
@@ -71366,10 +66004,6 @@ static SQLITE_NOINLINE void vdbeLeave(Vdbe *p){
}
}
}
-SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe *p){
- if( DbMaskAllZero(p->lockMask) ) return; /* The common case */
- vdbeLeave(p);
-}
#endif
#if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
@@ -71406,6 +66040,7 @@ static void releaseMemArray(Mem *p, int N){
if( p && N ){
Mem *pEnd = &p[N];
sqlite3 *db = p->db;
+ u8 malloc_failed = db->mallocFailed;
if( db->pnBytesFreed ){
do{
if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
@@ -71441,6 +66076,7 @@ static void releaseMemArray(Mem *p, int N){
p->flags = MEM_Undefined;
}while( (++p)<pEnd );
+ db->mallocFailed = malloc_failed;
}
}
@@ -71456,7 +66092,6 @@ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame *p){
sqlite3VdbeFreeCursor(p->v, apCsr[i]);
}
releaseMemArray(aMem, p->nChildMem);
- sqlite3VdbeDeleteAuxData(p->v->db, &p->pAuxData, -1, 0);
sqlite3DbFree(p->v->db, p);
}
@@ -71499,10 +66134,10 @@ SQLITE_PRIVATE int sqlite3VdbeList(
releaseMemArray(pMem, 8);
p->pResultSet = 0;
- if( p->rc==SQLITE_NOMEM_BKPT ){
+ if( p->rc==SQLITE_NOMEM ){
/* This happens if a malloc() inside a call to sqlite3_column_text() or
** sqlite3_column_text16() failed. */
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
return SQLITE_ERROR;
}
@@ -71541,7 +66176,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
}else if( db->u1.isInterrupted ){
p->rc = SQLITE_INTERRUPT;
rc = SQLITE_ERROR;
- sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
+ sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3ErrStr(p->rc));
}else{
char *zP4;
Op *pOp;
@@ -71603,12 +66238,12 @@ SQLITE_PRIVATE int sqlite3VdbeList(
pMem->u.i = pOp->p3; /* P3 */
pMem++;
- if( sqlite3VdbeMemClearAndResize(pMem, 100) ){ /* P4 */
+ if( sqlite3VdbeMemClearAndResize(pMem, 32) ){ /* P4 */
assert( p->db->mallocFailed );
return SQLITE_ERROR;
}
pMem->flags = MEM_Str|MEM_Term;
- zP4 = displayP4(pOp, pMem->z, pMem->szMalloc);
+ zP4 = displayP4(pOp, pMem->z, 32);
if( zP4!=pMem->z ){
sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0);
}else{
@@ -71700,46 +66335,43 @@ SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe *p){
}
#endif /* !SQLITE_OMIT_TRACE && SQLITE_ENABLE_IOTRACE */
-/* An instance of this object describes bulk memory available for use
-** by subcomponents of a prepared statement. Space is allocated out
-** of a ReusableSpace object by the allocSpace() routine below.
-*/
-struct ReusableSpace {
- u8 *pSpace; /* Available memory */
- int nFree; /* Bytes of available memory */
- int nNeeded; /* Total bytes that could not be allocated */
-};
-
-/* Try to allocate nByte bytes of 8-byte aligned bulk memory for pBuf
-** from the ReusableSpace object. Return a pointer to the allocated
-** memory on success. If insufficient memory is available in the
-** ReusableSpace object, increase the ReusableSpace.nNeeded
-** value by the amount needed and return NULL.
+/*
+** Allocate space from a fixed size buffer and return a pointer to
+** that space. If insufficient space is available, return NULL.
**
-** If pBuf is not initially NULL, that means that the memory has already
-** been allocated by a prior call to this routine, so just return a copy
-** of pBuf and leave ReusableSpace unchanged.
+** The pBuf parameter is the initial value of a pointer which will
+** receive the new memory. pBuf is normally NULL. If pBuf is not
+** NULL, it means that memory space has already been allocated and that
+** this routine should not allocate any new memory. When pBuf is not
+** NULL simply return pBuf. Only allocate new memory space when pBuf
+** is NULL.
**
-** This allocator is employed to repurpose unused slots at the end of the
-** opcode array of prepared state for other memory needs of the prepared
-** statement.
+** nByte is the number of bytes of space needed.
+**
+** *ppFrom points to available space and pEnd points to the end of the
+** available space. When space is allocated, *ppFrom is advanced past
+** the end of the allocated space.
+**
+** *pnByte is a counter of the number of bytes of space that have failed
+** to allocate. If there is insufficient space in *ppFrom to satisfy the
+** request, then increment *pnByte by the amount of the request.
*/
static void *allocSpace(
- struct ReusableSpace *p, /* Bulk memory available for allocation */
- void *pBuf, /* Pointer to a prior allocation */
- int nByte /* Bytes of memory needed */
-){
- assert( EIGHT_BYTE_ALIGNMENT(p->pSpace) );
- if( pBuf==0 ){
- nByte = ROUND8(nByte);
- if( nByte <= p->nFree ){
- p->nFree -= nByte;
- pBuf = &p->pSpace[p->nFree];
- }else{
- p->nNeeded += nByte;
- }
+ void *pBuf, /* Where return pointer will be stored */
+ int nByte, /* Number of bytes to allocate */
+ u8 **ppFrom, /* IN/OUT: Allocate from *ppFrom */
+ u8 *pEnd, /* Pointer to 1 byte past the end of *ppFrom buffer */
+ int *pnByte /* If allocation cannot be made, increment *pnByte */
+){
+ assert( EIGHT_BYTE_ALIGNMENT(*ppFrom) );
+ if( pBuf ) return pBuf;
+ nByte = ROUND8(nByte);
+ if( &(*ppFrom)[nByte] <= pEnd ){
+ pBuf = (void*)*ppFrom;
+ *ppFrom += nByte;
+ }else{
+ *pnByte += nByte;
}
- assert( EIGHT_BYTE_ALIGNMENT(pBuf) );
return pBuf;
}
@@ -71762,13 +66394,14 @@ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){
p->magic = VDBE_MAGIC_RUN;
#ifdef SQLITE_DEBUG
- for(i=0; i<p->nMem; i++){
+ for(i=1; i<p->nMem; i++){
assert( p->aMem[i].db==p->db );
}
#endif
p->pc = -1;
p->rc = SQLITE_OK;
p->errorAction = OE_Abort;
+ p->magic = VDBE_MAGIC_RUN;
p->nChange = 0;
p->cacheCtr = 1;
p->minWriteFileFormat = 255;
@@ -71811,7 +66444,9 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
int nArg; /* Number of arguments in subprograms */
int nOnce; /* Number of OP_Once instructions */
int n; /* Loop counter */
- struct ReusableSpace x; /* Reusable bulk memory */
+ u8 *zCsr; /* Memory available for allocation */
+ u8 *zEnd; /* First byte past allocated memory */
+ int nByte; /* How much extra memory is needed */
assert( p!=0 );
assert( p->nOp>0 );
@@ -71827,59 +66462,61 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
nOnce = pParse->nOnce;
if( nOnce==0 ) nOnce = 1; /* Ensure at least one byte in p->aOnceFlag[] */
- /* Each cursor uses a memory cell. The first cursor (cursor 0) can
- ** use aMem[0] which is not otherwise used by the VDBE program. Allocate
- ** space at the end of aMem[] for cursors 1 and greater.
+ /* For each cursor required, also allocate a memory cell. Memory
+ ** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by
+ ** the vdbe program. Instead they are used to allocate space for
+ ** VdbeCursor/BtCursor structures. The blob of memory associated with
+ ** cursor 0 is stored in memory cell nMem. Memory cell (nMem-1)
+ ** stores the blob of memory associated with cursor 1, etc.
+ **
** See also: allocateCursor().
*/
nMem += nCursor;
- if( nCursor==0 && nMem>0 ) nMem++; /* Space for aMem[0] even if not used */
- /* Figure out how much reusable memory is available at the end of the
- ** opcode array. This extra memory will be reallocated for other elements
- ** of the prepared statement.
+ /* Allocate space for memory registers, SQL variables, VDBE cursors and
+ ** an array to marshal SQL function arguments in.
*/
- n = ROUND8(sizeof(Op)*p->nOp); /* Bytes of opcode memory used */
- x.pSpace = &((u8*)p->aOp)[n]; /* Unused opcode memory */
- assert( EIGHT_BYTE_ALIGNMENT(x.pSpace) );
- x.nFree = ROUNDDOWN8(pParse->szOpAlloc - n); /* Bytes of unused memory */
- assert( x.nFree>=0 );
- if( x.nFree>0 ){
- memset(x.pSpace, 0, x.nFree);
- assert( EIGHT_BYTE_ALIGNMENT(&x.pSpace[x.nFree]) );
- }
+ zCsr = (u8*)&p->aOp[p->nOp]; /* Memory avaliable for allocation */
+ zEnd = (u8*)&p->aOp[pParse->nOpAlloc]; /* First byte past end of zCsr[] */
resolveP2Values(p, &nArg);
p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);
if( pParse->explain && nMem<10 ){
nMem = 10;
}
+ memset(zCsr, 0, zEnd-zCsr);
+ zCsr += (zCsr - (u8*)0)&7;
+ assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
p->expired = 0;
- /* Memory for registers, parameters, cursor, etc, is allocated in one or two
- ** passes. On the first pass, we try to reuse unused memory at the
+ /* Memory for registers, parameters, cursor, etc, is allocated in two
+ ** passes. On the first pass, we try to reuse unused space at the
** end of the opcode array. If we are unable to satisfy all memory
** requirements by reusing the opcode array tail, then the second
- ** pass will fill in the remainder using a fresh memory allocation.
+ ** pass will fill in the rest using a fresh allocation.
**
** This two-pass approach that reuses as much memory as possible from
- ** the leftover memory at the end of the opcode array. This can significantly
+ ** the leftover space at the end of the opcode array can significantly
** reduce the amount of memory held by a prepared statement.
*/
do {
- x.nNeeded = 0;
- p->aMem = allocSpace(&x, p->aMem, nMem*sizeof(Mem));
- p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem));
- p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*));
- p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*));
- p->aOnceFlag = allocSpace(&x, p->aOnceFlag, nOnce);
+ nByte = 0;
+ p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
+ p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
+ p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
+ p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
+ p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
+ &zCsr, zEnd, &nByte);
+ p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, &zCsr, zEnd, &nByte);
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64));
+ p->anExec = allocSpace(p->anExec, p->nOp*sizeof(i64), &zCsr, zEnd, &nByte);
#endif
- if( x.nNeeded==0 ) break;
- x.pSpace = p->pFree = sqlite3DbMallocZero(db, x.nNeeded);
- x.nFree = x.nNeeded;
- }while( !db->mallocFailed );
+ if( nByte ){
+ p->pFree = sqlite3DbMallocZero(db, nByte);
+ }
+ zCsr = p->pFree;
+ zEnd = &zCsr[nByte];
+ }while( nByte && !db->mallocFailed );
p->nCursor = nCursor;
p->nOnceFlag = nOnce;
@@ -71890,13 +66527,15 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
p->aVar[n].db = db;
}
}
- p->nzVar = pParse->nzVar;
- p->azVar = pParse->azVar;
- pParse->nzVar = 0;
- pParse->azVar = 0;
+ if( p->azVar && pParse->nzVar>0 ){
+ p->nzVar = pParse->nzVar;
+ memcpy(p->azVar, pParse->azVar, p->nzVar*sizeof(p->azVar[0]));
+ memset(pParse->azVar, 0, pParse->nzVar*sizeof(pParse->azVar[0]));
+ }
if( p->aMem ){
- p->nMem = nMem;
- for(n=0; n<nMem; n++){
+ p->aMem--; /* aMem[] goes from 1..nMem */
+ p->nMem = nMem; /* not from 0..nMem-1 */
+ for(n=1; n<=nMem; n++){
p->aMem[n].flags = MEM_Undefined;
p->aMem[n].db = db;
}
@@ -71913,34 +66552,23 @@ SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
if( pCx==0 ){
return;
}
- assert( pCx->pBt==0 || pCx->eCurType==CURTYPE_BTREE );
- switch( pCx->eCurType ){
- case CURTYPE_SORTER: {
- sqlite3VdbeSorterClose(p->db, pCx);
- break;
- }
- case CURTYPE_BTREE: {
- if( pCx->pBt ){
- sqlite3BtreeClose(pCx->pBt);
- /* The pCx->pCursor will be close automatically, if it exists, by
- ** the call above. */
- }else{
- assert( pCx->uc.pCursor!=0 );
- sqlite3BtreeCloseCursor(pCx->uc.pCursor);
- }
- break;
- }
+ sqlite3VdbeSorterClose(p->db, pCx);
+ if( pCx->pBt ){
+ sqlite3BtreeClose(pCx->pBt);
+ /* The pCx->pCursor will be close automatically, if it exists, by
+ ** the call above. */
+ }else if( pCx->pCursor ){
+ sqlite3BtreeCloseCursor(pCx->pCursor);
+ }
#ifndef SQLITE_OMIT_VIRTUALTABLE
- case CURTYPE_VTAB: {
- sqlite3_vtab_cursor *pVCur = pCx->uc.pVCur;
- const sqlite3_module *pModule = pVCur->pVtab->pModule;
- assert( pVCur->pVtab->nRef>0 );
- pVCur->pVtab->nRef--;
- pModule->xClose(pVCur);
- break;
- }
-#endif
+ else if( pCx->pVtabCursor ){
+ sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
+ const sqlite3_module *pModule = pVtabCursor->pVtab->pModule;
+ assert( pVtabCursor->pVtab->nRef>0 );
+ pVtabCursor->pVtab->nRef--;
+ pModule->xClose(pVtabCursor);
}
+#endif
}
/*
@@ -71981,9 +66609,6 @@ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
v->db->lastRowid = pFrame->lastRowid;
v->nChange = pFrame->nChange;
v->db->nChange = pFrame->nDbChange;
- sqlite3VdbeDeleteAuxData(v->db, &v->pAuxData, -1, 0);
- v->pAuxData = pFrame->pAuxData;
- pFrame->pAuxData = 0;
return pFrame->pc;
}
@@ -72006,7 +66631,7 @@ static void closeAllCursors(Vdbe *p){
assert( p->nFrame==0 );
closeCursorsInFrame(p);
if( p->aMem ){
- releaseMemArray(p->aMem, p->nMem);
+ releaseMemArray(&p->aMem[1], p->nMem);
}
while( p->pDelFrame ){
VdbeFrame *pDel = p->pDelFrame;
@@ -72015,7 +66640,7 @@ static void closeAllCursors(Vdbe *p){
}
/* Delete any auxdata allocations made by the VM */
- if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p->db, &p->pAuxData, -1, 0);
+ if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p, -1, 0);
assert( p->pAuxData==0 );
}
@@ -72031,7 +66656,7 @@ static void Cleanup(Vdbe *p){
int i;
if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 );
if( p->aMem ){
- for(i=0; i<p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined );
+ for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined );
}
#endif
@@ -72087,7 +66712,7 @@ SQLITE_PRIVATE int sqlite3VdbeSetColName(
assert( var<COLNAME_N );
if( p->db->mallocFailed ){
assert( !zName || xDel!=SQLITE_DYNAMIC );
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
assert( p->aColName!=0 );
pColName = &(p->aColName[idx+var*p->nResColumn]);
@@ -72104,9 +66729,7 @@ SQLITE_PRIVATE int sqlite3VdbeSetColName(
*/
static int vdbeCommit(sqlite3 *db, Vdbe *p){
int i;
- int nTrans = 0; /* Number of databases with an active write-transaction
- ** that are candidates for a two-phase commit using a
- ** master-journal */
+ int nTrans = 0; /* Number of databases with an active write-transaction */
int rc = SQLITE_OK;
int needXcommit = 0;
@@ -72134,28 +66757,10 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( sqlite3BtreeIsInTrans(pBt) ){
- /* Whether or not a database might need a master journal depends upon
- ** its journal mode (among other things). This matrix determines which
- ** journal modes use a master journal and which do not */
- static const u8 aMJNeeded[] = {
- /* DELETE */ 1,
- /* PERSIST */ 1,
- /* OFF */ 0,
- /* TRUNCATE */ 1,
- /* MEMORY */ 0,
- /* WAL */ 0
- };
- Pager *pPager; /* Pager associated with pBt */
needXcommit = 1;
+ if( i!=1 ) nTrans++;
sqlite3BtreeEnter(pBt);
- pPager = sqlite3BtreePager(pBt);
- if( db->aDb[i].safety_level!=PAGER_SYNCHRONOUS_OFF
- && aMJNeeded[sqlite3PagerGetJournalMode(pPager)]
- ){
- assert( i!=1 );
- nTrans++;
- }
- rc = sqlite3PagerExclusiveLock(pPager);
+ rc = sqlite3PagerExclusiveLock(sqlite3BtreePager(pBt));
sqlite3BtreeLeave(pBt);
}
}
@@ -72213,6 +66818,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
#ifndef SQLITE_OMIT_DISKIO
else{
sqlite3_vfs *pVfs = db->pVfs;
+ int needSync = 0;
char *zMaster = 0; /* File-name for the master journal */
char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt);
sqlite3_file *pMaster = 0;
@@ -72224,7 +66830,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
/* Select a master journal file name */
nMainFile = sqlite3Strlen30(zMainFile);
zMaster = sqlite3MPrintf(db, "%s-mjXXXXXX9XXz", zMainFile);
- if( zMaster==0 ) return SQLITE_NOMEM_BKPT;
+ if( zMaster==0 ) return SQLITE_NOMEM;
do {
u32 iRandom;
if( retryCount ){
@@ -72272,6 +66878,9 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
continue; /* Ignore TEMP and :memory: databases */
}
assert( zFile[0]!=0 );
+ if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){
+ needSync = 1;
+ }
rc = sqlite3OsWrite(pMaster, zFile, sqlite3Strlen30(zFile)+1, offset);
offset += sqlite3Strlen30(zFile)+1;
if( rc!=SQLITE_OK ){
@@ -72286,7 +66895,8 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
/* Sync the master journal file. If the IOCAP_SEQUENTIAL device
** flag is set this is not required.
*/
- if( 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL)
+ if( needSync
+ && 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL)
&& SQLITE_OK!=(rc = sqlite3OsSync(pMaster, SQLITE_SYNC_NORMAL))
){
sqlite3OsCloseFree(pMaster);
@@ -72322,7 +66932,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
** doing this the directory is synced again before any individual
** transaction files are deleted.
*/
- rc = sqlite3OsDelete(pVfs, zMaster, 1);
+ rc = sqlite3OsDelete(pVfs, zMaster, needSync);
sqlite3DbFree(db, zMaster);
zMaster = 0;
if( rc ){
@@ -72469,7 +67079,7 @@ SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *p, int deferred){
){
p->rc = SQLITE_CONSTRAINT_FOREIGNKEY;
p->errorAction = OE_Abort;
- sqlite3VdbeError(p, "FOREIGN KEY constraint failed");
+ sqlite3SetString(&p->zErrMsg, db, "FOREIGN KEY constraint failed");
return SQLITE_ERROR;
}
return SQLITE_OK;
@@ -72509,8 +67119,8 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
** one, or the complete transaction if there is no statement transaction.
*/
- if( db->mallocFailed ){
- p->rc = SQLITE_NOMEM_BKPT;
+ if( p->db->mallocFailed ){
+ p->rc = SQLITE_NOMEM;
}
if( p->aOnceFlag ) memset(p->aOnceFlag, 0, p->nOnceFlag);
closeAllCursors(p);
@@ -72670,8 +67280,8 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
}
p->magic = VDBE_MAGIC_HALT;
checkActiveVdbeCnt(db);
- if( db->mallocFailed ){
- p->rc = SQLITE_NOMEM_BKPT;
+ if( p->db->mallocFailed ){
+ p->rc = SQLITE_NOMEM;
}
/* If the auto-commit flag is set to true, then any locks that were held
@@ -72707,12 +67317,12 @@ SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p){
sqlite3 *db = p->db;
int rc = p->rc;
if( p->zErrMsg ){
- db->bBenignMalloc++;
+ u8 mallocFailed = db->mallocFailed;
sqlite3BeginBenignMalloc();
if( db->pErr==0 ) db->pErr = sqlite3ValueNew(db);
sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT);
sqlite3EndBenignMalloc();
- db->bBenignMalloc--;
+ db->mallocFailed = mallocFailed;
db->errCode = rc;
}else{
sqlite3Error(db, rc);
@@ -72858,7 +67468,8 @@ SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe *p){
** * the corresponding bit in argument mask is clear (where the first
** function parameter corresponds to bit 0 etc.).
*/
-SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp, int mask){
+SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){
+ AuxData **pp = &pVdbe->pAuxData;
while( *pp ){
AuxData *pAux = *pp;
if( (iOp<0)
@@ -72869,7 +67480,7 @@ SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp,
pAux->xDelete(pAux->pAux);
}
*pp = pAux->pNext;
- sqlite3DbFree(db, pAux);
+ sqlite3DbFree(pVdbe->db, pAux);
}else{
pp= &pAux->pNext;
}
@@ -72896,7 +67507,6 @@ SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
sqlite3DbFree(db, pSub);
}
for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]);
- sqlite3DbFree(db, p->azVar);
vdbeFreeOpArray(db, p->aOp, p->nOp);
sqlite3DbFree(db, p->aColName);
sqlite3DbFree(db, p->zSql);
@@ -72945,8 +67555,7 @@ static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){
#endif
assert( p->deferredMoveto );
assert( p->isTable );
- assert( p->eCurType==CURTYPE_BTREE );
- rc = sqlite3BtreeMovetoUnpacked(p->uc.pCursor, 0, p->movetoTarget, 0, &res);
+ rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res);
if( rc ) return rc;
if( res!=0 ) return SQLITE_CORRUPT_BKPT;
#ifdef SQLITE_TEST
@@ -72966,10 +67575,9 @@ static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){
*/
static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){
int isDifferentRow, rc;
- assert( p->eCurType==CURTYPE_BTREE );
- assert( p->uc.pCursor!=0 );
- assert( sqlite3BtreeCursorHasMoved(p->uc.pCursor) );
- rc = sqlite3BtreeCursorRestore(p->uc.pCursor, &isDifferentRow);
+ assert( p->pCursor!=0 );
+ assert( sqlite3BtreeCursorHasMoved(p->pCursor) );
+ rc = sqlite3BtreeCursorRestore(p->pCursor, &isDifferentRow);
p->cacheStatus = CACHE_STALE;
if( isDifferentRow ) p->nullRow = 1;
return rc;
@@ -72980,8 +67588,7 @@ static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){
** if need be. Return any I/O error from the restore operation.
*/
SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor *p){
- assert( p->eCurType==CURTYPE_BTREE );
- if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
+ if( sqlite3BtreeCursorHasMoved(p->pCursor) ){
return handleMovedCursor(p);
}
return SQLITE_OK;
@@ -73000,21 +67607,12 @@ SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor *p){
** If the cursor is already pointing to the correct row and that row has
** not been deleted out from under the cursor, then this routine is a no-op.
*/
-SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
- VdbeCursor *p = *pp;
- if( p->eCurType==CURTYPE_BTREE ){
- if( p->deferredMoveto ){
- int iMap;
- if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 ){
- *pp = p->pAltCursor;
- *piCol = iMap - 1;
- return SQLITE_OK;
- }
- return handleDeferredMoveto(p);
- }
- if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
- return handleMovedCursor(p);
- }
+SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor *p){
+ if( p->deferredMoveto ){
+ return handleDeferredMoveto(p);
+ }
+ if( p->pCursor && sqlite3BtreeCursorHasMoved(p->pCursor) ){
+ return handleMovedCursor(p);
}
return SQLITE_OK;
}
@@ -73064,13 +67662,11 @@ SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
/*
** Return the serial-type for the value stored in pMem.
*/
-SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){
+SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
int flags = pMem->flags;
u32 n;
- assert( pLen!=0 );
if( flags&MEM_Null ){
- *pLen = 0;
return 0;
}
if( flags&MEM_Int ){
@@ -73084,23 +67680,15 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){
u = i;
}
if( u<=127 ){
- if( (i&1)==i && file_format>=4 ){
- *pLen = 0;
- return 8+(u32)u;
- }else{
- *pLen = 1;
- return 1;
- }
+ return ((i&1)==i && file_format>=4) ? 8+(u32)u : 1;
}
- if( u<=32767 ){ *pLen = 2; return 2; }
- if( u<=8388607 ){ *pLen = 3; return 3; }
- if( u<=2147483647 ){ *pLen = 4; return 4; }
- if( u<=MAX_6BYTE ){ *pLen = 6; return 5; }
- *pLen = 8;
+ if( u<=32767 ) return 2;
+ if( u<=8388607 ) return 3;
+ if( u<=2147483647 ) return 4;
+ if( u<=MAX_6BYTE ) return 5;
return 6;
}
if( flags&MEM_Real ){
- *pLen = 8;
return 7;
}
assert( pMem->db->mallocFailed || flags&(MEM_Str|MEM_Blob) );
@@ -73109,46 +67697,20 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){
if( flags & MEM_Zero ){
n += pMem->u.nZero;
}
- *pLen = n;
return ((n*2) + 12 + ((flags&MEM_Str)!=0));
}
/*
-** The sizes for serial types less than 128
-*/
-static const u8 sqlite3SmallTypeSizes[] = {
- /* 0 1 2 3 4 5 6 7 8 9 */
-/* 0 */ 0, 1, 2, 3, 4, 6, 8, 8, 0, 0,
-/* 10 */ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
-/* 20 */ 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
-/* 30 */ 9, 9, 10, 10, 11, 11, 12, 12, 13, 13,
-/* 40 */ 14, 14, 15, 15, 16, 16, 17, 17, 18, 18,
-/* 50 */ 19, 19, 20, 20, 21, 21, 22, 22, 23, 23,
-/* 60 */ 24, 24, 25, 25, 26, 26, 27, 27, 28, 28,
-/* 70 */ 29, 29, 30, 30, 31, 31, 32, 32, 33, 33,
-/* 80 */ 34, 34, 35, 35, 36, 36, 37, 37, 38, 38,
-/* 90 */ 39, 39, 40, 40, 41, 41, 42, 42, 43, 43,
-/* 100 */ 44, 44, 45, 45, 46, 46, 47, 47, 48, 48,
-/* 110 */ 49, 49, 50, 50, 51, 51, 52, 52, 53, 53,
-/* 120 */ 54, 54, 55, 55, 56, 56, 57, 57
-};
-
-/*
** Return the length of the data corresponding to the supplied serial-type.
*/
SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32 serial_type){
- if( serial_type>=128 ){
+ if( serial_type>=12 ){
return (serial_type-12)/2;
}else{
- assert( serial_type<12
- || sqlite3SmallTypeSizes[serial_type]==(serial_type - 12)/2 );
- return sqlite3SmallTypeSizes[serial_type];
+ static const u8 aSize[] = { 0, 1, 2, 3, 4, 6, 8, 8, 0, 0, 0, 0 };
+ return aSize[serial_type];
}
}
-SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8 serial_type){
- assert( serial_type<128 );
- return sqlite3SmallTypeSizes[serial_type];
-}
/*
** If we are on an architecture with mixed-endian floating
@@ -73230,7 +67792,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
}else{
v = pMem->u.i;
}
- len = i = sqlite3SmallTypeSizes[serial_type];
+ len = i = sqlite3VdbeSerialTypeLen(serial_type);
assert( i>0 );
do{
buf[--i] = (u8)(v&0xFF);
@@ -73244,7 +67806,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
assert( pMem->n + ((pMem->flags & MEM_Zero)?pMem->u.nZero:0)
== (int)sqlite3VdbeSerialTypeLen(serial_type) );
len = pMem->n;
- if( len>0 ) memcpy(buf, pMem->z, len);
+ memcpy(buf, pMem->z, len);
return len;
}
@@ -73347,10 +67909,6 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
/* EVIDENCE-OF: R-01849-26079 Value is a big-endian 32-bit
** twos-complement integer. */
pMem->u.i = FOUR_BYTE_INT(buf);
-#ifdef __HP_cc
- /* Work around a sign-extension bug in the HP compiler for HP/UX */
- if( buf[0]&0x80 ) pMem->u.i |= 0xffffffff80000000LL;
-#endif
pMem->flags = MEM_Int;
testcase( pMem->u.i<0 );
return 4;
@@ -73468,7 +68026,6 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(
pMem->db = pKeyInfo->db;
/* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */
pMem->szMalloc = 0;
- pMem->z = 0;
d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem);
pMem++;
if( (++u)>=p->nField ) break;
@@ -73520,7 +68077,6 @@ static int vdbeRecordCompareDebug(
/* mem1.u.i = 0; // not needed, here to silence compiler warning */
idx1 = getVarint32(aKey1, szHdr1);
- if( szHdr1>98307 ) return SQLITE_CORRUPT;
d1 = szHdr1;
assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB );
assert( pKeyInfo->aSortOrder!=0 );
@@ -73649,9 +68205,9 @@ static int vdbeCompareMemString(
v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc);
n2 = v2==0 ? 0 : c2.n;
rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
- if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM_BKPT;
sqlite3VdbeMemRelease(&c1);
sqlite3VdbeMemRelease(&c2);
+ if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM;
return rc;
}
}
@@ -73667,34 +68223,6 @@ static SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){
return pB1->n - pB2->n;
}
-/*
-** Do a comparison between a 64-bit signed integer and a 64-bit floating-point
-** number. Return negative, zero, or positive if the first (i64) is less than,
-** equal to, or greater than the second (double).
-*/
-static int sqlite3IntFloatCompare(i64 i, double r){
- if( sizeof(LONGDOUBLE_TYPE)>8 ){
- LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i;
- if( x<r ) return -1;
- if( x>r ) return +1;
- return 0;
- }else{
- i64 y;
- double s;
- if( r<-9223372036854775808.0 ) return +1;
- if( r>9223372036854775807.0 ) return -1;
- y = (i64)r;
- if( i<y ) return -1;
- if( i>y ){
- if( y==SMALLEST_INT64 && r>0.0 ) return -1;
- return +1;
- }
- s = (double)i;
- if( s<r ) return -1;
- if( s>r ) return +1;
- return 0;
- }
-}
/*
** Compare the values contained by the two memory cells, returning
@@ -73721,34 +68249,34 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
return (f2&MEM_Null) - (f1&MEM_Null);
}
- /* At least one of the two values is a number
+ /* If one value is a number and the other is not, the number is less.
+ ** If both are numbers, compare as reals if one is a real, or as integers
+ ** if both values are integers.
*/
if( combined_flags&(MEM_Int|MEM_Real) ){
+ double r1, r2;
if( (f1 & f2 & MEM_Int)!=0 ){
if( pMem1->u.i < pMem2->u.i ) return -1;
- if( pMem1->u.i > pMem2->u.i ) return +1;
+ if( pMem1->u.i > pMem2->u.i ) return 1;
return 0;
}
- if( (f1 & f2 & MEM_Real)!=0 ){
- if( pMem1->u.r < pMem2->u.r ) return -1;
- if( pMem1->u.r > pMem2->u.r ) return +1;
- return 0;
- }
- if( (f1&MEM_Int)!=0 ){
- if( (f2&MEM_Real)!=0 ){
- return sqlite3IntFloatCompare(pMem1->u.i, pMem2->u.r);
- }else{
- return -1;
- }
- }
if( (f1&MEM_Real)!=0 ){
- if( (f2&MEM_Int)!=0 ){
- return -sqlite3IntFloatCompare(pMem2->u.i, pMem1->u.r);
- }else{
- return -1;
- }
+ r1 = pMem1->u.r;
+ }else if( (f1&MEM_Int)!=0 ){
+ r1 = (double)pMem1->u.i;
+ }else{
+ return 1;
+ }
+ if( (f2&MEM_Real)!=0 ){
+ r2 = pMem2->u.r;
+ }else if( (f2&MEM_Int)!=0 ){
+ r2 = (double)pMem2->u.i;
+ }else{
+ return -1;
}
- return +1;
+ if( r1<r2 ) return -1;
+ if( r1>r2 ) return 1;
+ return 0;
}
/* If one value is a string and the other is a blob, the string is less.
@@ -73762,7 +68290,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
return -1;
}
- assert( pMem1->enc==pMem2->enc || pMem1->db->mallocFailed );
+ assert( pMem1->enc==pMem2->enc );
assert( pMem1->enc==SQLITE_UTF8 ||
pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE );
@@ -73894,13 +68422,18 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
if( pRhs->flags & MEM_Int ){
serial_type = aKey1[idx1];
testcase( serial_type==12 );
- if( serial_type>=10 ){
+ if( serial_type>=12 ){
rc = +1;
}else if( serial_type==0 ){
rc = -1;
}else if( serial_type==7 ){
+ double rhs = (double)pRhs->u.i;
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
- rc = -sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r);
+ if( mem1.u.r<rhs ){
+ rc = -1;
+ }else if( mem1.u.r>rhs ){
+ rc = +1;
+ }
}else{
i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]);
i64 rhs = pRhs->u.i;
@@ -73915,24 +68448,23 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
/* RHS is real */
else if( pRhs->flags & MEM_Real ){
serial_type = aKey1[idx1];
- if( serial_type>=10 ){
- /* Serial types 12 or greater are strings and blobs (greater than
- ** numbers). Types 10 and 11 are currently "reserved for future
- ** use", so it doesn't really matter what the results of comparing
- ** them to numberic values are. */
+ if( serial_type>=12 ){
rc = +1;
}else if( serial_type==0 ){
rc = -1;
}else{
+ double rhs = pRhs->u.r;
+ double lhs;
sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
if( serial_type==7 ){
- if( mem1.u.r<pRhs->u.r ){
- rc = -1;
- }else if( mem1.u.r>pRhs->u.r ){
- rc = +1;
- }
+ lhs = mem1.u.r;
}else{
- rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r);
+ lhs = (double)mem1.u.i;
+ }
+ if( lhs<rhs ){
+ rc = -1;
+ }else if( lhs>rhs ){
+ rc = +1;
}
}
}
@@ -74022,7 +68554,6 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
|| vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc)
|| pKeyInfo->db->mallocFailed
);
- pPKey2->eqSeen = 1;
return pPKey2->default_rc;
}
SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
@@ -74122,7 +68653,6 @@ static int vdbeRecordCompareInt(
/* The first fields of the two keys are equal and there are no trailing
** fields. Return pPKey2->default_rc in this case. */
res = pPKey2->default_rc;
- pPKey2->eqSeen = 1;
}
assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) );
@@ -74143,7 +68673,6 @@ static int vdbeRecordCompareString(
int serial_type;
int res;
- assert( pPKey2->aMem[0].flags & MEM_Str );
vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
getVarint32(&aKey1[1], serial_type);
if( serial_type<12 ){
@@ -74170,7 +68699,6 @@ static int vdbeRecordCompareString(
res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
}else{
res = pPKey2->default_rc;
- pPKey2->eqSeen = 1;
}
}else if( res>0 ){
res = pPKey2->r2;
@@ -74289,7 +68817,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
if( unlikely(typeRowid<1 || typeRowid>9 || typeRowid==7) ){
goto idx_rowid_corruption;
}
- lenRowid = sqlite3SmallTypeSizes[typeRowid];
+ lenRowid = sqlite3VdbeSerialTypeLen(typeRowid);
testcase( (u32)m.n==szHdr+lenRowid );
if( unlikely((u32)m.n<szHdr+lenRowid) ){
goto idx_rowid_corruption;
@@ -74328,11 +68856,9 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
){
i64 nCellKey = 0;
int rc;
- BtCursor *pCur;
+ BtCursor *pCur = pC->pCursor;
Mem m;
- assert( pC->eCurType==CURTYPE_BTREE );
- pCur = pC->uc.pCursor;
assert( sqlite3BtreeCursorIsValid(pCur) );
VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey);
assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */
@@ -74343,7 +68869,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
return SQLITE_CORRUPT_BKPT;
}
sqlite3VdbeMemInit(&m, db, 0);
- rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m);
+ rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, (u32)nCellKey, 1, &m);
if( rc ){
return rc;
}
@@ -74439,100 +68965,14 @@ SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
** in memory obtained from sqlite3DbMalloc).
*/
SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
- if( pVtab->zErrMsg ){
- sqlite3 *db = p->db;
- sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
- sqlite3_free(pVtab->zErrMsg);
- pVtab->zErrMsg = 0;
- }
+ sqlite3 *db = p->db;
+ sqlite3DbFree(db, p->zErrMsg);
+ p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
+ sqlite3_free(pVtab->zErrMsg);
+ pVtab->zErrMsg = 0;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
-
-/*
-** If the second argument is not NULL, release any allocations associated
-** with the memory cells in the p->aMem[] array. Also free the UnpackedRecord
-** structure itself, using sqlite3DbFree().
-**
-** This function is used to free UnpackedRecord structures allocated by
-** the vdbeUnpackRecord() function found in vdbeapi.c.
-*/
-static void vdbeFreeUnpacked(sqlite3 *db, UnpackedRecord *p){
- if( p ){
- int i;
- for(i=0; i<p->nField; i++){
- Mem *pMem = &p->aMem[i];
- if( pMem->zMalloc ) sqlite3VdbeMemRelease(pMem);
- }
- sqlite3DbFree(db, p);
- }
-}
-#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
-
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
-/*
-** Invoke the pre-update hook. If this is an UPDATE or DELETE pre-update call,
-** then cursor passed as the second argument should point to the row about
-** to be update or deleted. If the application calls sqlite3_preupdate_old(),
-** the required value will be read from the row the cursor points to.
-*/
-SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
- Vdbe *v, /* Vdbe pre-update hook is invoked by */
- VdbeCursor *pCsr, /* Cursor to grab old.* values from */
- int op, /* SQLITE_INSERT, UPDATE or DELETE */
- const char *zDb, /* Database name */
- Table *pTab, /* Modified table */
- i64 iKey1, /* Initial key value */
- int iReg /* Register for new.* record */
-){
- sqlite3 *db = v->db;
- i64 iKey2;
- PreUpdate preupdate;
- const char *zTbl = pTab->zName;
- static const u8 fakeSortOrder = 0;
-
- assert( db->pPreUpdate==0 );
- memset(&preupdate, 0, sizeof(PreUpdate));
- if( op==SQLITE_UPDATE ){
- iKey2 = v->aMem[iReg].u.i;
- }else{
- iKey2 = iKey1;
- }
-
- assert( pCsr->nField==pTab->nCol
- || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1)
- );
-
- preupdate.v = v;
- preupdate.pCsr = pCsr;
- preupdate.op = op;
- preupdate.iNewReg = iReg;
- preupdate.keyinfo.db = db;
- preupdate.keyinfo.enc = ENC(db);
- preupdate.keyinfo.nField = pTab->nCol;
- preupdate.keyinfo.aSortOrder = (u8*)&fakeSortOrder;
- preupdate.iKey1 = iKey1;
- preupdate.iKey2 = iKey2;
- preupdate.iPKey = pTab->iPKey;
-
- db->pPreUpdate = &preupdate;
- db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
- db->pPreUpdate = 0;
- sqlite3DbFree(db, preupdate.aRecord);
- vdbeFreeUnpacked(db, preupdate.pUnpacked);
- vdbeFreeUnpacked(db, preupdate.pNewUnpacked);
- if( preupdate.aNew ){
- int i;
- for(i=0; i<pCsr->nField; i++){
- sqlite3VdbeMemRelease(&preupdate.aNew[i]);
- }
- sqlite3DbFree(db, preupdate.aNew);
- }
-}
-#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
-
/************** End of vdbeaux.c *********************************************/
/************** Begin file vdbeapi.c *****************************************/
/*
@@ -74550,8 +68990,6 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
** This file contains code use to implement APIs that are part of the
** VDBE.
*/
-/* #include "sqliteInt.h" */
-/* #include "vdbeInt.h" */
#ifndef SQLITE_OMIT_DEPRECATED
/*
@@ -74590,31 +69028,6 @@ static int vdbeSafetyNotNull(Vdbe *p){
}
}
-#ifndef SQLITE_OMIT_TRACE
-/*
-** Invoke the profile callback. This routine is only called if we already
-** know that the profile callback is defined and needs to be invoked.
-*/
-static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){
- sqlite3_int64 iNow;
- assert( p->startTime>0 );
- assert( db->xProfile!=0 );
- assert( db->init.busy==0 );
- assert( p->zSql!=0 );
- sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
- db->xProfile(db->pProfileArg, p->zSql, (iNow - p->startTime)*1000000);
- p->startTime = 0;
-}
-/*
-** The checkProfileCallback(DB,P) macro checks to see if a profile callback
-** is needed, and it invokes the callback if it is needed.
-*/
-# define checkProfileCallback(DB,P) \
- if( ((P)->startTime)>0 ){ invokeProfileCallback(DB,P); }
-#else
-# define checkProfileCallback(DB,P) /*no-op*/
-#endif
-
/*
** The following routine destroys a virtual machine that is created by
** the sqlite3_compile() routine. The integer returned is an SQLITE_
@@ -74635,7 +69048,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt){
sqlite3 *db = v->db;
if( vdbeSafety(v) ) return SQLITE_MISUSE_BKPT;
sqlite3_mutex_enter(db->mutex);
- checkProfileCallback(db, v);
rc = sqlite3VdbeFinalize(v);
rc = sqlite3ApiExit(db, rc);
sqlite3LeaveMutexAndCloseZombie(db);
@@ -74657,14 +69069,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt){
rc = SQLITE_OK;
}else{
Vdbe *v = (Vdbe*)pStmt;
- sqlite3 *db = v->db;
- sqlite3_mutex_enter(db->mutex);
- checkProfileCallback(db, v);
+ sqlite3_mutex_enter(v->db->mutex);
rc = sqlite3VdbeReset(v);
sqlite3VdbeRewind(v);
- assert( (rc & (db->errMask))==rc );
- rc = sqlite3ApiExit(db, rc);
- sqlite3_mutex_leave(db->mutex);
+ assert( (rc & (v->db->errMask))==rc );
+ rc = sqlite3ApiExit(v->db, rc);
+ sqlite3_mutex_leave(v->db->mutex);
}
return rc;
}
@@ -74699,10 +69109,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt *pStmt){
SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value *pVal){
Mem *p = (Mem*)pVal;
if( p->flags & (MEM_Blob|MEM_Str) ){
- if( sqlite3VdbeMemExpandBlob(p)!=SQLITE_OK ){
- assert( p->flags==MEM_Null && p->z==0 );
- return 0;
- }
+ sqlite3VdbeMemExpandBlob(p);
p->flags |= MEM_Blob;
return p->n ? p->z : 0;
}else{
@@ -74724,10 +69131,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value *pVal){
SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value *pVal){
return sqlite3VdbeIntValue((Mem*)pVal);
}
-SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value *pVal){
- Mem *pMem = (Mem*)pVal;
- return ((pMem->flags & MEM_Subtype) ? pMem->eSubtype : 0);
-}
SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value *pVal){
return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8);
}
@@ -74784,36 +69187,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value* pVal){
return aType[pVal->flags&MEM_AffMask];
}
-/* Make a copy of an sqlite3_value object
-*/
-SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value *pOrig){
- sqlite3_value *pNew;
- if( pOrig==0 ) return 0;
- pNew = sqlite3_malloc( sizeof(*pNew) );
- if( pNew==0 ) return 0;
- memset(pNew, 0, sizeof(*pNew));
- memcpy(pNew, pOrig, MEMCELLSIZE);
- pNew->flags &= ~MEM_Dyn;
- pNew->db = 0;
- if( pNew->flags&(MEM_Str|MEM_Blob) ){
- pNew->flags &= ~(MEM_Static|MEM_Dyn);
- pNew->flags |= MEM_Ephem;
- if( sqlite3VdbeMemMakeWriteable(pNew)!=SQLITE_OK ){
- sqlite3ValueFree(pNew);
- pNew = 0;
- }
- }
- return pNew;
-}
-
-/* Destroy an sqlite3_value object previously obtained from
-** sqlite3_value_dup().
-*/
-SQLITE_API void SQLITE_STDCALL sqlite3_value_free(sqlite3_value *pOld){
- sqlite3ValueFree(pOld);
-}
-
-
/**************************** sqlite3_result_ *******************************
** The following routines are used by user-defined functions to specify
** the function result.
@@ -74906,12 +69279,6 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context *pCtx){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetNull(pCtx->pOut);
}
-SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){
- Mem *pOut = pCtx->pOut;
- assert( sqlite3_mutex_held(pOut->db->mutex) );
- pOut->eSubtype = eSubtype & 0xff;
- pOut->flags |= MEM_Subtype;
-}
SQLITE_API void SQLITE_STDCALL sqlite3_result_text(
sqlite3_context *pCtx,
const char *z,
@@ -74974,15 +69341,6 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context *pCtx, in
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetZeroBlob(pCtx->pOut, n);
}
-SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){
- Mem *pOut = pCtx->pOut;
- assert( sqlite3_mutex_held(pOut->db->mutex) );
- if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){
- return SQLITE_TOOBIG;
- }
- sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n);
- return SQLITE_OK;
-}
SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
pCtx->isError = errCode;
pCtx->fErrorOrAux = 1;
@@ -75008,9 +69366,9 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context *pCtx
SQLITE_API void SQLITE_STDCALL sqlite3_result_error_nomem(sqlite3_context *pCtx){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetNull(pCtx->pOut);
- pCtx->isError = SQLITE_NOMEM_BKPT;
+ pCtx->isError = SQLITE_NOMEM;
pCtx->fErrorOrAux = 1;
- sqlite3OomFault(pCtx->pOut->db);
+ pCtx->pOut->db->mallocFailed = 1;
}
/*
@@ -75037,7 +69395,6 @@ static int doWalCallbacks(sqlite3 *db){
return rc;
}
-
/*
** Execute the statement pStmt, either until a row of data is ready, the
** statement is completely executed or an error occurs.
@@ -75084,7 +69441,7 @@ static int sqlite3Step(Vdbe *p){
db = p->db;
if( db->mallocFailed ){
p->rc = SQLITE_NOMEM;
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
if( p->pc<=0 && p->expired ){
@@ -75106,10 +69463,8 @@ static int sqlite3Step(Vdbe *p){
);
#ifndef SQLITE_OMIT_TRACE
- if( db->xProfile && !db->init.busy && p->zSql ){
+ if( db->xProfile && !db->init.busy ){
sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
- }else{
- assert( p->startTime==0 );
}
#endif
@@ -75133,8 +69488,13 @@ static int sqlite3Step(Vdbe *p){
}
#ifndef SQLITE_OMIT_TRACE
- /* If the statement completed successfully, invoke the profile callback */
- if( rc!=SQLITE_ROW ) checkProfileCallback(db, p);
+ /* Invoke the profile callback if there is one
+ */
+ if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy && p->zSql ){
+ sqlite3_int64 iNow;
+ sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
+ db->xProfile(db->pProfileArg, p->zSql, (iNow - p->startTime)*1000000);
+ }
#endif
if( rc==SQLITE_DONE ){
@@ -75147,7 +69507,7 @@ static int sqlite3Step(Vdbe *p){
db->errCode = rc;
if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){
- p->rc = SQLITE_NOMEM_BKPT;
+ p->rc = SQLITE_NOMEM;
}
end_of_step:
/* At this point local variable rc holds the value that should be
@@ -75158,7 +69518,7 @@ end_of_step:
** were called on statement p.
*/
assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR
- || (rc&0xff)==SQLITE_BUSY || rc==SQLITE_MISUSE
+ || rc==SQLITE_BUSY || rc==SQLITE_MISUSE
);
assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp );
if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
@@ -75214,7 +69574,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt *pStmt){
v->rc = rc2;
} else {
v->zErrMsg = 0;
- v->rc = rc = SQLITE_NOMEM_BKPT;
+ v->rc = rc = SQLITE_NOMEM;
}
}
rc = sqlite3ApiExit(db, rc);
@@ -75243,7 +69603,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context *p){
** application defined function.
*/
SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context *p){
- assert( p && p->pOut );
+ assert( p && p->pFunc );
return p->pOut->db;
}
@@ -75319,7 +69679,7 @@ static SQLITE_NOINLINE void *createAggContext(sqlite3_context *p, int nByte){
** same context that was returned on prior calls.
*/
SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context *p, int nByte){
- assert( p && p->pFunc && p->pFunc->xFinalize );
+ assert( p && p->pFunc && p->pFunc->xStep );
assert( sqlite3_mutex_held(p->pOut->db->mutex) );
testcase( nByte<0 );
if( (p->pMem->flags & MEM_Agg)==0 ){
@@ -75410,7 +69770,7 @@ failed:
** context.
*/
SQLITE_API int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context *p){
- assert( p && p->pMem && p->pFunc && p->pFunc->xFinalize );
+ assert( p && p->pMem && p->pFunc && p->pFunc->xStep );
return p->pMem->n;
}
#endif
@@ -75452,19 +69812,18 @@ static const Mem *columnNullValue(void){
#endif
= {
/* .u = */ {0},
- /* .flags = */ (u16)MEM_Null,
- /* .enc = */ (u8)0,
- /* .eSubtype = */ (u8)0,
- /* .n = */ (int)0,
- /* .z = */ (char*)0,
- /* .zMalloc = */ (char*)0,
- /* .szMalloc = */ (int)0,
- /* .uTemp = */ (u32)0,
- /* .db = */ (sqlite3*)0,
- /* .xDel = */ (void(*)(void*))0,
+ /* .flags = */ MEM_Null,
+ /* .enc = */ 0,
+ /* .n = */ 0,
+ /* .z = */ 0,
+ /* .zMalloc = */ 0,
+ /* .szMalloc = */ 0,
+ /* .iPadding1 = */ 0,
+ /* .db = */ 0,
+ /* .xDel = */ 0,
#ifdef SQLITE_DEBUG
- /* .pScopyFrom = */ (Mem*)0,
- /* .pFiller = */ (void*)0,
+ /* .pScopyFrom = */ 0,
+ /* .pFiller = */ 0,
#endif
};
return &nullMem;
@@ -75638,7 +69997,7 @@ static const void *columnName(
** is the case, clear the mallocFailed flag and return NULL.
*/
if( db->mallocFailed ){
- sqlite3OomClear(db);
+ db->mallocFailed = 0;
ret = 0;
}
sqlite3_mutex_leave(db->mutex);
@@ -75838,9 +70197,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob(
int nData,
void (*xDel)(void*)
){
-#ifdef SQLITE_ENABLE_API_ARMOR
- if( nData<0 ) return SQLITE_MISUSE_BKPT;
-#endif
return bindText(pStmt, i, zData, nData, xDel, 0);
}
SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(
@@ -75966,20 +70322,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i,
}
return rc;
}
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint64 n){
- int rc;
- Vdbe *p = (Vdbe *)pStmt;
- sqlite3_mutex_enter(p->db->mutex);
- if( n>(u64)p->db->aLimit[SQLITE_LIMIT_LENGTH] ){
- rc = SQLITE_TOOBIG;
- }else{
- assert( (n & 0x7FFFFFFF)==n );
- rc = sqlite3_bind_zeroblob(pStmt, i, n);
- }
- rc = sqlite3ApiExit(p->db, rc);
- sqlite3_mutex_leave(p->db->mutex);
- return rc;
-}
/*
** Return the number of wildcards that can be potentially bound to.
@@ -76141,187 +70483,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, i
return (int)v;
}
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
-/*
-** Allocate and populate an UnpackedRecord structure based on the serialized
-** record in nKey/pKey. Return a pointer to the new UnpackedRecord structure
-** if successful, or a NULL pointer if an OOM error is encountered.
-*/
-static UnpackedRecord *vdbeUnpackRecord(
- KeyInfo *pKeyInfo,
- int nKey,
- const void *pKey
-){
- char *dummy; /* Dummy argument for AllocUnpackedRecord() */
- UnpackedRecord *pRet; /* Return value */
-
- pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo, 0, 0, &dummy);
- if( pRet ){
- memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nField+1));
- sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, pRet);
- }
- return pRet;
-}
-
-/*
-** This function is called from within a pre-update callback to retrieve
-** a field of the row currently being updated or deleted.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
- PreUpdate *p = db->pPreUpdate;
- int rc = SQLITE_OK;
-
- /* Test that this call is being made from within an SQLITE_DELETE or
- ** SQLITE_UPDATE pre-update callback, and that iIdx is within range. */
- if( !p || p->op==SQLITE_INSERT ){
- rc = SQLITE_MISUSE_BKPT;
- goto preupdate_old_out;
- }
- if( iIdx>=p->pCsr->nField || iIdx<0 ){
- rc = SQLITE_RANGE;
- goto preupdate_old_out;
- }
-
- /* If the old.* record has not yet been loaded into memory, do so now. */
- if( p->pUnpacked==0 ){
- u32 nRec;
- u8 *aRec;
-
- rc = sqlite3BtreeDataSize(p->pCsr->uc.pCursor, &nRec);
- if( rc!=SQLITE_OK ) goto preupdate_old_out;
- aRec = sqlite3DbMallocRaw(db, nRec);
- if( !aRec ) goto preupdate_old_out;
- rc = sqlite3BtreeData(p->pCsr->uc.pCursor, 0, nRec, aRec);
- if( rc==SQLITE_OK ){
- p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec);
- if( !p->pUnpacked ) rc = SQLITE_NOMEM;
- }
- if( rc!=SQLITE_OK ){
- sqlite3DbFree(db, aRec);
- goto preupdate_old_out;
- }
- p->aRecord = aRec;
- }
-
- if( iIdx>=p->pUnpacked->nField ){
- *ppValue = (sqlite3_value *)columnNullValue();
- }else{
- *ppValue = &p->pUnpacked->aMem[iIdx];
- if( iIdx==p->iPKey ){
- sqlite3VdbeMemSetInt64(*ppValue, p->iKey1);
- }
- }
-
- preupdate_old_out:
- sqlite3Error(db, rc);
- return sqlite3ApiExit(db, rc);
-}
-#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
-
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
-/*
-** This function is called from within a pre-update callback to retrieve
-** the number of columns in the row being updated, deleted or inserted.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3_preupdate_count(sqlite3 *db){
- PreUpdate *p = db->pPreUpdate;
- return (p ? p->keyinfo.nField : 0);
-}
-#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
-
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
-/*
-** This function is designed to be called from within a pre-update callback
-** only. It returns zero if the change that caused the callback was made
-** immediately by a user SQL statement. Or, if the change was made by a
-** trigger program, it returns the number of trigger programs currently
-** on the stack (1 for a top-level trigger, 2 for a trigger fired by a
-** top-level trigger etc.).
-**
-** For the purposes of the previous paragraph, a foreign key CASCADE, SET NULL
-** or SET DEFAULT action is considered a trigger.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3_preupdate_depth(sqlite3 *db){
- PreUpdate *p = db->pPreUpdate;
- return (p ? p->v->nFrame : 0);
-}
-#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
-
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
-/*
-** This function is called from within a pre-update callback to retrieve
-** a field of the row currently being updated or inserted.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
- PreUpdate *p = db->pPreUpdate;
- int rc = SQLITE_OK;
- Mem *pMem;
-
- if( !p || p->op==SQLITE_DELETE ){
- rc = SQLITE_MISUSE_BKPT;
- goto preupdate_new_out;
- }
- if( iIdx>=p->pCsr->nField || iIdx<0 ){
- rc = SQLITE_RANGE;
- goto preupdate_new_out;
- }
-
- if( p->op==SQLITE_INSERT ){
- /* For an INSERT, memory cell p->iNewReg contains the serialized record
- ** that is being inserted. Deserialize it. */
- UnpackedRecord *pUnpack = p->pNewUnpacked;
- if( !pUnpack ){
- Mem *pData = &p->v->aMem[p->iNewReg];
- rc = sqlite3VdbeMemExpandBlob(pData);
- if( rc!=SQLITE_OK ) goto preupdate_new_out;
- pUnpack = vdbeUnpackRecord(&p->keyinfo, pData->n, pData->z);
- if( !pUnpack ){
- rc = SQLITE_NOMEM;
- goto preupdate_new_out;
- }
- p->pNewUnpacked = pUnpack;
- }
- if( iIdx>=pUnpack->nField ){
- pMem = (sqlite3_value *)columnNullValue();
- }else{
- pMem = &pUnpack->aMem[iIdx];
- if( iIdx==p->iPKey ){
- sqlite3VdbeMemSetInt64(pMem, p->iKey2);
- }
- }
- }else{
- /* For an UPDATE, memory cell (p->iNewReg+1+iIdx) contains the required
- ** value. Make a copy of the cell contents and return a pointer to it.
- ** It is not safe to return a pointer to the memory cell itself as the
- ** caller may modify the value text encoding.
- */
- assert( p->op==SQLITE_UPDATE );
- if( !p->aNew ){
- p->aNew = (Mem *)sqlite3DbMallocZero(db, sizeof(Mem) * p->pCsr->nField);
- if( !p->aNew ){
- rc = SQLITE_NOMEM;
- goto preupdate_new_out;
- }
- }
- assert( iIdx>=0 && iIdx<p->pCsr->nField );
- pMem = &p->aNew[iIdx];
- if( pMem->flags==0 ){
- if( iIdx==p->iPKey ){
- sqlite3VdbeMemSetInt64(pMem, p->iKey2);
- }else{
- rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iIdx]);
- if( rc!=SQLITE_OK ) goto preupdate_new_out;
- }
- }
- }
- *ppValue = pMem;
-
- preupdate_new_out:
- sqlite3Error(db, rc);
- return sqlite3ApiExit(db, rc);
-}
-#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
-
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
/*
** Return status data for a single loop within query pStmt.
@@ -76410,8 +70571,6 @@ SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt
**
** The Vdbe parse-tree explainer is also found here.
*/
-/* #include "sqliteInt.h" */
-/* #include "vdbeInt.h" */
#ifndef SQLITE_OMIT_TRACE
@@ -76523,9 +70682,9 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
if( pVar->flags & MEM_Null ){
sqlite3StrAccumAppend(&out, "NULL", 4);
}else if( pVar->flags & MEM_Int ){
- sqlite3XPrintf(&out, "%lld", pVar->u.i);
+ sqlite3XPrintf(&out, 0, "%lld", pVar->u.i);
}else if( pVar->flags & MEM_Real ){
- sqlite3XPrintf(&out, "%!.15g", pVar->u.r);
+ sqlite3XPrintf(&out, 0, "%!.15g", pVar->u.r);
}else if( pVar->flags & MEM_Str ){
int nOut; /* Number of bytes of the string text to include in output */
#ifndef SQLITE_OMIT_UTF16
@@ -76546,17 +70705,17 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
while( nOut<pVar->n && (pVar->z[nOut]&0xc0)==0x80 ){ nOut++; }
}
#endif
- sqlite3XPrintf(&out, "'%.*q'", nOut, pVar->z);
+ sqlite3XPrintf(&out, 0, "'%.*q'", nOut, pVar->z);
#ifdef SQLITE_TRACE_SIZE_LIMIT
if( nOut<pVar->n ){
- sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut);
+ sqlite3XPrintf(&out, 0, "/*+%d bytes*/", pVar->n-nOut);
}
#endif
#ifndef SQLITE_OMIT_UTF16
if( enc!=SQLITE_UTF8 ) sqlite3VdbeMemRelease(&utf8);
#endif
}else if( pVar->flags & MEM_Zero ){
- sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
+ sqlite3XPrintf(&out, 0, "zeroblob(%d)", pVar->u.nZero);
}else{
int nOut; /* Number of bytes of the blob to include in output */
assert( pVar->flags & MEM_Blob );
@@ -76566,12 +70725,12 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
if( nOut>SQLITE_TRACE_SIZE_LIMIT ) nOut = SQLITE_TRACE_SIZE_LIMIT;
#endif
for(i=0; i<nOut; i++){
- sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
+ sqlite3XPrintf(&out, 0, "%02x", pVar->z[i]&0xff);
}
sqlite3StrAccumAppend(&out, "'", 1);
#ifdef SQLITE_TRACE_SIZE_LIMIT
if( nOut<pVar->n ){
- sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut);
+ sqlite3XPrintf(&out, 0, "/*+%d bytes*/", pVar->n-nOut);
}
#endif
}
@@ -76604,8 +70763,6 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
*/
-/* #include "sqliteInt.h" */
-/* #include "vdbeInt.h" */
/*
** Invoke this macro on memory cells just prior to changing the
@@ -76673,16 +70830,6 @@ static void updateMaxBlobsize(Mem *p){
#endif
/*
-** This macro evaluates to true if either the update hook or the preupdate
-** hook are enabled for database connect DB.
-*/
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
-# define HAS_UPDATE_HOOK(DB) ((DB)->xPreUpdateCallback||(DB)->xUpdateCallback)
-#else
-# define HAS_UPDATE_HOOK(DB) ((DB)->xUpdateCallback)
-#endif
-
-/*
** The next global variable is incremented each time the OP_Found opcode
** is executed. This is used to test whether or not the foreign key
** operation implemented using OP_FkIsZero is working. This variable
@@ -76761,7 +70908,7 @@ SQLITE_API int sqlite3_found_count = 0;
&& sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;}
/* Return true if the cursor was opened using the OP_OpenSorter opcode. */
-#define isSorter(x) ((x)->eCurType==CURTYPE_SORTER)
+#define isSorter(x) ((x)->pSorter!=0)
/*
** Allocate VdbeCursor number iCur. Return a pointer to it. Return NULL
@@ -76772,7 +70919,7 @@ static VdbeCursor *allocateCursor(
int iCur, /* Index of the new VdbeCursor */
int nField, /* Number of fields in the table or index */
int iDb, /* Database the cursor belongs to, or -1 */
- u8 eCurType /* Type of the new cursor */
+ int isBtreeCursor /* True for B-Tree. False for pseudo-table or vtab */
){
/* Find the memory cell that will be used to store the blob of memory
** required for this VdbeCursor structure. It is convenient to use a
@@ -76788,34 +70935,33 @@ static VdbeCursor *allocateCursor(
** be freed lazily via the sqlite3_release_memory() API. This
** minimizes the number of malloc calls made by the system.
**
- ** The memory cell for cursor 0 is aMem[0]. The rest are allocated from
- ** the top of the register space. Cursor 1 is at Mem[p->nMem-1].
- ** Cursor 2 is at Mem[p->nMem-2]. And so forth.
+ ** Memory cells for cursors are allocated at the top of the address
+ ** space. Memory cell (p->nMem) corresponds to cursor 0. Space for
+ ** cursor 1 is managed by memory cell (p->nMem-1), etc.
*/
- Mem *pMem = iCur>0 ? &p->aMem[p->nMem-iCur] : p->aMem;
+ Mem *pMem = &p->aMem[p->nMem-iCur];
int nByte;
VdbeCursor *pCx = 0;
nByte =
ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
- (eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0);
+ (isBtreeCursor?sqlite3BtreeCursorSize():0);
- assert( iCur>=0 && iCur<p->nCursor );
- if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/
+ assert( iCur<p->nCursor );
+ if( p->apCsr[iCur] ){
sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
p->apCsr[iCur] = 0;
}
if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){
p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z;
memset(pCx, 0, sizeof(VdbeCursor));
- pCx->eCurType = eCurType;
pCx->iDb = iDb;
pCx->nField = nField;
pCx->aOffset = &pCx->aType[nField];
- if( eCurType==CURTYPE_BTREE ){
- pCx->uc.pCursor = (BtCursor*)
+ if( isBtreeCursor ){
+ pCx->pCursor = (BtCursor*)
&pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField];
- sqlite3BtreeCursorZero(pCx->uc.pCursor);
+ sqlite3BtreeCursorZero(pCx->pCursor);
}
}
return pCx;
@@ -76867,7 +71013,7 @@ static void applyNumericAffinity(Mem *pRec, int bTryForInt){
** SQLITE_AFF_TEXT:
** Convert pRec to a text representation.
**
-** SQLITE_AFF_BLOB:
+** SQLITE_AFF_NONE:
** No-op. pRec is unchanged.
*/
static void applyAffinity(
@@ -76878,7 +71024,7 @@ static void applyAffinity(
if( affinity>=SQLITE_AFF_NUMERIC ){
assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL
|| affinity==SQLITE_AFF_NUMERIC );
- if( (pRec->flags & MEM_Int)==0 ){ /*OPTIMIZATION-IF-FALSE*/
+ if( (pRec->flags & MEM_Int)==0 ){
if( (pRec->flags & MEM_Real)==0 ){
if( pRec->flags & MEM_Str ) applyNumericAffinity(pRec,1);
}else{
@@ -76888,13 +71034,10 @@ static void applyAffinity(
}else if( affinity==SQLITE_AFF_TEXT ){
/* Only attempt the conversion to TEXT if there is an integer or real
** representation (blob and NULL do not get converted) but no string
- ** representation. It would be harmless to repeat the conversion if
- ** there is already a string rep, but it is pointless to waste those
- ** CPU cycles. */
- if( 0==(pRec->flags&MEM_Str) ){ /*OPTIMIZATION-IF-FALSE*/
- if( (pRec->flags&(MEM_Real|MEM_Int)) ){
- sqlite3VdbeMemStringify(pRec, enc, 1);
- }
+ ** representation.
+ */
+ if( 0==(pRec->flags&MEM_Str) && (pRec->flags&(MEM_Real|MEM_Int)) ){
+ sqlite3VdbeMemStringify(pRec, enc, 1);
}
pRec->flags &= ~(MEM_Real|MEM_Int);
}
@@ -77070,7 +71213,6 @@ static void memTracePrint(Mem *p){
sqlite3VdbeMemPrettyPrint(p, zBuf);
printf(" %s", zBuf);
}
- if( p->flags & MEM_Subtype ) printf(" subtype=0x%02x", p->eSubtype);
}
static void registerTrace(int iReg, Mem *p){
printf("REG[%d] = ", iReg);
@@ -77208,24 +71350,16 @@ static int checkSavepointCount(sqlite3 *db){
/*
** Return the register of pOp->p2 after first preparing it to be
** overwritten with an integer value.
-*/
-static SQLITE_NOINLINE Mem *out2PrereleaseWithClear(Mem *pOut){
- sqlite3VdbeMemSetNull(pOut);
- pOut->flags = MEM_Int;
- return pOut;
-}
+*/
static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){
Mem *pOut;
assert( pOp->p2>0 );
- assert( pOp->p2<=(p->nMem+1 - p->nCursor) );
+ assert( pOp->p2<=(p->nMem-p->nCursor) );
pOut = &p->aMem[pOp->p2];
memAboutToChange(p, pOut);
- if( VdbeMemDynamic(pOut) ){ /*OPTIMIZATION-IF-FALSE*/
- return out2PrereleaseWithClear(pOut);
- }else{
- pOut->flags = MEM_Int;
- return pOut;
- }
+ if( VdbeMemDynamic(pOut) ) sqlite3VdbeMemSetNull(pOut);
+ pOut->flags = MEM_Int;
+ return pOut;
}
@@ -77241,9 +71375,6 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
Op *pOrigOp; /* Value of pOp at the top of the loop */
#endif
-#ifdef SQLITE_DEBUG
- int nExtraDelete = 0; /* Verifies FORDELETE and AUXDELETE flags */
-#endif
int rc = SQLITE_OK; /* Value to return */
sqlite3 *db = p->db; /* The database */
u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */
@@ -77272,7 +71403,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
** sqlite3_column_text16() failed. */
goto no_mem;
}
- assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY );
+ assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY );
assert( p->bIsReader || p->readOnly!=0 );
p->rc = SQLITE_OK;
p->iCurrentTime = 0;
@@ -77283,9 +71414,13 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
sqlite3VdbeIOTraceSql(p);
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
if( db->xProgress ){
- u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP];
assert( 0 < db->nProgressOps );
- nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps);
+ nProgressLimit = (unsigned)p->aCounter[SQLITE_STMTSTATUS_VM_STEP];
+ if( nProgressLimit==0 ){
+ nProgressLimit = db->nProgressOps;
+ }else{
+ nProgressLimit %= (unsigned)db->nProgressOps;
+ }
}
#endif
#ifdef SQLITE_DEBUG
@@ -77315,12 +71450,9 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
}
sqlite3EndBenignMalloc();
#endif
- for(pOp=&aOp[p->pc]; 1; pOp++){
- /* Errors are detected by individual opcodes, with an immediate
- ** jumps to abort_due_to_error. */
- assert( rc==SQLITE_OK );
-
+ for(pOp=&aOp[p->pc]; rc==SQLITE_OK; pOp++){
assert( pOp>=aOp && pOp<&aOp[p->nOp]);
+ if( db->mallocFailed ) goto no_mem;
#ifdef VDBE_PROFILE
start = sqlite3Hwtime();
#endif
@@ -77352,39 +71484,37 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
/* Sanity checking on other operands */
#ifdef SQLITE_DEBUG
- {
- u8 opProperty = sqlite3OpcodeProperty[pOp->opcode];
- if( (opProperty & OPFLG_IN1)!=0 ){
- assert( pOp->p1>0 );
- assert( pOp->p1<=(p->nMem+1 - p->nCursor) );
- assert( memIsValid(&aMem[pOp->p1]) );
- assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) );
- REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]);
- }
- if( (opProperty & OPFLG_IN2)!=0 ){
- assert( pOp->p2>0 );
- assert( pOp->p2<=(p->nMem+1 - p->nCursor) );
- assert( memIsValid(&aMem[pOp->p2]) );
- assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p2]) );
- REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]);
- }
- if( (opProperty & OPFLG_IN3)!=0 ){
- assert( pOp->p3>0 );
- assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
- assert( memIsValid(&aMem[pOp->p3]) );
- assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p3]) );
- REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]);
- }
- if( (opProperty & OPFLG_OUT2)!=0 ){
- assert( pOp->p2>0 );
- assert( pOp->p2<=(p->nMem+1 - p->nCursor) );
- memAboutToChange(p, &aMem[pOp->p2]);
- }
- if( (opProperty & OPFLG_OUT3)!=0 ){
- assert( pOp->p3>0 );
- assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
- memAboutToChange(p, &aMem[pOp->p3]);
- }
+ assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] );
+ if( (pOp->opflags & OPFLG_IN1)!=0 ){
+ assert( pOp->p1>0 );
+ assert( pOp->p1<=(p->nMem-p->nCursor) );
+ assert( memIsValid(&aMem[pOp->p1]) );
+ assert( sqlite3VdbeCheckMemInvariants(&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-p->nCursor) );
+ assert( memIsValid(&aMem[pOp->p2]) );
+ assert( sqlite3VdbeCheckMemInvariants(&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-p->nCursor) );
+ assert( memIsValid(&aMem[pOp->p3]) );
+ assert( sqlite3VdbeCheckMemInvariants(&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-p->nCursor) );
+ memAboutToChange(p, &aMem[pOp->p2]);
+ }
+ if( (pOp->opflags & OPFLG_OUT3)!=0 ){
+ assert( pOp->p3>0 );
+ assert( pOp->p3<=(p->nMem-p->nCursor) );
+ memAboutToChange(p, &aMem[pOp->p3]);
}
#endif
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
@@ -77468,7 +71598,7 @@ check_for_interrupt:
nProgressLimit = nVmStep + db->nProgressOps - (nVmStep%db->nProgressOps);
if( db->xProgress(db->pProgressArg) ){
rc = SQLITE_INTERRUPT;
- goto abort_due_to_error;
+ goto vdbe_error_halt;
}
}
#endif
@@ -77482,7 +71612,7 @@ check_for_interrupt:
** and then jump to address P2.
*/
case OP_Gosub: { /* jump */
- assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
+ assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
pIn1 = &aMem[pOp->p1];
assert( VdbeMemDynamic(pIn1)==0 );
memAboutToChange(p, pIn1);
@@ -77522,7 +71652,7 @@ case OP_Return: { /* in1 */
** See also: EndCoroutine
*/
case OP_InitCoroutine: { /* jump */
- assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
+ assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
assert( pOp->p2>=0 && pOp->p2<p->nOp );
assert( pOp->p3>=0 && pOp->p3<p->nOp );
pOut = &aMem[pOp->p1];
@@ -77624,6 +71754,8 @@ case OP_HaltIfNull: { /* in3 */
** is the same as executing Halt.
*/
case OP_Halt: {
+ const char *zType;
+ const char *zLogFmt;
VdbeFrame *pFrame;
int pcx;
@@ -77652,28 +71784,35 @@ case OP_Halt: {
p->rc = pOp->p1;
p->errorAction = (u8)pOp->p2;
p->pc = pcx;
- assert( pOp->p5>=0 && pOp->p5<=4 );
if( p->rc ){
if( pOp->p5 ){
static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK",
"FOREIGN KEY" };
+ assert( pOp->p5>=1 && pOp->p5<=4 );
testcase( pOp->p5==1 );
testcase( pOp->p5==2 );
testcase( pOp->p5==3 );
testcase( pOp->p5==4 );
- sqlite3VdbeError(p, "%s constraint failed", azType[pOp->p5-1]);
- if( pOp->p4.z ){
- p->zErrMsg = sqlite3MPrintf(db, "%z: %s", p->zErrMsg, pOp->p4.z);
- }
+ zType = azType[pOp->p5-1];
+ }else{
+ zType = 0;
+ }
+ assert( zType!=0 || pOp->p4.z!=0 );
+ zLogFmt = "abort at %d in [%s]: %s";
+ if( zType && pOp->p4.z ){
+ sqlite3SetString(&p->zErrMsg, db, "%s constraint failed: %s",
+ zType, pOp->p4.z);
+ }else if( pOp->p4.z ){
+ sqlite3SetString(&p->zErrMsg, db, "%s", pOp->p4.z);
}else{
- sqlite3VdbeError(p, "%s", pOp->p4.z);
+ sqlite3SetString(&p->zErrMsg, db, "%s constraint failed", zType);
}
- sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg);
+ sqlite3_log(pOp->p1, zLogFmt, pcx, p->zSql, p->zErrMsg);
}
rc = sqlite3VdbeHalt(p);
assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR );
if( rc==SQLITE_BUSY ){
- p->rc = SQLITE_BUSY;
+ p->rc = rc = SQLITE_BUSY;
}else{
assert( rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT );
assert( rc==SQLITE_OK || db->nDeferredCons>0 || db->nDeferredImmCons>0 );
@@ -77739,7 +71878,7 @@ case OP_String8: { /* same as TK_STRING, out2 */
#ifndef SQLITE_OMIT_UTF16
if( encoding!=SQLITE_UTF8 ){
rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC);
- assert( rc==SQLITE_OK || rc==SQLITE_TOOBIG );
+ if( rc==SQLITE_TOOBIG ) goto too_big;
if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem;
assert( pOut->szMalloc>0 && pOut->zMalloc==pOut->z );
assert( VdbeMemDynamic(pOut)==0 );
@@ -77752,12 +71891,10 @@ case OP_String8: { /* same as TK_STRING, out2 */
pOp->p4.z = pOut->z;
pOp->p1 = pOut->n;
}
- testcase( rc==SQLITE_TOOBIG );
#endif
if( pOp->p1>db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
- assert( rc==SQLITE_OK );
/* Fall through to the next case, OP_String */
}
@@ -77766,12 +71903,10 @@ case OP_String8: { /* same as TK_STRING, out2 */
**
** The string value P4 of length P1 (bytes) is stored in register P2.
**
-** If P3 is not zero and the content of register P3 is equal to P5, then
+** If P5!=0 and the content of register P3 is greater than zero, then
** the datatype of the register P2 is converted to BLOB. The content is
** the same sequence of bytes, it is merely interpreted as a BLOB instead
-** of a string, as if it had been CAST. In other words:
-**
-** if( P3!=0 and reg[P3]==P5 ) reg[P2] := CAST(reg[P2] as BLOB)
+** of a string, as if it had been CAST.
*/
case OP_String: { /* out2 */
assert( pOp->p4.z!=0 );
@@ -77781,14 +71916,13 @@ case OP_String: { /* out2 */
pOut->n = pOp->p1;
pOut->enc = encoding;
UPDATE_MAX_BLOBSIZE(pOut);
-#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
- if( pOp->p3>0 ){
- assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
+ if( pOp->p5 ){
+ assert( pOp->p3>0 );
+ assert( pOp->p3<=(p->nMem-p->nCursor) );
pIn3 = &aMem[pOp->p3];
assert( pIn3->flags & MEM_Int );
- if( pIn3->u.i==pOp->p5 ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term;
+ if( pIn3->u.i ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term;
}
-#endif
break;
}
@@ -77809,7 +71943,7 @@ case OP_Null: { /* out2 */
u16 nullFlag;
pOut = out2Prerelease(p, pOp);
cnt = pOp->p3-pOp->p2;
- assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
+ assert( pOp->p3<=(p->nMem-p->nCursor) );
pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null;
while( cnt>0 ){
pOut++;
@@ -77830,7 +71964,7 @@ case OP_Null: { /* out2 */
** previously copied using OP_SCopy, the copies will continue to be valid.
*/
case OP_SoftNull: {
- assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
+ assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
pOut = &aMem[pOp->p1];
pOut->flags = (pOut->flags|MEM_Null)&~MEM_Undefined;
break;
@@ -77897,8 +72031,8 @@ case OP_Move: {
pIn1 = &aMem[p1];
pOut = &aMem[p2];
do{
- assert( pOut<=&aMem[(p->nMem+1 - p->nCursor)] );
- assert( pIn1<=&aMem[(p->nMem+1 - p->nCursor)] );
+ assert( pOut<=&aMem[(p->nMem-p->nCursor)] );
+ assert( pIn1<=&aMem[(p->nMem-p->nCursor)] );
assert( memIsValid(pIn1) );
memAboutToChange(p, pOut);
sqlite3VdbeMemMove(pOut, pIn1);
@@ -77968,22 +72102,6 @@ case OP_SCopy: { /* out2 */
break;
}
-/* Opcode: IntCopy P1 P2 * * *
-** Synopsis: r[P2]=r[P1]
-**
-** Transfer the integer value held in register P1 into register P2.
-**
-** This is an optimized version of SCopy that works only for integer
-** values.
-*/
-case OP_IntCopy: { /* out2 */
- pIn1 = &aMem[pOp->p1];
- assert( (pIn1->flags & MEM_Int)!=0 );
- pOut = &aMem[pOp->p2];
- sqlite3VdbeMemSetInt64(pOut, pIn1->u.i);
- break;
-}
-
/* Opcode: ResultRow P1 P2 * * *
** Synopsis: output=r[P1@P2]
**
@@ -77998,7 +72116,7 @@ case OP_ResultRow: {
int i;
assert( p->nResColumn==pOp->p2 );
assert( pOp->p1>0 );
- assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 );
+ assert( pOp->p1+pOp->p2<=(p->nMem-p->nCursor)+1 );
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
/* Run the progress counter just before returning.
@@ -78008,7 +72126,7 @@ case OP_ResultRow: {
&& db->xProgress(db->pProgressArg)!=0
){
rc = SQLITE_INTERRUPT;
- goto abort_due_to_error;
+ goto vdbe_error_halt;
}
#endif
@@ -78018,7 +72136,7 @@ case OP_ResultRow: {
if( SQLITE_OK!=(rc = sqlite3VdbeCheckFk(p, 0)) ){
assert( db->flags&SQLITE_CountRows );
assert( p->usesStmtJournal );
- goto abort_due_to_error;
+ break;
}
/* If the SQLITE_CountRows flag is set in sqlite3.flags mask, then
@@ -78038,7 +72156,9 @@ case OP_ResultRow: {
*/
assert( p->iStatement==0 || db->flags&SQLITE_CountRows );
rc = sqlite3VdbeCloseStatement(p, SAVEPOINT_RELEASE);
- assert( rc==SQLITE_OK );
+ if( NEVER(rc!=SQLITE_OK) ){
+ break;
+ }
/* Invalidate all ephemeral cursor row caches */
p->cacheCtr = (p->cacheCtr + 2)|1;
@@ -78263,10 +72383,10 @@ case OP_CollSeq: {
break;
}
-/* Opcode: Function0 P1 P2 P3 P4 P5
+/* Opcode: Function P1 P2 P3 P4 P5
** Synopsis: r[P3]=func(r[P2@P5])
**
-** Invoke a user function (P4 is a pointer to a FuncDef object that
+** Invoke a user function (P4 is a pointer to a Function structure that
** defines the function) with P5 arguments taken from register P2 and
** successors. The result of the function is stored in register P3.
** Register P3 must not be one of the function inputs.
@@ -78278,101 +72398,59 @@ case OP_CollSeq: {
** sqlite3_set_auxdata() API may be safely retained until the next
** invocation of this opcode.
**
-** See also: Function, AggStep, AggFinal
+** See also: AggStep and AggFinal
*/
-/* Opcode: Function P1 P2 P3 P4 P5
-** Synopsis: r[P3]=func(r[P2@P5])
-**
-** Invoke a user function (P4 is a pointer to an sqlite3_context object that
-** contains a pointer to the function to be run) with P5 arguments taken
-** from register P2 and successors. The result of the function is stored
-** in register P3. Register P3 must not be one of the function inputs.
-**
-** P1 is a 32-bit bitmask indicating whether or not each argument to the
-** function was determined to be constant at compile time. If the first
-** argument was constant then bit 0 of P1 is set. This is used to determine
-** whether meta data associated with a user function argument using the
-** sqlite3_set_auxdata() API may be safely retained until the next
-** invocation of this opcode.
-**
-** SQL functions are initially coded as OP_Function0 with P4 pointing
-** to a FuncDef object. But on first evaluation, the P4 operand is
-** automatically converted into an sqlite3_context object and the operation
-** changed to this OP_Function opcode. In this way, the initialization of
-** the sqlite3_context object occurs only once, rather than once for each
-** evaluation of the function.
-**
-** See also: Function0, AggStep, AggFinal
-*/
-case OP_Function0: {
- int n;
- sqlite3_context *pCtx;
-
- assert( pOp->p4type==P4_FUNCDEF );
- n = pOp->p5;
- assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
- assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) );
- assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
- pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
- if( pCtx==0 ) goto no_mem;
- pCtx->pOut = 0;
- pCtx->pFunc = pOp->p4.pFunc;
- pCtx->iOp = (int)(pOp - aOp);
- pCtx->pVdbe = p;
- pCtx->argc = n;
- pOp->p4type = P4_FUNCCTX;
- pOp->p4.pCtx = pCtx;
- pOp->opcode = OP_Function;
- /* Fall through into OP_Function */
-}
case OP_Function: {
int i;
- sqlite3_context *pCtx;
+ Mem *pArg;
+ sqlite3_context ctx;
+ sqlite3_value **apVal;
+ int n;
- assert( pOp->p4type==P4_FUNCCTX );
- pCtx = pOp->p4.pCtx;
+ n = pOp->p5;
+ apVal = p->apArg;
+ assert( apVal || n==0 );
+ assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
+ ctx.pOut = &aMem[pOp->p3];
+ memAboutToChange(p, ctx.pOut);
- /* If this function is inside of a trigger, the register array in aMem[]
- ** might change from one evaluation to the next. The next block of code
- ** checks to see if the register array has changed, and if so it
- ** reinitializes the relavant parts of the sqlite3_context object */
- pOut = &aMem[pOp->p3];
- if( pCtx->pOut != pOut ){
- pCtx->pOut = pOut;
- for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i];
+ assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) );
+ assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
+ pArg = &aMem[pOp->p2];
+ for(i=0; i<n; i++, pArg++){
+ assert( memIsValid(pArg) );
+ apVal[i] = pArg;
+ Deephemeralize(pArg);
+ REGISTER_TRACE(pOp->p2+i, pArg);
}
- memAboutToChange(p, pCtx->pOut);
-#ifdef SQLITE_DEBUG
- for(i=0; i<pCtx->argc; i++){
- assert( memIsValid(pCtx->argv[i]) );
- REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]);
- }
-#endif
- MemSetTypeFlag(pCtx->pOut, MEM_Null);
- pCtx->fErrorOrAux = 0;
+ assert( pOp->p4type==P4_FUNCDEF );
+ ctx.pFunc = pOp->p4.pFunc;
+ ctx.iOp = (int)(pOp - aOp);
+ ctx.pVdbe = p;
+ MemSetTypeFlag(ctx.pOut, MEM_Null);
+ ctx.fErrorOrAux = 0;
db->lastRowid = lastRowid;
- (*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */
- lastRowid = db->lastRowid; /* Remember rowid changes made by xSFunc */
+ (*ctx.pFunc->xFunc)(&ctx, n, apVal); /* IMP: R-24505-23230 */
+ lastRowid = db->lastRowid; /* Remember rowid changes made by xFunc */
/* If the function returned an error, throw an exception */
- if( pCtx->fErrorOrAux ){
- if( pCtx->isError ){
- sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut));
- rc = pCtx->isError;
+ if( ctx.fErrorOrAux ){
+ if( ctx.isError ){
+ sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(ctx.pOut));
+ rc = ctx.isError;
}
- sqlite3VdbeDeleteAuxData(db, &p->pAuxData, pCtx->iOp, pOp->p1);
- if( rc ) goto abort_due_to_error;
+ sqlite3VdbeDeleteAuxData(p, (int)(pOp - aOp), pOp->p1);
}
/* Copy the result of the function into register P3 */
- if( pOut->flags & (MEM_Str|MEM_Blob) ){
- sqlite3VdbeChangeEncoding(pCtx->pOut, encoding);
- if( sqlite3VdbeMemTooBig(pCtx->pOut) ) goto too_big;
+ sqlite3VdbeChangeEncoding(ctx.pOut, encoding);
+ if( sqlite3VdbeMemTooBig(ctx.pOut) ){
+ goto too_big;
}
- REGISTER_TRACE(pOp->p3, pCtx->pOut);
- UPDATE_MAX_BLOBSIZE(pCtx->pOut);
+ REGISTER_TRACE(pOp->p3, ctx.pOut);
+ UPDATE_MAX_BLOBSIZE(ctx.pOut);
break;
}
@@ -78535,9 +72613,9 @@ case OP_RealAffinity: { /* in1 */
** A NULL value is not changed by this routine. It remains NULL.
*/
case OP_Cast: { /* in1 */
- assert( pOp->p2>=SQLITE_AFF_BLOB && pOp->p2<=SQLITE_AFF_REAL );
+ assert( pOp->p2>=SQLITE_AFF_NONE && pOp->p2<=SQLITE_AFF_REAL );
testcase( pOp->p2==SQLITE_AFF_TEXT );
- testcase( pOp->p2==SQLITE_AFF_BLOB );
+ testcase( pOp->p2==SQLITE_AFF_NONE );
testcase( pOp->p2==SQLITE_AFF_NUMERIC );
testcase( pOp->p2==SQLITE_AFF_INTEGER );
testcase( pOp->p2==SQLITE_AFF_REAL );
@@ -78546,7 +72624,6 @@ case OP_Cast: { /* in1 */
rc = ExpandBlob(pIn1);
sqlite3VdbeMemCast(pIn1, pOp->p2, encoding);
UPDATE_MAX_BLOBSIZE(pIn1);
- if( rc ) goto abort_due_to_error;
break;
}
#endif /* SQLITE_OMIT_CAST */
@@ -78673,7 +72750,6 @@ 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_Null);
REGISTER_TRACE(pOp->p2, pOut);
}else{
@@ -78688,23 +72764,21 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
/* Neither operand is NULL. Do a comparison. */
affinity = pOp->p5 & SQLITE_AFF_MASK;
if( affinity>=SQLITE_AFF_NUMERIC ){
- if( (flags1 | flags3)&MEM_Str ){
- if( (flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
- applyNumericAffinity(pIn1,0);
- }
- if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
- applyNumericAffinity(pIn3,0);
- }
+ if( (pIn1->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
+ applyNumericAffinity(pIn1,0);
+ }
+ if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
+ applyNumericAffinity(pIn3,0);
}
}else if( affinity==SQLITE_AFF_TEXT ){
- if( (flags1 & MEM_Str)==0 && (flags1 & (MEM_Int|MEM_Real))!=0 ){
+ if( (pIn1->flags & MEM_Str)==0 && (pIn1->flags & (MEM_Int|MEM_Real))!=0 ){
testcase( pIn1->flags & MEM_Int );
testcase( pIn1->flags & MEM_Real );
sqlite3VdbeMemStringify(pIn1, encoding, 1);
testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) );
flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
}
- if( (flags3 & MEM_Str)==0 && (flags3 & (MEM_Int|MEM_Real))!=0 ){
+ if( (pIn3->flags & MEM_Str)==0 && (pIn3->flags & (MEM_Int|MEM_Real))!=0 ){
testcase( pIn3->flags & MEM_Int );
testcase( pIn3->flags & MEM_Real );
sqlite3VdbeMemStringify(pIn3, encoding, 1);
@@ -78713,14 +72787,15 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
}
}
assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 );
- if( flags1 & MEM_Zero ){
+ if( pIn1->flags & MEM_Zero ){
sqlite3VdbeMemExpandBlob(pIn1);
flags1 &= ~MEM_Zero;
}
- if( flags3 & MEM_Zero ){
+ if( pIn3->flags & MEM_Zero ){
sqlite3VdbeMemExpandBlob(pIn3);
flags3 &= ~MEM_Zero;
}
+ if( db->mallocFailed ) goto no_mem;
res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
}
switch( pOp->opcode ){
@@ -78761,14 +72836,11 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
** The permutation is only valid until the next OP_Compare that has
** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should
** occur immediately prior to the OP_Compare.
-**
-** The first integer in the P4 integer array is the length of the array
-** and does not become part of the permutation.
*/
case OP_Permutation: {
assert( pOp->p4type==P4_INTARRAY );
assert( pOp->p4.ai );
- aPermute = pOp->p4.ai + 1;
+ aPermute = pOp->p4.ai;
break;
}
@@ -78813,11 +72885,11 @@ case OP_Compare: {
if( aPermute ){
int k, mx = 0;
for(k=0; k<n; k++) if( aPermute[k]>mx ) mx = aPermute[k];
- assert( p1>0 && p1+mx<=(p->nMem+1 - p->nCursor)+1 );
- assert( p2>0 && p2+mx<=(p->nMem+1 - p->nCursor)+1 );
+ assert( p1>0 && p1+mx<=(p->nMem-p->nCursor)+1 );
+ assert( p2>0 && p2+mx<=(p->nMem-p->nCursor)+1 );
}else{
- assert( p1>0 && p1+n<=(p->nMem+1 - p->nCursor)+1 );
- assert( p2>0 && p2+n<=(p->nMem+1 - p->nCursor)+1 );
+ assert( p1>0 && p1+n<=(p->nMem-p->nCursor)+1 );
+ assert( p2>0 && p2+n<=(p->nMem-p->nCursor)+1 );
}
#endif /* SQLITE_DEBUG */
for(i=0; i<n; i++){
@@ -79068,35 +73140,36 @@ case OP_Column: {
const u8 *zHdr; /* Next unparsed byte of the header */
const u8 *zEndHdr; /* Pointer to first byte after the header */
u32 offset; /* Offset into the data */
- u64 offset64; /* 64-bit offset */
+ u32 szField; /* Number of bytes in the content of a field */
u32 avail; /* Number of bytes of available data */
u32 t; /* A type code from the record header */
+ u16 fx; /* pDest->flags value */
Mem *pReg; /* PseudoTable input register */
- pC = p->apCsr[pOp->p1];
p2 = pOp->p2;
-
- /* If the cursor cache is stale, bring it up-to-date */
- rc = sqlite3VdbeCursorMoveto(&pC, &p2);
-
- assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
+ assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
pDest = &aMem[pOp->p3];
memAboutToChange(p, pDest);
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( p2<pC->nField );
aOffset = pC->aOffset;
- assert( pC->eCurType!=CURTYPE_VTAB );
- assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
- assert( pC->eCurType!=CURTYPE_SORTER );
- pCrsr = pC->uc.pCursor;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ assert( pC->pVtabCursor==0 ); /* OP_Column never called on virtual table */
+#endif
+ pCrsr = pC->pCursor;
+ assert( pCrsr!=0 || pC->pseudoTableReg>0 ); /* pCrsr NULL on PseudoTables */
+ assert( pCrsr!=0 || pC->nullRow ); /* pC->nullRow on PseudoTables */
+ /* If the cursor cache is stale, bring it up-to-date */
+ rc = sqlite3VdbeCursorMoveto(pC);
if( rc ) goto abort_due_to_error;
if( pC->cacheStatus!=p->cacheCtr ){
if( pC->nullRow ){
- if( pC->eCurType==CURTYPE_PSEUDO ){
- assert( pC->uc.pseudoTableReg>0 );
- pReg = &aMem[pC->uc.pseudoTableReg];
+ if( pCrsr==0 ){
+ assert( pC->pseudoTableReg>0 );
+ pReg = &aMem[pC->pseudoTableReg];
assert( pReg->flags & MEM_Blob );
assert( memIsValid(pReg) );
pC->payloadSize = pC->szRow = avail = pReg->n;
@@ -79106,7 +73179,6 @@ case OP_Column: {
goto op_column_out;
}
}else{
- assert( pC->eCurType==CURTYPE_BTREE );
assert( pCrsr );
if( pC->isTable==0 ){
assert( sqlite3BtreeCursorIsValid(pCrsr) );
@@ -79127,17 +73199,31 @@ case OP_Column: {
assert( avail<=65536 ); /* Maximum page size is 64KiB */
if( pC->payloadSize <= (u32)avail ){
pC->szRow = pC->payloadSize;
- }else if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
- goto too_big;
}else{
pC->szRow = avail;
}
+ if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ goto too_big;
+ }
}
pC->cacheStatus = p->cacheCtr;
pC->iHdrOffset = getVarint32(pC->aRow, offset);
pC->nHdrParsed = 0;
aOffset[0] = offset;
+ /* Make sure a corrupt database has not given us an oversize header.
+ ** Do this now to avoid an oversize memory allocation.
+ **
+ ** Type entries can be between 1 and 5 bytes each. But 4 and 5 byte
+ ** types use so much data space that there can only be 4096 and 32 of
+ ** them, respectively. So the maximum header length results from a
+ ** 3-byte type for each of the maximum of 32768 columns plus three
+ ** extra bytes for the header length itself. 32768*3 + 3 = 98307.
+ */
+ if( offset > 98307 || offset > pC->payloadSize ){
+ rc = SQLITE_CORRUPT_BKPT;
+ goto op_column_error;
+ }
if( avail<offset ){
/* pC->aRow does not have to hold the entire row, but it does at least
@@ -79146,20 +73232,6 @@ case OP_Column: {
** dynamically allocated. */
pC->aRow = 0;
pC->szRow = 0;
-
- /* Make sure a corrupt database has not given us an oversize header.
- ** Do this now to avoid an oversize memory allocation.
- **
- ** Type entries can be between 1 and 5 bytes each. But 4 and 5 byte
- ** types use so much data space that there can only be 4096 and 32 of
- ** them, respectively. So the maximum header length results from a
- ** 3-byte type for each of the maximum of 32768 columns plus three
- ** extra bytes for the header length itself. 32768*3 + 3 = 98307.
- */
- if( offset > 98307 || offset > pC->payloadSize ){
- rc = SQLITE_CORRUPT_BKPT;
- goto abort_due_to_error;
- }
}
/* The following goto is an optimization. It can be omitted and
@@ -79182,8 +73254,11 @@ case OP_Column: {
/* Make sure zData points to enough of the record to cover the header. */
if( pC->aRow==0 ){
memset(&sMem, 0, sizeof(sMem));
- rc = sqlite3VdbeMemFromBtree(pCrsr, 0, aOffset[0], !pC->isTable, &sMem);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
+ rc = sqlite3VdbeMemFromBtree(pCrsr, 0, aOffset[0],
+ !pC->isTable, &sMem);
+ if( rc!=SQLITE_OK ){
+ goto op_column_error;
+ }
zData = (u8*)sMem.z;
}else{
zData = pC->aRow;
@@ -79191,40 +73266,48 @@ case OP_Column: {
/* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */
i = pC->nHdrParsed;
- offset64 = aOffset[i];
+ offset = aOffset[i];
zHdr = zData + pC->iHdrOffset;
zEndHdr = zData + aOffset[0];
assert( i<=p2 && zHdr<zEndHdr );
do{
- if( (t = zHdr[0])<0x80 ){
+ if( zHdr[0]<0x80 ){
+ t = zHdr[0];
zHdr++;
- offset64 += sqlite3VdbeOneByteSerialTypeLen(t);
}else{
zHdr += sqlite3GetVarint32(zHdr, &t);
- offset64 += sqlite3VdbeSerialTypeLen(t);
}
- pC->aType[i++] = t;
- aOffset[i] = (u32)(offset64 & 0xffffffff);
+ pC->aType[i] = t;
+ szField = sqlite3VdbeSerialTypeLen(t);
+ offset += szField;
+ if( offset<szField ){ /* True if offset overflows */
+ zHdr = &zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */
+ break;
+ }
+ i++;
+ aOffset[i] = offset;
}while( i<=p2 && zHdr<zEndHdr );
pC->nHdrParsed = i;
pC->iHdrOffset = (u32)(zHdr - zData);
+ if( pC->aRow==0 ){
+ sqlite3VdbeMemRelease(&sMem);
+ sMem.flags = MEM_Null;
+ }
/* The record is corrupt if any of the following are true:
** (1) the bytes of the header extend past the declared header size
+ ** (zHdr>zEndHdr)
** (2) the entire header was used but not all data was used
+ ** (zHdr==zEndHdr && offset!=pC->payloadSize)
** (3) the end of the data extends beyond the end of the record.
+ ** (offset > pC->payloadSize)
*/
- if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset64!=pC->payloadSize))
- || (offset64 > pC->payloadSize)
+ if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset!=pC->payloadSize))
+ || (offset > pC->payloadSize)
){
- if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem);
rc = SQLITE_CORRUPT_BKPT;
- goto abort_due_to_error;
+ goto op_column_error;
}
- if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem);
-
- }else{
- t = 0;
}
/* If after trying to extract new entries from the header, nHdrParsed is
@@ -79239,8 +73322,6 @@ case OP_Column: {
}
goto op_column_out;
}
- }else{
- t = pC->aType[p2];
}
/* Extract the content for the p2+1-th column. Control can only
@@ -79251,32 +73332,11 @@ case OP_Column: {
assert( rc==SQLITE_OK );
assert( sqlite3VdbeCheckMemInvariants(pDest) );
if( VdbeMemDynamic(pDest) ) sqlite3VdbeMemSetNull(pDest);
- assert( t==pC->aType[p2] );
- pDest->enc = encoding;
+ t = pC->aType[p2];
if( pC->szRow>=aOffset[p2+1] ){
/* This is the common case where the desired content fits on the original
** page - where the content is not on an overflow page */
- zData = pC->aRow + aOffset[p2];
- if( t<12 ){
- sqlite3VdbeSerialGet(zData, t, pDest);
- }else{
- /* If the column value is a string, we need a persistent value, not
- ** a MEM_Ephem value. This branch is a fast short-cut that is equivalent
- ** to calling sqlite3VdbeSerialGet() and sqlite3VdbeDeephemeralize().
- */
- static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term };
- pDest->n = len = (t-12)/2;
- if( pDest->szMalloc < len+2 ){
- pDest->flags = MEM_Null;
- if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem;
- }else{
- pDest->z = pDest->zMalloc;
- }
- memcpy(pDest->z, zData, len);
- pDest->z[len] = 0;
- pDest->z[len+1] = 0;
- pDest->flags = aFlag[t&1];
- }
+ sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], t, pDest);
}else{
/* This branch happens only when content is on overflow pages */
if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
@@ -79288,19 +73348,39 @@ case OP_Column: {
** 2. the length(X) function if X is a blob, and
** 3. if the content length is zero.
** So we might as well use bogus content rather than reading
- ** content from disk. */
- static u8 aZero[8]; /* This is the bogus content */
- sqlite3VdbeSerialGet(aZero, t, pDest);
+ ** content from disk. NULL will work for the value for strings
+ ** and blobs and whatever is in the payloadSize64 variable
+ ** will work for everything else. */
+ sqlite3VdbeSerialGet(t<=13 ? (u8*)&payloadSize64 : 0, t, pDest);
}else{
rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, !pC->isTable,
pDest);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
+ if( rc!=SQLITE_OK ){
+ goto op_column_error;
+ }
sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
pDest->flags &= ~MEM_Ephem;
}
}
+ pDest->enc = encoding;
op_column_out:
+ /* If the column value is an ephemeral string, go ahead and persist
+ ** that string in case the cursor moves before the column value is
+ ** used. The following code does the equivalent of Deephemeralize()
+ ** but does it faster. */
+ if( (pDest->flags & MEM_Ephem)!=0 && pDest->z ){
+ fx = pDest->flags & (MEM_Str|MEM_Blob);
+ assert( fx!=0 );
+ zData = (const u8*)pDest->z;
+ len = pDest->n;
+ if( sqlite3VdbeMemClearAndResize(pDest, len+2) ) goto no_mem;
+ memcpy(pDest->z, zData, len);
+ pDest->z[len] = 0;
+ pDest->z[len+1] = 0;
+ pDest->flags = fx|MEM_Term;
+ }
+op_column_error:
UPDATE_MAX_BLOBSIZE(pDest);
REGISTER_TRACE(pOp->p3, pDest);
break;
@@ -79324,7 +73404,7 @@ case OP_Affinity: {
assert( zAffinity[pOp->p2]==0 );
pIn1 = &aMem[pOp->p1];
while( (cAff = *(zAffinity++))!=0 ){
- assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] );
+ assert( pIn1 <= &p->aMem[(p->nMem-p->nCursor)] );
assert( memIsValid(pIn1) );
applyAffinity(pIn1, cAff, encoding);
pIn1++;
@@ -79346,7 +73426,7 @@ case OP_Affinity: {
** The mapping from character to affinity is given by the SQLITE_AFF_
** macros defined in sqliteInt.h.
**
-** If P4 is NULL then all index fields have the affinity BLOB.
+** If P4 is NULL then all index fields have the affinity NONE.
*/
case OP_MakeRecord: {
u8 *zNewRecord; /* A buffer to hold the data for the new record */
@@ -79364,7 +73444,7 @@ case OP_MakeRecord: {
int file_format; /* File format to use for encoding */
int i; /* Space used in zNewRecord[] header */
int j; /* Space used in zNewRecord[] content */
- u32 len; /* Length of a field */
+ int len; /* Length of a field */
/* Assuming the record contains N fields, the record format looks
** like this:
@@ -79386,7 +73466,7 @@ case OP_MakeRecord: {
nZero = 0; /* Number of zero bytes at the end of the record */
nField = pOp->p1;
zAffinity = pOp->p4.z;
- assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem+1 - p->nCursor)+1 );
+ assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem-p->nCursor)+1 );
pData0 = &aMem[nField];
nField = pOp->p2;
pLast = &pData0[nField-1];
@@ -79414,10 +73494,11 @@ case OP_MakeRecord: {
pRec = pLast;
do{
assert( memIsValid(pRec) );
- pRec->uTemp = serial_type = sqlite3VdbeSerialType(pRec, file_format, &len);
+ pRec->uTemp = serial_type = sqlite3VdbeSerialType(pRec, file_format);
+ len = sqlite3VdbeSerialTypeLen(serial_type);
if( pRec->flags & MEM_Zero ){
if( nData ){
- if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem;
+ sqlite3VdbeMemExpandBlob(pRec);
}else{
nZero += pRec->u.nZero;
len -= pRec->u.nZero;
@@ -79427,9 +73508,7 @@ case OP_MakeRecord: {
testcase( serial_type==127 );
testcase( serial_type==128 );
nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type);
- if( pRec==pData0 ) break;
- pRec--;
- }while(1);
+ }while( (--pRec)>=pData0 );
/* EVIDENCE-OF: R-22564-11647 The header begins with a single varint
** which determines the total number of bytes in the header. The varint
@@ -79478,7 +73557,7 @@ case OP_MakeRecord: {
assert( i==nHdr );
assert( j==nByte );
- assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
+ assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
pOut->n = (int)nByte;
pOut->flags = MEM_Blob;
if( nZero ){
@@ -79502,12 +73581,10 @@ case OP_Count: { /* out2 */
i64 nEntry;
BtCursor *pCrsr;
- assert( p->apCsr[pOp->p1]->eCurType==CURTYPE_BTREE );
- pCrsr = p->apCsr[pOp->p1]->uc.pCursor;
+ pCrsr = p->apCsr[pOp->p1]->pCursor;
assert( pCrsr );
nEntry = 0; /* Not needed. Only used to silence a warning. */
rc = sqlite3BtreeCount(pCrsr, &nEntry);
- if( rc ) goto abort_due_to_error;
pOut = out2Prerelease(p, pOp);
pOut->u.i = nEntry;
break;
@@ -79547,7 +73624,8 @@ case OP_Savepoint: {
/* A new savepoint cannot be created if there are active write
** statements (i.e. open read/write incremental blob handles).
*/
- sqlite3VdbeError(p, "cannot open savepoint - SQL statements in progress");
+ sqlite3SetString(&p->zErrMsg, db, "cannot open savepoint - "
+ "SQL statements in progress");
rc = SQLITE_BUSY;
}else{
nName = sqlite3Strlen30(zName);
@@ -79564,7 +73642,7 @@ case OP_Savepoint: {
#endif
/* Create a new savepoint structure. */
- pNew = sqlite3DbMallocRawNN(db, sizeof(Savepoint)+nName+1);
+ pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+nName+1);
if( pNew ){
pNew->zName = (char *)&pNew[1];
memcpy(pNew->zName, zName, nName+1);
@@ -79577,7 +73655,7 @@ case OP_Savepoint: {
}else{
db->nSavepoint++;
}
-
+
/* Link the new savepoint into the database handle's list. */
pNew->pNext = db->pSavepoint;
db->pSavepoint = pNew;
@@ -79598,14 +73676,15 @@ case OP_Savepoint: {
iSavepoint++;
}
if( !pSavepoint ){
- sqlite3VdbeError(p, "no such savepoint: %s", zName);
+ sqlite3SetString(&p->zErrMsg, db, "no such savepoint: %s", zName);
rc = SQLITE_ERROR;
}else if( db->nVdbeWrite>0 && p1==SAVEPOINT_RELEASE ){
/* It is not possible to release (commit) a savepoint if there are
** active write statements.
*/
- sqlite3VdbeError(p, "cannot release savepoint - "
- "SQL statements in progress");
+ sqlite3SetString(&p->zErrMsg, db,
+ "cannot release savepoint - SQL statements in progress"
+ );
rc = SQLITE_BUSY;
}else{
@@ -79685,7 +73764,6 @@ case OP_Savepoint: {
}
}
}
- if( rc ) goto abort_due_to_error;
break;
}
@@ -79702,37 +73780,49 @@ case OP_Savepoint: {
case OP_AutoCommit: {
int desiredAutoCommit;
int iRollback;
+ int turnOnAC;
desiredAutoCommit = pOp->p1;
iRollback = pOp->p2;
+ turnOnAC = desiredAutoCommit && !db->autoCommit;
assert( desiredAutoCommit==1 || desiredAutoCommit==0 );
assert( desiredAutoCommit==1 || iRollback==0 );
assert( db->nVdbeActive>0 ); /* At least this one VM is active */
assert( p->bIsReader );
- if( desiredAutoCommit!=db->autoCommit ){
+#if 0
+ if( turnOnAC && iRollback && db->nVdbeActive>1 ){
+ /* If this instruction implements a ROLLBACK and other VMs are
+ ** still running, and a transaction is active, return an error indicating
+ ** that the other VMs must complete first.
+ */
+ sqlite3SetString(&p->zErrMsg, db, "cannot rollback transaction - "
+ "SQL statements in progress");
+ rc = SQLITE_BUSY;
+ }else
+#endif
+ if( turnOnAC && !iRollback && db->nVdbeWrite>0 ){
+ /* If this instruction implements a COMMIT and other VMs are writing
+ ** return an error indicating that the other VMs must complete first.
+ */
+ sqlite3SetString(&p->zErrMsg, db, "cannot commit transaction - "
+ "SQL statements in progress");
+ rc = SQLITE_BUSY;
+ }else if( desiredAutoCommit!=db->autoCommit ){
if( iRollback ){
assert( desiredAutoCommit==1 );
sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
db->autoCommit = 1;
- }else if( desiredAutoCommit && db->nVdbeWrite>0 ){
- /* If this instruction implements a COMMIT and other VMs are writing
- ** return an error indicating that the other VMs must complete first.
- */
- sqlite3VdbeError(p, "cannot commit transaction - "
- "SQL statements in progress");
- rc = SQLITE_BUSY;
- goto abort_due_to_error;
}else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){
goto vdbe_return;
}else{
db->autoCommit = (u8)desiredAutoCommit;
- }
- if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
- p->pc = (int)(pOp - aOp);
- db->autoCommit = (u8)(1-desiredAutoCommit);
- p->rc = rc = SQLITE_BUSY;
- goto vdbe_return;
+ if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
+ p->pc = (int)(pOp - aOp);
+ db->autoCommit = (u8)(1-desiredAutoCommit);
+ p->rc = rc = SQLITE_BUSY;
+ goto vdbe_return;
+ }
}
assert( db->nStatement==0 );
sqlite3CloseSavepoints(db);
@@ -79743,13 +73833,12 @@ case OP_AutoCommit: {
}
goto vdbe_return;
}else{
- sqlite3VdbeError(p,
+ sqlite3SetString(&p->zErrMsg, db,
(!desiredAutoCommit)?"cannot start a transaction within a transaction":(
(iRollback)?"cannot rollback - no transaction is active":
"cannot commit - no transaction is active"));
rc = SQLITE_ERROR;
- goto abort_due_to_error;
}
break;
}
@@ -79805,11 +73894,9 @@ case OP_Transaction: {
if( pBt ){
rc = sqlite3BtreeBeginTrans(pBt, pOp->p2);
- testcase( rc==SQLITE_BUSY_SNAPSHOT );
- testcase( rc==SQLITE_BUSY_RECOVERY );
- if( (rc&0xff)==SQLITE_BUSY ){
+ if( rc==SQLITE_BUSY ){
p->pc = (int)(pOp - aOp);
- p->rc = rc;
+ p->rc = rc = SQLITE_BUSY;
goto vdbe_return;
}
if( rc!=SQLITE_OK ){
@@ -79872,7 +73959,6 @@ case OP_Transaction: {
p->expired = 1;
rc = SQLITE_SCHEMA;
}
- if( rc ) goto abort_due_to_error;
break;
}
@@ -79909,15 +73995,15 @@ case OP_ReadCookie: { /* out2 */
/* Opcode: SetCookie P1 P2 P3 * *
**
-** Write the integer value P3 into cookie number P2 of database P1.
-** P2==1 is the schema version. P2==2 is the database format.
-** P2==3 is the recommended pager cache
+** Write the content of register P3 (interpreted as an integer)
+** into cookie number P2 of database P1. P2==1 is the schema version.
+** P2==2 is the database format. P2==3 is the recommended pager cache
** size, and so forth. P1==0 is the main database file and P1==1 is the
** database file used to store temporary tables.
**
** A transaction must be started before executing this opcode.
*/
-case OP_SetCookie: {
+case OP_SetCookie: { /* in3 */
Db *pDb;
assert( pOp->p2<SQLITE_N_BTREE_META );
assert( pOp->p1>=0 && pOp->p1<db->nDb );
@@ -79926,15 +74012,17 @@ case OP_SetCookie: {
pDb = &db->aDb[pOp->p1];
assert( pDb->pBt!=0 );
assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) );
+ pIn3 = &aMem[pOp->p3];
+ sqlite3VdbeMemIntegerify(pIn3);
/* See note about index shifting on OP_ReadCookie */
- rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, pOp->p3);
+ rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, (int)pIn3->u.i);
if( pOp->p2==BTREE_SCHEMA_VERSION ){
/* When the schema cookie changes, record the new cookie internally */
- pDb->pSchema->schema_cookie = pOp->p3;
+ pDb->pSchema->schema_cookie = (int)pIn3->u.i;
db->flags |= SQLITE_InternChanges;
}else if( pOp->p2==BTREE_FILE_FORMAT ){
/* Record changes in the file format */
- pDb->pSchema->file_format = pOp->p3;
+ pDb->pSchema->file_format = (u8)pIn3->u.i;
}
if( pOp->p1==1 ){
/* Invalidate all prepared statements whenever the TEMP database
@@ -79942,7 +74030,6 @@ case OP_SetCookie: {
sqlite3ExpirePreparedStatements(db);
p->expired = 0;
}
- if( rc ) goto abort_due_to_error;
break;
}
@@ -80033,6 +74120,7 @@ case OP_ReopenIdx: {
case OP_OpenRead:
case OP_OpenWrite:
+ assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR|OPFLAG_SEEKEQ))==pOp->p5 );
assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ );
assert( p->bIsReader );
assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx
@@ -80040,7 +74128,7 @@ case OP_OpenWrite:
if( p->expired ){
rc = SQLITE_ABORT_ROLLBACK;
- goto abort_due_to_error;
+ break;
}
nField = 0;
@@ -80053,8 +74141,7 @@ case OP_OpenWrite:
pX = pDb->pBt;
assert( pX!=0 );
if( pOp->opcode==OP_OpenWrite ){
- assert( OPFLAG_FORDELETE==BTREE_FORDELETE );
- wrFlag = BTREE_WRCSR | (pOp->p5 & OPFLAG_FORDELETE);
+ wrFlag = 1;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( pDb->pSchema->file_format < p->minWriteFileFormat ){
p->minWriteFileFormat = pDb->pSchema->file_format;
@@ -80064,7 +74151,7 @@ case OP_OpenWrite:
}
if( pOp->p5 & OPFLAG_P2ISREG ){
assert( p2>0 );
- assert( p2<=(p->nMem+1 - p->nCursor) );
+ assert( p2<=(p->nMem-p->nCursor) );
pIn2 = &aMem[p2];
assert( memIsValid(pIn2) );
assert( (pIn2->flags & MEM_Int)!=0 );
@@ -80074,7 +74161,10 @@ case OP_OpenWrite:
** that opcode will always set the p2 value to 2 or more or else fail.
** If there were a failure, the prepared statement would have halted
** before reaching this instruction. */
- assert( p2>=2 );
+ if( NEVER(p2<2) ) {
+ rc = SQLITE_CORRUPT_BKPT;
+ goto abort_due_to_error;
+ }
}
if( pOp->p4type==P4_KEYINFO ){
pKeyInfo = pOp->p4.pKeyInfo;
@@ -80087,15 +74177,12 @@ case OP_OpenWrite:
assert( pOp->p1>=0 );
assert( nField>=0 );
testcase( nField==0 ); /* Table with INTEGER PRIMARY KEY and nothing else */
- pCur = allocateCursor(p, pOp->p1, nField, iDb, CURTYPE_BTREE);
+ pCur = allocateCursor(p, pOp->p1, nField, iDb, 1);
if( pCur==0 ) goto no_mem;
pCur->nullRow = 1;
pCur->isOrdered = 1;
pCur->pgnoRoot = p2;
-#ifdef SQLITE_DEBUG
- pCur->wrFlag = wrFlag;
-#endif
- rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->uc.pCursor);
+ rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor);
pCur->pKeyInfo = pKeyInfo;
/* Set the VdbeCursor.isTable variable. Previous versions of
** SQLite used to check if the root-page flags were sane at this point
@@ -80106,13 +74193,8 @@ case OP_OpenWrite:
open_cursor_set_hints:
assert( OPFLAG_BULKCSR==BTREE_BULKLOAD );
assert( OPFLAG_SEEKEQ==BTREE_SEEK_EQ );
- testcase( pOp->p5 & OPFLAG_BULKCSR );
-#ifdef SQLITE_ENABLE_CURSOR_HINTS
- testcase( pOp->p2 & OPFLAG_SEEKEQ );
-#endif
- sqlite3BtreeCursorHintFlags(pCur->uc.pCursor,
- (pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ)));
- if( rc ) goto abort_due_to_error;
+ sqlite3BtreeCursorHints(pCur->pCursor,
+ (pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ)));
break;
}
@@ -80155,7 +74237,7 @@ case OP_OpenEphemeral: {
SQLITE_OPEN_TRANSIENT_DB;
assert( pOp->p1>=0 );
assert( pOp->p2>=0 );
- pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_BTREE);
+ pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
pCx->isEphemeral = 1;
@@ -80179,17 +74261,14 @@ case OP_OpenEphemeral: {
assert( pKeyInfo->db==db );
assert( pKeyInfo->enc==ENC(db) );
pCx->pKeyInfo = pKeyInfo;
- rc = sqlite3BtreeCursor(pCx->pBt, pgno, BTREE_WRCSR,
- pKeyInfo, pCx->uc.pCursor);
+ rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, pKeyInfo, pCx->pCursor);
}
pCx->isTable = 0;
}else{
- rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, BTREE_WRCSR,
- 0, pCx->uc.pCursor);
+ rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, pCx->pCursor);
pCx->isTable = 1;
}
}
- if( rc ) goto abort_due_to_error;
pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
break;
}
@@ -80209,13 +74288,12 @@ case OP_SorterOpen: {
assert( pOp->p1>=0 );
assert( pOp->p2>=0 );
- pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_SORTER);
+ pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
if( pCx==0 ) goto no_mem;
pCx->pKeyInfo = pOp->p4.pKeyInfo;
assert( pCx->pKeyInfo->db==db );
assert( pCx->pKeyInfo->enc==ENC(db) );
rc = sqlite3VdbeSorterInit(db, pOp->p3, pCx);
- if( rc ) goto abort_due_to_error;
break;
}
@@ -80230,7 +74308,7 @@ case OP_SequenceTest: {
VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
- assert( isSorter(pC) );
+ assert( pC->pSorter );
if( (pC->seqCount++)==0 ){
goto jump_to_p2;
}
@@ -80258,10 +74336,10 @@ case OP_OpenPseudo: {
assert( pOp->p1>=0 );
assert( pOp->p3>=0 );
- pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, CURTYPE_PSEUDO);
+ pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0);
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
- pCx->uc.pseudoTableReg = pOp->p2;
+ pCx->pseudoTableReg = pOp->p2;
pCx->isTable = 1;
assert( pOp->p5==0 );
break;
@@ -80279,26 +74357,6 @@ case OP_Close: {
break;
}
-#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
-/* Opcode: ColumnsUsed P1 * * P4 *
-**
-** This opcode (which only exists if SQLite was compiled with
-** SQLITE_ENABLE_COLUMN_USED_MASK) identifies which columns of the
-** table or index for cursor P1 are used. P4 is a 64-bit integer
-** (P4_INT64) in which the first 63 bits are one for each of the
-** first 63 columns of the table or index that are actually used
-** by the cursor. The high-order bit is set if any column after
-** the 64th is used.
-*/
-case OP_ColumnsUsed: {
- VdbeCursor *pC;
- pC = p->apCsr[pOp->p1];
- assert( pC->eCurType==CURTYPE_BTREE );
- pC->maskUsed = *(u64*)pOp->p4.pI64;
- break;
-}
-#endif
-
/* Opcode: SeekGE P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
@@ -80311,13 +74369,6 @@ case OP_ColumnsUsed: {
** is greater than or equal to the key value. If there are no records
** greater than or equal to the key and P2 is not zero, then jump to P2.
**
-** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this
-** opcode will always land on a record that equally equals the key, or
-** else jump immediately to P2. When the cursor is OPFLAG_SEEKEQ, this
-** opcode must be followed by an IdxLE opcode with the same arguments.
-** The IdxLE opcode will be skipped if this opcode succeeds, but the
-** IdxLE opcode will be used on subsequent loop iterations.
-**
** This opcode leaves the cursor configured to move in forward order,
** from the beginning toward the end. In other words, the cursor is
** configured to use Next, not Prev.
@@ -80376,48 +74427,51 @@ case OP_ColumnsUsed: {
** from the end toward the beginning. In other words, the cursor is
** configured to use Prev, not Next.
**
-** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this
-** opcode will always land on a record that equally equals the key, or
-** else jump immediately to P2. When the cursor is OPFLAG_SEEKEQ, this
-** opcode must be followed by an IdxGE opcode with the same arguments.
-** The IdxGE opcode will be skipped if this opcode succeeds, but the
-** IdxGE opcode will be used on subsequent loop iterations.
-**
** See also: Found, NotFound, SeekGt, SeekGe, SeekLt
*/
case OP_SeekLT: /* jump, in3 */
case OP_SeekLE: /* jump, in3 */
case OP_SeekGE: /* jump, in3 */
case OP_SeekGT: { /* jump, in3 */
- int res; /* Comparison result */
- int oc; /* Opcode */
- VdbeCursor *pC; /* The cursor to seek */
- UnpackedRecord r; /* The key to seek for */
- int nField; /* Number of columns or fields in the key */
- i64 iKey; /* The rowid we are to seek to */
- int eqOnly; /* Only interested in == results */
+ int res;
+ int oc;
+ VdbeCursor *pC;
+ UnpackedRecord r;
+ int nField;
+ i64 iKey; /* The rowid we are to seek to */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p2!=0 );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
- assert( pC->eCurType==CURTYPE_BTREE );
+ assert( pC->pseudoTableReg==0 );
assert( OP_SeekLE == OP_SeekLT+1 );
assert( OP_SeekGE == OP_SeekLT+2 );
assert( OP_SeekGT == OP_SeekLT+3 );
assert( pC->isOrdered );
- assert( pC->uc.pCursor!=0 );
+ assert( pC->pCursor!=0 );
oc = pOp->opcode;
- eqOnly = 0;
pC->nullRow = 0;
#ifdef SQLITE_DEBUG
pC->seekOp = pOp->opcode;
#endif
+ /* For a cursor with the BTREE_SEEK_EQ hint, only the OP_SeekGE and
+ ** OP_SeekLE opcodes are allowed, and these must be immediately followed
+ ** by an OP_IdxGT or OP_IdxLT opcode, respectively, with the same key.
+ */
+#ifdef SQLITE_DEBUG
+ if( sqlite3BtreeCursorHasHint(pC->pCursor, BTREE_SEEK_EQ) ){
+ assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE );
+ assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
+ assert( pOp[1].p1==pOp[0].p1 );
+ assert( pOp[1].p2==pOp[0].p2 );
+ assert( pOp[1].p3==pOp[0].p3 );
+ assert( pOp[1].p4.i==pOp[0].p4.i );
+ }
+#endif
+
if( pC->isTable ){
- /* The BTREE_SEEK_EQ flag is only set on index cursors */
- assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0 );
-
/* The input value in P3 might be of any type: integer, real, string,
** blob, or NULL. But it needs to be an integer before we can do
** the seek, so convert it. */
@@ -80460,26 +74514,12 @@ case OP_SeekGT: { /* jump, in3 */
if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++;
}
}
- rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)iKey, 0, &res);
+ rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)iKey, 0, &res);
pC->movetoTarget = iKey; /* Used by OP_Delete */
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
}else{
- /* For a cursor with the BTREE_SEEK_EQ hint, only the OP_SeekGE and
- ** OP_SeekLE opcodes are allowed, and these must be immediately followed
- ** by an OP_IdxGT or OP_IdxLT opcode, respectively, with the same key.
- */
- if( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ) ){
- eqOnly = 1;
- assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE );
- assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
- assert( pOp[1].p1==pOp[0].p1 );
- assert( pOp[1].p2==pOp[0].p2 );
- assert( pOp[1].p3==pOp[0].p3 );
- assert( pOp[1].p4.i==pOp[0].p4.i );
- }
-
nField = pOp->p4.i;
assert( pOp->p4type==P4_INT32 );
assert( nField>0 );
@@ -80504,15 +74544,10 @@ case OP_SeekGT: { /* jump, in3 */
{ int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
#endif
ExpandBlob(r.aMem);
- r.eqSeen = 0;
- rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, &r, 0, 0, &res);
+ rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, &r, 0, 0, &res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- if( eqOnly && r.eqSeen==0 ){
- assert( res!=0 );
- goto seek_not_found;
- }
}
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
@@ -80522,7 +74557,7 @@ case OP_SeekGT: { /* jump, in3 */
if( oc>=OP_SeekGE ){ assert( oc==OP_SeekGE || oc==OP_SeekGT );
if( res<0 || (res==0 && oc==OP_SeekGT) ){
res = 0;
- rc = sqlite3BtreeNext(pC->uc.pCursor, &res);
+ rc = sqlite3BtreeNext(pC->pCursor, &res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
}else{
res = 0;
@@ -80531,26 +74566,47 @@ case OP_SeekGT: { /* jump, in3 */
assert( oc==OP_SeekLT || oc==OP_SeekLE );
if( res>0 || (res==0 && oc==OP_SeekLT) ){
res = 0;
- rc = sqlite3BtreePrevious(pC->uc.pCursor, &res);
+ rc = sqlite3BtreePrevious(pC->pCursor, &res);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
}else{
/* res might be negative because the table is empty. Check to
** see if this is the case.
*/
- res = sqlite3BtreeEof(pC->uc.pCursor);
+ res = sqlite3BtreeEof(pC->pCursor);
}
}
-seek_not_found:
assert( pOp->p2>0 );
VdbeBranchTaken(res!=0,2);
if( res ){
goto jump_to_p2;
- }else if( eqOnly ){
- assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
- pOp++; /* Skip the OP_IdxLt or OP_IdxGT that follows */
}
break;
}
+
+/* Opcode: Seek P1 P2 * * *
+** Synopsis: intkey=r[P2]
+**
+** P1 is an open table cursor and P2 is a rowid integer. Arrange
+** for P1 to move so that it points to the rowid given by P2.
+**
+** This is actually a deferred seek. Nothing actually happens until
+** the cursor is used to read a record. That way, if no reads
+** occur, no unnecessary I/O happens.
+*/
+case OP_Seek: { /* in2 */
+ VdbeCursor *pC;
+
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ pC = p->apCsr[pOp->p1];
+ assert( pC!=0 );
+ assert( pC->pCursor!=0 );
+ assert( pC->isTable );
+ pC->nullRow = 0;
+ pIn2 = &aMem[pOp->p2];
+ pC->movetoTarget = sqlite3VdbeIntValue(pIn2);
+ pC->deferredMoveto = 1;
+ break;
+}
/* Opcode: Found P1 P2 P3 P4 *
@@ -80637,8 +74693,7 @@ case OP_Found: { /* jump, in3 */
pC->seekOp = pOp->opcode;
#endif
pIn3 = &aMem[pOp->p3];
- assert( pC->eCurType==CURTYPE_BTREE );
- assert( pC->uc.pCursor!=0 );
+ assert( pC->pCursor!=0 );
assert( pC->isTable==0 );
pFree = 0;
if( pOp->p4.i>0 ){
@@ -80675,10 +74730,10 @@ case OP_Found: { /* jump, in3 */
}
}
}
- rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, pIdxKey, 0, 0, &res);
+ rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, pIdxKey, 0, 0, &res);
sqlite3DbFree(db, pFree);
if( rc!=SQLITE_OK ){
- goto abort_due_to_error;
+ break;
}
pC->seekResult = res;
alreadyExists = (res==0);
@@ -80700,10 +74755,9 @@ case OP_Found: { /* jump, in3 */
**
** P1 is the index of a cursor open on an SQL table btree (with integer
** keys). P3 is an integer rowid. If P1 does not contain a record with
-** rowid P3 then jump immediately to P2. Or, if P2 is 0, raise an
-** SQLITE_CORRUPT error. If P1 does contain a record with rowid P3 then
-** leave the cursor pointing at that record and fall through to the next
-** instruction.
+** rowid P3 then jump immediately to P2. If P1 does contain a record
+** with rowid P3 then leave the cursor pointing at that record and fall
+** through to the next instruction.
**
** The OP_NotFound opcode performs the same operation on index btrees
** (with arbitrary multi-value keys).
@@ -80729,28 +74783,19 @@ case OP_NotExists: { /* jump, in3 */
pC->seekOp = 0;
#endif
assert( pC->isTable );
- assert( pC->eCurType==CURTYPE_BTREE );
- pCrsr = pC->uc.pCursor;
+ assert( pC->pseudoTableReg==0 );
+ pCrsr = pC->pCursor;
assert( pCrsr!=0 );
res = 0;
iKey = pIn3->u.i;
rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res);
- assert( rc==SQLITE_OK || res==0 );
pC->movetoTarget = iKey; /* Used by OP_Delete */
pC->nullRow = 0;
pC->cacheStatus = CACHE_STALE;
pC->deferredMoveto = 0;
VdbeBranchTaken(res!=0,2);
pC->seekResult = res;
- if( res!=0 ){
- assert( rc==SQLITE_OK );
- if( pOp->p2==0 ){
- rc = SQLITE_CORRUPT_BKPT;
- }else{
- goto jump_to_p2;
- }
- }
- if( rc ) goto abort_due_to_error;
+ if( res!=0 ) goto jump_to_p2;
break;
}
@@ -80765,7 +74810,6 @@ case OP_NotExists: { /* jump, in3 */
case OP_Sequence: { /* out2 */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( p->apCsr[pOp->p1]!=0 );
- assert( p->apCsr[pOp->p1]->eCurType!=CURTYPE_VTAB );
pOut = out2Prerelease(p, pOp);
pOut->u.i = p->apCsr[pOp->p1]->seqCount++;
break;
@@ -80801,9 +74845,9 @@ case OP_NewRowid: { /* out2 */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
- assert( pC->eCurType==CURTYPE_BTREE );
- assert( pC->uc.pCursor!=0 );
- {
+ if( NEVER(pC->pCursor==0) ){
+ /* The zero initialization above is all that is needed */
+ }else{
/* The next rowid or record number (different terms for the same
** thing) is obtained in a two-step algorithm.
**
@@ -80830,15 +74874,15 @@ case OP_NewRowid: { /* out2 */
#endif
if( !pC->useRandomRowid ){
- rc = sqlite3BtreeLast(pC->uc.pCursor, &res);
+ rc = sqlite3BtreeLast(pC->pCursor, &res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
if( res ){
v = 1; /* IMP: R-61914-48074 */
}else{
- assert( sqlite3BtreeCursorIsValid(pC->uc.pCursor) );
- rc = sqlite3BtreeKeySize(pC->uc.pCursor, &v);
+ assert( sqlite3BtreeCursorIsValid(pC->pCursor) );
+ rc = sqlite3BtreeKeySize(pC->pCursor, &v);
assert( rc==SQLITE_OK ); /* Cannot fail following BtreeLast() */
if( v>=MAX_ROWID ){
pC->useRandomRowid = 1;
@@ -80859,7 +74903,7 @@ case OP_NewRowid: { /* out2 */
pMem = &pFrame->aMem[pOp->p3];
}else{
/* Assert that P3 is a valid memory cell. */
- assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
+ assert( pOp->p3<=(p->nMem-p->nCursor) );
pMem = &aMem[pOp->p3];
memAboutToChange(p, pMem);
}
@@ -80889,12 +74933,11 @@ case OP_NewRowid: { /* out2 */
do{
sqlite3_randomness(sizeof(v), &v);
v &= (MAX_ROWID>>1); v++; /* Ensure that v is greater than zero */
- }while( ((rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)v,
+ }while( ((rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)v,
0, &res))==SQLITE_OK)
&& (res==0)
&& (++cnt<100));
- if( rc ) goto abort_due_to_error;
- if( res==0 ){
+ if( rc==SQLITE_OK && res==0 ){
rc = SQLITE_FULL; /* IMP: R-38219-53002 */
goto abort_due_to_error;
}
@@ -80934,9 +74977,9 @@ case OP_NewRowid: { /* out2 */
** is part of an INSERT operation. The difference is only important to
** the update hook.
**
-** Parameter P4 may point to a Table structure, or may be NULL. If it is
-** not NULL, then the update-hook (sqlite3.xUpdateCallback) is invoked
-** following a successful insert.
+** Parameter P4 may point to a string containing the table-name, or
+** may be NULL. If it is not NULL, then the update-hook
+** (sqlite3.xUpdateCallback) is invoked following a successful insert.
**
** (WARNING/TODO: If P1 is a pseudo-cursor and P2 is dynamically
** allocated, then ownership of P2 is transferred to the pseudo-cursor
@@ -80962,19 +75005,17 @@ case OP_InsertInt: {
int nZero; /* Number of zero-bytes to append */
int seekResult; /* Result of prior seek or 0 if no USESEEKRESULT flag */
const char *zDb; /* database name - used by the update hook */
- Table *pTab; /* Table structure - used by update and pre-update hooks */
+ const char *zTbl; /* Table name - used by the opdate hook */
int op; /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */
- op = 0;
pData = &aMem[pOp->p2];
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( memIsValid(pData) );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
- assert( pC->eCurType==CURTYPE_BTREE );
- assert( pC->uc.pCursor!=0 );
+ assert( pC->pCursor!=0 );
+ assert( pC->pseudoTableReg==0 );
assert( pC->isTable );
- assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC );
REGISTER_TRACE(pOp->p2, pData);
if( pOp->opcode==OP_Insert ){
@@ -80988,28 +75029,6 @@ case OP_InsertInt: {
iKey = pOp->p3;
}
- if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){
- assert( pC->isTable );
- assert( pC->iDb>=0 );
- zDb = db->aDb[pC->iDb].zName;
- pTab = pOp->p4.pTab;
- assert( HasRowid(pTab) );
- op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
- }else{
- pTab = 0; /* Not needed. Silence a comiler warning. */
- zDb = 0; /* Not needed. Silence a compiler warning. */
- }
-
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
- /* Invoke the pre-update hook, if any */
- if( db->xPreUpdateCallback
- && pOp->p4type==P4_TABLE
- && !(pOp->p5 & OPFLAG_ISUPDATE)
- ){
- sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, iKey, pOp->p2);
- }
-#endif
-
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = iKey;
if( pData->flags & MEM_Null ){
@@ -81024,7 +75043,7 @@ case OP_InsertInt: {
}else{
nZero = 0;
}
- rc = sqlite3BtreeInsert(pC->uc.pCursor, 0, iKey,
+ rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey,
pData->z, pData->n, nZero,
(pOp->p5 & OPFLAG_APPEND)!=0, seekResult
);
@@ -81032,137 +75051,67 @@ case OP_InsertInt: {
pC->cacheStatus = CACHE_STALE;
/* Invoke the update-hook if required. */
- if( rc ) goto abort_due_to_error;
- if( db->xUpdateCallback && op ){
- db->xUpdateCallback(db->pUpdateArg, op, zDb, pTab->zName, iKey);
+ if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){
+ zDb = db->aDb[pC->iDb].zName;
+ zTbl = pOp->p4.z;
+ op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
+ assert( pC->isTable );
+ db->xUpdateCallback(db->pUpdateArg, op, zDb, zTbl, iKey);
+ assert( pC->iDb>=0 );
}
break;
}
-/* Opcode: Delete P1 P2 P3 P4 P5
+/* Opcode: Delete P1 P2 * P4 *
**
** Delete the record at which the P1 cursor is currently pointing.
**
-** If the OPFLAG_SAVEPOSITION bit of the P5 parameter is set, then
-** the cursor will be left pointing at either the next or the previous
+** The cursor will be left pointing at either the next or the previous
** record in the table. If it is left pointing at the next record, then
-** the next Next instruction will be a no-op. As a result, in this case
-** it is ok to delete a record from within a Next loop. If
-** OPFLAG_SAVEPOSITION bit of P5 is clear, then the cursor will be
-** left in an undefined state.
+** the next Next instruction will be a no-op. Hence it is OK to delete
+** a record from within a Next loop.
**
-** If the OPFLAG_AUXDELETE bit is set on P5, that indicates that this
-** delete one of several associated with deleting a table row and all its
-** associated index entries. Exactly one of those deletes is the "primary"
-** delete. The others are all on OPFLAG_FORDELETE cursors or else are
-** marked with the AUXDELETE flag.
-**
-** If the OPFLAG_NCHANGE flag of P2 (NB: P2 not P5) is set, then the row
-** change count is incremented (otherwise not).
+** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
+** incremented (otherwise not).
**
** P1 must not be pseudo-table. It has to be a real table with
** multiple rows.
**
-** If P4 is not NULL then it points to a Table struture. In this case either
-** the update or pre-update hook, or both, may be invoked. The P1 cursor must
-** have been positioned using OP_NotFound prior to invoking this opcode in
-** this case. Specifically, if one is configured, the pre-update hook is
-** invoked if P4 is not NULL. The update-hook is invoked if one is configured,
-** P4 is not NULL, and the OPFLAG_NCHANGE flag is set in P2.
-**
-** If the OPFLAG_ISUPDATE flag is set in P2, then P3 contains the address
-** of the memory cell that contains the value that the rowid of the row will
-** be set to by the update.
+** If P4 is not NULL, then it is the name of the table that P1 is
+** pointing to. The update hook will be invoked, if it exists.
+** If P4 is not NULL then the P1 cursor must have been positioned
+** using OP_NotFound prior to invoking this opcode.
*/
case OP_Delete: {
VdbeCursor *pC;
- const char *zDb;
- Table *pTab;
- int opflags;
- opflags = pOp->p2;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
- assert( pC->eCurType==CURTYPE_BTREE );
- assert( pC->uc.pCursor!=0 );
+ assert( pC->pCursor!=0 ); /* Only valid for real tables, no pseudotables */
assert( pC->deferredMoveto==0 );
#ifdef SQLITE_DEBUG
- if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 ){
- /* If p5 is zero, the seek operation that positioned the cursor prior to
- ** OP_Delete will have also set the pC->movetoTarget field to the rowid of
- ** the row that is being deleted */
+ /* The seek operation that positioned the cursor prior to OP_Delete will
+ ** have also set the pC->movetoTarget field to the rowid of the row that
+ ** is being deleted */
+ if( pOp->p4.z && pC->isTable ){
i64 iKey = 0;
- sqlite3BtreeKeySize(pC->uc.pCursor, &iKey);
- assert( pC->movetoTarget==iKey );
+ sqlite3BtreeKeySize(pC->pCursor, &iKey);
+ assert( pC->movetoTarget==iKey );
}
#endif
-
- /* If the update-hook or pre-update-hook will be invoked, set zDb to
- ** the name of the db to pass as to it. Also set local pTab to a copy
- ** of p4.pTab. Finally, if p5 is true, indicating that this cursor was
- ** last moved with OP_Next or OP_Prev, not Seek or NotFound, set
- ** VdbeCursor.movetoTarget to the current rowid. */
- if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){
- assert( pC->iDb>=0 );
- assert( pOp->p4.pTab!=0 );
- zDb = db->aDb[pC->iDb].zName;
- pTab = pOp->p4.pTab;
- if( (pOp->p5 & OPFLAG_SAVEPOSITION)!=0 && pC->isTable ){
- sqlite3BtreeKeySize(pC->uc.pCursor, &pC->movetoTarget);
- }
- }else{
- zDb = 0; /* Not needed. Silence a compiler warning. */
- pTab = 0; /* Not needed. Silence a compiler warning. */
- }
-
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
- /* Invoke the pre-update-hook if required. */
- if( db->xPreUpdateCallback && pOp->p4.pTab && HasRowid(pTab) ){
- assert( !(opflags & OPFLAG_ISUPDATE) || (aMem[pOp->p3].flags & MEM_Int) );
- sqlite3VdbePreUpdateHook(p, pC,
- (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE,
- zDb, pTab, pC->movetoTarget,
- pOp->p3
- );
- }
- if( opflags & OPFLAG_ISNOOP ) break;
-#endif
- /* Only flags that can be set are SAVEPOISTION and AUXDELETE */
- assert( (pOp->p5 & ~(OPFLAG_SAVEPOSITION|OPFLAG_AUXDELETE))==0 );
- assert( OPFLAG_SAVEPOSITION==BTREE_SAVEPOSITION );
- assert( OPFLAG_AUXDELETE==BTREE_AUXDELETE );
-
-#ifdef SQLITE_DEBUG
- if( p->pFrame==0 ){
- if( pC->isEphemeral==0
- && (pOp->p5 & OPFLAG_AUXDELETE)==0
- && (pC->wrFlag & OPFLAG_FORDELETE)==0
- ){
- nExtraDelete++;
- }
- if( pOp->p2 & OPFLAG_NCHANGE ){
- nExtraDelete--;
- }
- }
-#endif
-
- rc = sqlite3BtreeDelete(pC->uc.pCursor, pOp->p5);
+ rc = sqlite3BtreeDelete(pC->pCursor);
pC->cacheStatus = CACHE_STALE;
- if( rc ) goto abort_due_to_error;
/* Invoke the update-hook if required. */
- if( opflags & OPFLAG_NCHANGE ){
- p->nChange++;
- if( db->xUpdateCallback && HasRowid(pTab) ){
- db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, pTab->zName,
- pC->movetoTarget);
- assert( pC->iDb>=0 );
- }
+ if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z && pC->isTable ){
+ db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE,
+ db->aDb[pC->iDb].zName, pOp->p4.z, pC->movetoTarget);
+ assert( pC->iDb>=0 );
}
-
+ if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
break;
}
/* Opcode: ResetCount * * * * *
@@ -81206,7 +75155,6 @@ case OP_SorterCompare: {
res = 0;
rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res);
VdbeBranchTaken(res!=0,2);
- if( rc ) goto abort_due_to_error;
if( res ) goto jump_to_p2;
break;
};
@@ -81232,7 +75180,6 @@ case OP_SorterData: {
rc = sqlite3VdbeSorterRowkey(pC, pOut);
assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- if( rc ) goto abort_due_to_error;
p->apCsr[pOp->p3]->cacheStatus = CACHE_STALE;
break;
}
@@ -81272,14 +75219,14 @@ case OP_RowData: {
/* Note that RowKey and RowData are really exactly the same instruction */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
- assert( pC!=0 );
- assert( pC->eCurType==CURTYPE_BTREE );
assert( isSorter(pC)==0 );
assert( pC->isTable || pOp->opcode!=OP_RowData );
assert( pC->isTable==0 || pOp->opcode==OP_RowData );
+ assert( pC!=0 );
assert( pC->nullRow==0 );
- assert( pC->uc.pCursor!=0 );
- pCrsr = pC->uc.pCursor;
+ assert( pC->pseudoTableReg==0 );
+ assert( pC->pCursor!=0 );
+ pCrsr = pC->pCursor;
/* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or
** OP_Rewind/Op_Next with no intervening instructions that might invalidate
@@ -81321,7 +75268,6 @@ case OP_RowData: {
}else{
rc = sqlite3BtreeData(pCrsr, 0, n, pOut->z);
}
- if( rc ) goto abort_due_to_error;
pOut->enc = SQLITE_UTF8; /* In case the blob is ever cast to text */
UPDATE_MAX_BLOBSIZE(pOut);
REGISTER_TRACE(pOp->p2, pOut);
@@ -81348,32 +75294,29 @@ case OP_Rowid: { /* out2 */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
- assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
+ assert( pC->pseudoTableReg==0 || pC->nullRow );
if( pC->nullRow ){
pOut->flags = MEM_Null;
break;
}else if( pC->deferredMoveto ){
v = pC->movetoTarget;
#ifndef SQLITE_OMIT_VIRTUALTABLE
- }else if( pC->eCurType==CURTYPE_VTAB ){
- assert( pC->uc.pVCur!=0 );
- pVtab = pC->uc.pVCur->pVtab;
+ }else if( pC->pVtabCursor ){
+ pVtab = pC->pVtabCursor->pVtab;
pModule = pVtab->pModule;
assert( pModule->xRowid );
- rc = pModule->xRowid(pC->uc.pVCur, &v);
+ rc = pModule->xRowid(pC->pVtabCursor, &v);
sqlite3VtabImportErrmsg(p, pVtab);
- if( rc ) goto abort_due_to_error;
#endif /* SQLITE_OMIT_VIRTUALTABLE */
}else{
- assert( pC->eCurType==CURTYPE_BTREE );
- assert( pC->uc.pCursor!=0 );
+ assert( pC->pCursor!=0 );
rc = sqlite3VdbeCursorRestore(pC);
if( rc ) goto abort_due_to_error;
if( pC->nullRow ){
pOut->flags = MEM_Null;
break;
}
- rc = sqlite3BtreeKeySize(pC->uc.pCursor, &v);
+ rc = sqlite3BtreeKeySize(pC->pCursor, &v);
assert( rc==SQLITE_OK ); /* Always so because of CursorRestore() above */
}
pOut->u.i = v;
@@ -81394,9 +75337,8 @@ case OP_NullRow: {
assert( pC!=0 );
pC->nullRow = 1;
pC->cacheStatus = CACHE_STALE;
- if( pC->eCurType==CURTYPE_BTREE ){
- assert( pC->uc.pCursor!=0 );
- sqlite3BtreeClearCursor(pC->uc.pCursor);
+ if( pC->pCursor ){
+ sqlite3BtreeClearCursor(pC->pCursor);
}
break;
}
@@ -81421,8 +75363,7 @@ case OP_Last: { /* jump */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
- assert( pC->eCurType==CURTYPE_BTREE );
- pCrsr = pC->uc.pCursor;
+ pCrsr = pC->pCursor;
res = 0;
assert( pCrsr!=0 );
rc = sqlite3BtreeLast(pCrsr, &res);
@@ -81433,7 +75374,6 @@ case OP_Last: { /* jump */
#ifdef SQLITE_DEBUG
pC->seekOp = OP_Last;
#endif
- if( rc ) goto abort_due_to_error;
if( pOp->p2>0 ){
VdbeBranchTaken(res!=0,2);
if( res ) goto jump_to_p2;
@@ -81491,14 +75431,12 @@ case OP_Rewind: { /* jump */
if( isSorter(pC) ){
rc = sqlite3VdbeSorterRewind(pC, &res);
}else{
- assert( pC->eCurType==CURTYPE_BTREE );
- pCrsr = pC->uc.pCursor;
+ pCrsr = pC->pCursor;
assert( pCrsr );
rc = sqlite3BtreeFirst(pCrsr, &res);
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
}
- if( rc ) goto abort_due_to_error;
pC->nullRow = (u8)res;
assert( pOp->p2>0 && pOp->p2<p->nOp );
VdbeBranchTaken(res!=0,2);
@@ -81590,7 +75528,7 @@ case OP_Next: /* jump */
res = pOp->p3;
assert( pC!=0 );
assert( pC->deferredMoveto==0 );
- assert( pC->eCurType==CURTYPE_BTREE );
+ assert( pC->pCursor );
assert( res==0 || (res==1 && pC->isTable==0) );
testcase( res==1 );
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
@@ -81607,11 +75545,10 @@ case OP_Next: /* jump */
|| pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE
|| pC->seekOp==OP_Last );
- rc = pOp->p4.xAdvance(pC->uc.pCursor, &res);
+ rc = pOp->p4.xAdvance(pC->pCursor, &res);
next_tail:
pC->cacheStatus = CACHE_STALE;
VdbeBranchTaken(res==0,2);
- if( rc ) goto abort_due_to_error;
if( res==0 ){
pC->nullRow = 0;
p->aCounter[pOp->p5]++;
@@ -81649,6 +75586,7 @@ next_tail:
case OP_SorterInsert: /* in2 */
case OP_IdxInsert: { /* in2 */
VdbeCursor *pC;
+ BtCursor *pCrsr;
int nKey;
const char *zKey;
@@ -81658,23 +75596,24 @@ case OP_IdxInsert: { /* in2 */
assert( isSorter(pC)==(pOp->opcode==OP_SorterInsert) );
pIn2 = &aMem[pOp->p2];
assert( pIn2->flags & MEM_Blob );
+ pCrsr = pC->pCursor;
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
- assert( pC->eCurType==CURTYPE_BTREE || pOp->opcode==OP_SorterInsert );
+ assert( pCrsr!=0 );
assert( pC->isTable==0 );
rc = ExpandBlob(pIn2);
- if( rc ) goto abort_due_to_error;
- if( pOp->opcode==OP_SorterInsert ){
- rc = sqlite3VdbeSorterWrite(pC, pIn2);
- }else{
- nKey = pIn2->n;
- zKey = pIn2->z;
- rc = sqlite3BtreeInsert(pC->uc.pCursor, zKey, nKey, "", 0, 0, pOp->p3,
- ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
- );
- assert( pC->deferredMoveto==0 );
- pC->cacheStatus = CACHE_STALE;
+ if( rc==SQLITE_OK ){
+ if( isSorter(pC) ){
+ rc = sqlite3VdbeSorterWrite(pC, pIn2);
+ }else{
+ nKey = pIn2->n;
+ zKey = pIn2->z;
+ rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0, 0, pOp->p3,
+ ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
+ );
+ assert( pC->deferredMoveto==0 );
+ pC->cacheStatus = CACHE_STALE;
+ }
}
- if( rc) goto abort_due_to_error;
break;
}
@@ -81692,48 +75631,29 @@ case OP_IdxDelete: {
UnpackedRecord r;
assert( pOp->p3>0 );
- assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem+1 - p->nCursor)+1 );
+ assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem-p->nCursor)+1 );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
- assert( pC->eCurType==CURTYPE_BTREE );
- pCrsr = pC->uc.pCursor;
+ pCrsr = pC->pCursor;
assert( pCrsr!=0 );
assert( pOp->p5==0 );
r.pKeyInfo = pC->pKeyInfo;
r.nField = (u16)pOp->p3;
r.default_rc = 0;
r.aMem = &aMem[pOp->p2];
+#ifdef SQLITE_DEBUG
+ { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
+#endif
rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res);
- if( rc ) goto abort_due_to_error;
- if( res==0 ){
- rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
- if( rc ) goto abort_due_to_error;
+ if( rc==SQLITE_OK && res==0 ){
+ rc = sqlite3BtreeDelete(pCrsr);
}
assert( pC->deferredMoveto==0 );
pC->cacheStatus = CACHE_STALE;
break;
}
-/* Opcode: Seek P1 * P3 P4 *
-** Synopsis: Move P3 to P1.rowid
-**
-** P1 is an open index cursor and P3 is a cursor on the corresponding
-** table. This opcode does a deferred seek of the P3 table cursor
-** to the row that corresponds to the current row of P1.
-**
-** This is a deferred seek. Nothing actually happens until
-** the cursor is used to read a record. That way, if no reads
-** occur, no unnecessary I/O happens.
-**
-** P4 may be an array of integers (type P4_INTARRAY) containing
-** one entry for each column in the P3 table. If array entry a(i)
-** is non-zero, then reading column a(i)-1 from cursor P3 is
-** equivalent to performing the deferred seek and then reading column i
-** from P1. This information is stored in P3 and used to redirect
-** reads against P3 over to P1, thus possibly avoiding the need to
-** seek and read cursor P3.
-*/
/* Opcode: IdxRowid P1 P2 * * *
** Synopsis: r[P2]=rowid
**
@@ -81743,57 +75663,36 @@ case OP_IdxDelete: {
**
** See also: Rowid, MakeRecord.
*/
-case OP_Seek:
case OP_IdxRowid: { /* out2 */
- VdbeCursor *pC; /* The P1 index cursor */
- VdbeCursor *pTabCur; /* The P2 table cursor (OP_Seek only) */
- i64 rowid; /* Rowid that P1 current points to */
+ BtCursor *pCrsr;
+ VdbeCursor *pC;
+ i64 rowid;
+ pOut = out2Prerelease(p, pOp);
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
- assert( pC->eCurType==CURTYPE_BTREE );
- assert( pC->uc.pCursor!=0 );
+ pCrsr = pC->pCursor;
+ assert( pCrsr!=0 );
+ pOut->flags = MEM_Null;
assert( pC->isTable==0 );
assert( pC->deferredMoveto==0 );
- assert( !pC->nullRow || pOp->opcode==OP_IdxRowid );
-
- /* The IdxRowid and Seek opcodes are combined because of the commonality
- ** of sqlite3VdbeCursorRestore() and sqlite3VdbeIdxRowid(). */
- rc = sqlite3VdbeCursorRestore(pC);
/* sqlite3VbeCursorRestore() can only fail if the record has been deleted
- ** out from under the cursor. That will never happens for an IdxRowid
- ** or Seek opcode */
+ ** out from under the cursor. That will never happend for an IdxRowid
+ ** opcode, hence the NEVER() arround the check of the return value.
+ */
+ rc = sqlite3VdbeCursorRestore(pC);
if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
if( !pC->nullRow ){
rowid = 0; /* Not needed. Only used to silence a warning. */
- rc = sqlite3VdbeIdxRowid(db, pC->uc.pCursor, &rowid);
+ rc = sqlite3VdbeIdxRowid(db, pCrsr, &rowid);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- if( pOp->opcode==OP_Seek ){
- assert( pOp->p3>=0 && pOp->p3<p->nCursor );
- pTabCur = p->apCsr[pOp->p3];
- assert( pTabCur!=0 );
- assert( pTabCur->eCurType==CURTYPE_BTREE );
- assert( pTabCur->uc.pCursor!=0 );
- assert( pTabCur->isTable );
- pTabCur->nullRow = 0;
- pTabCur->movetoTarget = rowid;
- pTabCur->deferredMoveto = 1;
- assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 );
- pTabCur->aAltMap = pOp->p4.ai;
- pTabCur->pAltCursor = pC;
- }else{
- pOut = out2Prerelease(p, pOp);
- pOut->u.i = rowid;
- pOut->flags = MEM_Int;
- }
- }else{
- assert( pOp->opcode==OP_IdxRowid );
- sqlite3VdbeMemSetNull(&aMem[pOp->p2]);
+ pOut->u.i = rowid;
+ pOut->flags = MEM_Int;
}
break;
}
@@ -81854,8 +75753,7 @@ case OP_IdxGE: { /* jump */
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->isOrdered );
- assert( pC->eCurType==CURTYPE_BTREE );
- assert( pC->uc.pCursor!=0);
+ assert( pC->pCursor!=0);
assert( pC->deferredMoveto==0 );
assert( pOp->p5==0 || pOp->p5==1 );
assert( pOp->p4type==P4_INT32 );
@@ -81883,7 +75781,6 @@ case OP_IdxGE: { /* jump */
res++;
}
VdbeBranchTaken(res>0,2);
- if( rc ) goto abort_due_to_error;
if( res>0 ) goto jump_to_p2;
break;
}
@@ -81913,13 +75810,11 @@ case OP_Destroy: { /* out2 */
int iDb;
assert( p->readOnly==0 );
- assert( pOp->p1>1 );
pOut = out2Prerelease(p, pOp);
pOut->flags = MEM_Null;
if( db->nVdbeRead > db->nVDestroy+1 ){
rc = SQLITE_LOCKED;
p->errorAction = OE_Abort;
- goto abort_due_to_error;
}else{
iDb = pOp->p3;
assert( DbMaskTest(p->btreeMask, iDb) );
@@ -81927,9 +75822,8 @@ case OP_Destroy: { /* out2 */
rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved);
pOut->flags = MEM_Int;
pOut->u.i = iMoved;
- if( rc ) goto abort_due_to_error;
#ifndef SQLITE_OMIT_AUTOVACUUM
- if( iMoved!=0 ){
+ if( rc==SQLITE_OK && iMoved!=0 ){
sqlite3RootPageMoved(db, iDb, iMoved, pOp->p1);
/* All OP_Destroy operations occur on the same btree */
assert( resetSchemaOnFault==0 || resetSchemaOnFault==iDb+1 );
@@ -81975,7 +75869,6 @@ case OP_Clear: {
aMem[pOp->p3].u.i += nChange;
}
}
- if( rc ) goto abort_due_to_error;
break;
}
@@ -81993,13 +75886,11 @@ case OP_ResetSorter: {
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
- if( isSorter(pC) ){
- sqlite3VdbeSorterReset(db, pC->uc.pSorter);
+ if( pC->pSorter ){
+ sqlite3VdbeSorterReset(db, pC->pSorter);
}else{
- assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->isEphemeral );
- rc = sqlite3BtreeClearTableOfCursor(pC->uc.pCursor);
- if( rc ) goto abort_due_to_error;
+ rc = sqlite3BtreeClearTableOfCursor(pC->pCursor);
}
break;
}
@@ -82048,7 +75939,6 @@ case OP_CreateTable: { /* out2 */
flags = BTREE_BLOBKEY;
}
rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags);
- if( rc ) goto abort_due_to_error;
pOut->u.i = pgno;
break;
}
@@ -82089,7 +75979,7 @@ case OP_ParseSchema: {
"SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
db->aDb[iDb].zName, zMaster, pOp->p4.z);
if( zSql==0 ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}else{
assert( db->init.busy==0 );
db->init.busy = 1;
@@ -82101,12 +75991,9 @@ case OP_ParseSchema: {
db->init.busy = 0;
}
}
- if( rc ){
- sqlite3ResetAllSchemasOfConnection(db);
- if( rc==SQLITE_NOMEM ){
- goto no_mem;
- }
- goto abort_due_to_error;
+ if( rc ) sqlite3ResetAllSchemasOfConnection(db);
+ if( rc==SQLITE_NOMEM ){
+ goto no_mem;
}
break;
}
@@ -82121,7 +76008,6 @@ case OP_ParseSchema: {
case OP_LoadAnalysis: {
assert( pOp->p1>=0 && pOp->p1<db->nDb );
rc = sqlite3AnalysisLoad(db, pOp->p1);
- if( rc ) goto abort_due_to_error;
break;
}
#endif /* !defined(SQLITE_OMIT_ANALYZE) */
@@ -82167,7 +76053,7 @@ case OP_DropTrigger: {
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
-/* Opcode: IntegrityCk P1 P2 P3 P4 P5
+/* Opcode: IntegrityCk P1 P2 P3 * P5
**
** Do an analysis of the currently open database. Store in
** register P1 the text of an error message describing any problems.
@@ -82178,8 +76064,9 @@ case OP_DropTrigger: {
** In other words, the analysis stops as soon as reg(P1) errors are
** seen. Reg(P1) is updated with the number of errors remaining.
**
-** The root page numbers of all tables in the database are integers
-** stored in P4_INTARRAY argument.
+** The root page numbers of all tables in the database are integer
+** stored in reg(P1), reg(P1+1), reg(P1+2), .... There are P2 tables
+** total.
**
** If P5 is not zero, the check is done on the auxiliary database
** file, not the main database file.
@@ -82189,24 +76076,30 @@ case OP_DropTrigger: {
case OP_IntegrityCk: {
int nRoot; /* Number of tables to check. (Number of root pages.) */
int *aRoot; /* Array of rootpage numbers for tables to be checked */
+ int j; /* Loop counter */
int nErr; /* Number of errors reported */
char *z; /* Text of the error report */
Mem *pnErr; /* Register keeping track of errors remaining */
assert( p->bIsReader );
nRoot = pOp->p2;
- aRoot = pOp->p4.ai;
assert( nRoot>0 );
- assert( aRoot[nRoot]==0 );
- assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
+ aRoot = sqlite3DbMallocRaw(db, sizeof(int)*(nRoot+1) );
+ if( aRoot==0 ) goto no_mem;
+ assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
pnErr = &aMem[pOp->p3];
assert( (pnErr->flags & MEM_Int)!=0 );
assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
pIn1 = &aMem[pOp->p1];
+ for(j=0; j<nRoot; j++){
+ aRoot[j] = (int)sqlite3VdbeIntValue(&pIn1[j]);
+ }
+ aRoot[j] = 0;
assert( pOp->p5<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p5) );
z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot,
(int)pnErr->u.i, &nErr);
+ sqlite3DbFree(db, aRoot);
pnErr->u.i -= nErr;
sqlite3VdbeMemSetNull(pIn1);
if( nErr==0 ){
@@ -82373,8 +76266,8 @@ case OP_Program: { /* jump */
if( p->nFrame>=db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){
rc = SQLITE_ERROR;
- sqlite3VdbeError(p, "too many levels of trigger recursion");
- goto abort_due_to_error;
+ sqlite3SetString(&p->zErrMsg, db, "too many levels of trigger recursion");
+ break;
}
/* Register pRt is used to store the memory required to save the state
@@ -82388,8 +76281,6 @@ case OP_Program: { /* jump */
** variable nMem (and later, VdbeFrame.nChildMem) to this value.
*/
nMem = pProgram->nMem + pProgram->nCsr;
- assert( nMem>0 );
- if( pProgram->nCsr==0 ) nMem++;
nByte = ROUND8(sizeof(VdbeFrame))
+ nMem * sizeof(Mem)
+ pProgram->nCsr * sizeof(VdbeCursor *)
@@ -82426,8 +76317,7 @@ case OP_Program: { /* jump */
}
}else{
pFrame = pRt->u.pFrame;
- assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem
- || (pProgram->nCsr==0 && pProgram->nMem+1==pFrame->nChildMem) );
+ assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem );
assert( pProgram->nCsr==pFrame->nChildCsr );
assert( (int)(pOp - aOp)==pFrame->pc );
}
@@ -82437,15 +76327,12 @@ case OP_Program: { /* jump */
pFrame->lastRowid = lastRowid;
pFrame->nChange = p->nChange;
pFrame->nDbChange = p->db->nChange;
- assert( pFrame->pAuxData==0 );
- pFrame->pAuxData = p->pAuxData;
- p->pAuxData = 0;
p->nChange = 0;
p->pFrame = pFrame;
- p->aMem = aMem = VdbeFrameMem(pFrame);
+ p->aMem = aMem = &VdbeFrameMem(pFrame)[-1];
p->nMem = pFrame->nChildMem;
p->nCursor = (u16)pFrame->nChildCsr;
- p->apCsr = (VdbeCursor **)&aMem[p->nMem];
+ p->apCsr = (VdbeCursor **)&aMem[p->nMem+1];
p->aOp = aOp = pProgram->aOp;
p->nOp = pProgram->nOp;
p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor];
@@ -82558,12 +76445,12 @@ case OP_MemMax: { /* in2 */
}
#endif /* SQLITE_OMIT_AUTOINCREMENT */
-/* Opcode: IfPos P1 P2 P3 * *
-** Synopsis: if r[P1]>0 then r[P1]-=P3, goto P2
+/* Opcode: IfPos P1 P2 * * *
+** Synopsis: if r[P1]>0 goto P2
**
** Register P1 must contain an integer.
-** If the value of register P1 is 1 or greater, subtract P3 from the
-** value in P1 and jump to P2.
+** If the value of register P1 is 1 or greater, jump to P2 and
+** add the literal value P3 to register P1.
**
** If the initial value of register P1 is less than 1, then the
** value is unchanged and control passes through to the next instruction.
@@ -82572,55 +76459,38 @@ case OP_IfPos: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
VdbeBranchTaken( pIn1->u.i>0, 2);
- if( pIn1->u.i>0 ){
- pIn1->u.i -= pOp->p3;
- goto jump_to_p2;
- }
+ if( pIn1->u.i>0 ) goto jump_to_p2;
break;
}
-/* Opcode: OffsetLimit P1 P2 P3 * *
-** Synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)
+/* Opcode: IfNeg P1 P2 P3 * *
+** Synopsis: r[P1]+=P3, if r[P1]<0 goto P2
**
-** This opcode performs a commonly used computation associated with
-** LIMIT and OFFSET process. r[P1] holds the limit counter. r[P3]
-** holds the offset counter. The opcode computes the combined value
-** of the LIMIT and OFFSET and stores that value in r[P2]. The r[P2]
-** value computed is the total number of rows that will need to be
-** visited in order to complete the query.
-**
-** If r[P3] is zero or negative, that means there is no OFFSET
-** and r[P2] is set to be the value of the LIMIT, r[P1].
-**
-** if r[P1] is zero or negative, that means there is no LIMIT
-** and r[P2] is set to -1.
-**
-** Otherwise, r[P2] is set to the sum of r[P1] and r[P3].
+** Register P1 must contain an integer. Add literal P3 to the value in
+** register P1 then if the value of register P1 is less than zero, jump to P2.
*/
-case OP_OffsetLimit: { /* in1, out2, in3 */
+case OP_IfNeg: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
- pIn3 = &aMem[pOp->p3];
- pOut = out2Prerelease(p, pOp);
- assert( pIn1->flags & MEM_Int );
- assert( pIn3->flags & MEM_Int );
- pOut->u.i = pIn1->u.i<=0 ? -1 : pIn1->u.i+(pIn3->u.i>0?pIn3->u.i:0);
+ assert( pIn1->flags&MEM_Int );
+ pIn1->u.i += pOp->p3;
+ VdbeBranchTaken(pIn1->u.i<0, 2);
+ if( pIn1->u.i<0 ) goto jump_to_p2;
break;
}
/* Opcode: IfNotZero P1 P2 P3 * *
-** Synopsis: if r[P1]!=0 then r[P1]-=P3, goto P2
+** Synopsis: if r[P1]!=0 then r[P1]+=P3, goto P2
**
** Register P1 must contain an integer. If the content of register P1 is
-** initially nonzero, then subtract P3 from the value in register P1 and
-** jump to P2. If register P1 is initially zero, leave it unchanged
-** and fall through.
+** initially nonzero, then add P3 to P1 and jump to P2. If register P1 is
+** initially zero, leave it unchanged and fall through.
*/
case OP_IfNotZero: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
VdbeBranchTaken(pIn1->u.i<0, 2);
if( pIn1->u.i ){
- pIn1->u.i -= pOp->p3;
+ pIn1->u.i += pOp->p3;
goto jump_to_p2;
}
break;
@@ -82642,102 +76512,72 @@ case OP_DecrJumpZero: { /* jump, in1 */
}
-/* Opcode: AggStep0 * P2 P3 P4 P5
-** Synopsis: accum=r[P3] step(r[P2@P5])
-**
-** Execute the step function for an aggregate. The
-** function has P5 arguments. P4 is a pointer to the FuncDef
-** structure that specifies the function. Register P3 is the
-** accumulator.
+/* Opcode: JumpZeroIncr P1 P2 * * *
+** Synopsis: if (r[P1]++)==0 ) goto P2
**
-** The P5 arguments are taken from register P2 and its
-** successors.
+** The register P1 must contain an integer. If register P1 is initially
+** zero, then jump to P2. Increment register P1 regardless of whether or
+** not the jump is taken.
*/
+case OP_JumpZeroIncr: { /* jump, in1 */
+ pIn1 = &aMem[pOp->p1];
+ assert( pIn1->flags&MEM_Int );
+ VdbeBranchTaken(pIn1->u.i==0, 2);
+ if( (pIn1->u.i++)==0 ) goto jump_to_p2;
+ break;
+}
+
/* Opcode: AggStep * P2 P3 P4 P5
** Synopsis: accum=r[P3] step(r[P2@P5])
**
** Execute the step function for an aggregate. The
-** function has P5 arguments. P4 is a pointer to an sqlite3_context
-** object that is used to run the function. Register P3 is
-** as the accumulator.
+** function has P5 arguments. P4 is a pointer to the FuncDef
+** structure that specifies the function. Use register
+** P3 as the accumulator.
**
** The P5 arguments are taken from register P2 and its
** successors.
-**
-** This opcode is initially coded as OP_AggStep0. On first evaluation,
-** the FuncDef stored in P4 is converted into an sqlite3_context and
-** the opcode is changed. In this way, the initialization of the
-** sqlite3_context only happens once, instead of on each call to the
-** step function.
*/
-case OP_AggStep0: {
- int n;
- sqlite3_context *pCtx;
-
- assert( pOp->p4type==P4_FUNCDEF );
- n = pOp->p5;
- assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
- assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) );
- assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
- pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
- if( pCtx==0 ) goto no_mem;
- pCtx->pMem = 0;
- pCtx->pFunc = pOp->p4.pFunc;
- pCtx->iOp = (int)(pOp - aOp);
- pCtx->pVdbe = p;
- pCtx->argc = n;
- pOp->p4type = P4_FUNCCTX;
- pOp->p4.pCtx = pCtx;
- pOp->opcode = OP_AggStep;
- /* Fall through into OP_AggStep */
-}
case OP_AggStep: {
+ int n;
int i;
- sqlite3_context *pCtx;
Mem *pMem;
+ Mem *pRec;
Mem t;
+ sqlite3_context ctx;
+ sqlite3_value **apVal;
- assert( pOp->p4type==P4_FUNCCTX );
- pCtx = pOp->p4.pCtx;
- pMem = &aMem[pOp->p3];
-
- /* If this function is inside of a trigger, the register array in aMem[]
- ** might change from one evaluation to the next. The next block of code
- ** checks to see if the register array has changed, and if so it
- ** reinitializes the relavant parts of the sqlite3_context object */
- if( pCtx->pMem != pMem ){
- pCtx->pMem = pMem;
- for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i];
- }
-
-#ifdef SQLITE_DEBUG
- for(i=0; i<pCtx->argc; i++){
- assert( memIsValid(pCtx->argv[i]) );
- REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]);
+ n = pOp->p5;
+ assert( n>=0 );
+ pRec = &aMem[pOp->p2];
+ apVal = p->apArg;
+ assert( apVal || n==0 );
+ for(i=0; i<n; i++, pRec++){
+ assert( memIsValid(pRec) );
+ apVal[i] = pRec;
+ memAboutToChange(p, pRec);
}
-#endif
-
+ ctx.pFunc = pOp->p4.pFunc;
+ assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
+ ctx.pMem = pMem = &aMem[pOp->p3];
pMem->n++;
sqlite3VdbeMemInit(&t, db, MEM_Null);
- pCtx->pOut = &t;
- pCtx->fErrorOrAux = 0;
- pCtx->skipFlag = 0;
- (pCtx->pFunc->xSFunc)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */
- if( pCtx->fErrorOrAux ){
- if( pCtx->isError ){
- sqlite3VdbeError(p, "%s", sqlite3_value_text(&t));
- rc = pCtx->isError;
- }
- sqlite3VdbeMemRelease(&t);
- if( rc ) goto abort_due_to_error;
- }else{
- assert( t.flags==MEM_Null );
+ ctx.pOut = &t;
+ ctx.isError = 0;
+ ctx.pVdbe = p;
+ ctx.iOp = (int)(pOp - aOp);
+ ctx.skipFlag = 0;
+ (ctx.pFunc->xStep)(&ctx, n, apVal); /* IMP: R-24505-23230 */
+ if( ctx.isError ){
+ sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&t));
+ rc = ctx.isError;
}
- if( pCtx->skipFlag ){
+ if( ctx.skipFlag ){
assert( pOp[-1].opcode==OP_CollSeq );
i = pOp[-1].p1;
if( i ) sqlite3VdbeMemSetInt64(&aMem[i], 1);
}
+ sqlite3VdbeMemRelease(&t);
break;
}
@@ -82756,13 +76596,12 @@ case OP_AggStep: {
*/
case OP_AggFinal: {
Mem *pMem;
- assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
+ assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
pMem = &aMem[pOp->p1];
assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc);
if( rc ){
- sqlite3VdbeError(p, "%s", sqlite3_value_text(pMem));
- goto abort_due_to_error;
+ sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(pMem));
}
sqlite3VdbeChangeEncoding(pMem, encoding);
UPDATE_MAX_BLOBSIZE(pMem);
@@ -82798,8 +76637,7 @@ case OP_Checkpoint: {
|| pOp->p2==SQLITE_CHECKPOINT_TRUNCATE
);
rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &aRes[1], &aRes[2]);
- if( rc ){
- if( rc!=SQLITE_BUSY ) goto abort_due_to_error;
+ if( rc==SQLITE_BUSY ){
rc = SQLITE_OK;
aRes[0] = 1;
}
@@ -82868,11 +76706,11 @@ case OP_JournalMode: { /* out2 */
){
if( !db->autoCommit || db->nVdbeRead>1 ){
rc = SQLITE_ERROR;
- sqlite3VdbeError(p,
+ sqlite3SetString(&p->zErrMsg, db,
"cannot change %s wal mode from within a transaction",
(eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
);
- goto abort_due_to_error;
+ break;
}else{
if( eOld==PAGER_JOURNALMODE_WAL ){
@@ -82902,7 +76740,9 @@ case OP_JournalMode: { /* out2 */
}
#endif /* ifndef SQLITE_OMIT_WAL */
- if( rc ) eNew = eOld;
+ if( rc ){
+ eNew = eOld;
+ }
eNew = sqlite3PagerSetJournalMode(pPager, eNew);
pOut->flags = MEM_Str|MEM_Static|MEM_Term;
@@ -82910,7 +76750,6 @@ case OP_JournalMode: { /* out2 */
pOut->n = sqlite3Strlen30(pOut->z);
pOut->enc = SQLITE_UTF8;
sqlite3VdbeChangeEncoding(pOut, encoding);
- if( rc ) goto abort_due_to_error;
break;
};
#endif /* SQLITE_OMIT_PRAGMA */
@@ -82925,7 +76764,6 @@ case OP_JournalMode: { /* out2 */
case OP_Vacuum: {
assert( p->readOnly==0 );
rc = sqlite3RunVacuum(&p->zErrMsg, db);
- if( rc ) goto abort_due_to_error;
break;
}
#endif
@@ -82946,8 +76784,7 @@ case OP_IncrVacuum: { /* jump */
pBt = db->aDb[pOp->p1].pBt;
rc = sqlite3BtreeIncrVacuum(pBt);
VdbeBranchTaken(rc==SQLITE_DONE,2);
- if( rc ){
- if( rc!=SQLITE_DONE ) goto abort_due_to_error;
+ if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
goto jump_to_p2;
}
@@ -82998,12 +76835,9 @@ case OP_TableLock: {
assert( DbMaskTest(p->btreeMask, p1) );
assert( isWriteLock==0 || isWriteLock==1 );
rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock);
- if( rc ){
- if( (rc&0xFF)==SQLITE_LOCKED ){
- const char *z = pOp->p4.z;
- sqlite3VdbeError(p, "database table is locked: %s", z);
- }
- goto abort_due_to_error;
+ if( (rc&0xFF)==SQLITE_LOCKED ){
+ const char *z = pOp->p4.z;
+ sqlite3SetString(&p->zErrMsg, db, "database table is locked: %s", z);
}
}
break;
@@ -83025,7 +76859,6 @@ case OP_VBegin: {
pVTab = pOp->p4.pVtab;
rc = sqlite3VtabBegin(db, pVTab);
if( pVTab ) sqlite3VtabImportErrmsg(p, pVTab->pVtab);
- if( rc ) goto abort_due_to_error;
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -83054,7 +76887,6 @@ case OP_VCreate: {
rc = sqlite3VtabCallCreate(db, pOp->p1, zTab, &p->zErrMsg);
}
sqlite3VdbeMemRelease(&sMem);
- if( rc ) goto abort_due_to_error;
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -83069,7 +76901,6 @@ case OP_VDestroy: {
db->nVDestroy++;
rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z);
db->nVDestroy--;
- if( rc ) goto abort_due_to_error;
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -83083,35 +76914,35 @@ case OP_VDestroy: {
*/
case OP_VOpen: {
VdbeCursor *pCur;
- sqlite3_vtab_cursor *pVCur;
+ sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
assert( p->bIsReader );
pCur = 0;
- pVCur = 0;
+ pVtabCursor = 0;
pVtab = pOp->p4.pVtab->pVtab;
if( pVtab==0 || NEVER(pVtab->pModule==0) ){
rc = SQLITE_LOCKED;
- goto abort_due_to_error;
+ break;
}
pModule = pVtab->pModule;
- rc = pModule->xOpen(pVtab, &pVCur);
+ rc = pModule->xOpen(pVtab, &pVtabCursor);
sqlite3VtabImportErrmsg(p, pVtab);
- if( rc ) goto abort_due_to_error;
-
- /* Initialize sqlite3_vtab_cursor base class */
- pVCur->pVtab = pVtab;
+ if( SQLITE_OK==rc ){
+ /* Initialize sqlite3_vtab_cursor base class */
+ pVtabCursor->pVtab = pVtab;
- /* Initialize vdbe cursor object */
- pCur = allocateCursor(p, pOp->p1, 0, -1, CURTYPE_VTAB);
- if( pCur ){
- pCur->uc.pVCur = pVCur;
- pVtab->nRef++;
- }else{
- assert( db->mallocFailed );
- pModule->xClose(pVCur);
- goto no_mem;
+ /* Initialize vdbe cursor object */
+ pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
+ if( pCur ){
+ pCur->pVtabCursor = pVtabCursor;
+ pVtab->nRef++;
+ }else{
+ assert( db->mallocFailed );
+ pModule->xClose(pVtabCursor);
+ goto no_mem;
+ }
}
break;
}
@@ -83143,7 +76974,7 @@ case OP_VFilter: { /* jump */
const sqlite3_module *pModule;
Mem *pQuery;
Mem *pArgc;
- sqlite3_vtab_cursor *pVCur;
+ sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
VdbeCursor *pCur;
int res;
@@ -83155,9 +76986,9 @@ case OP_VFilter: { /* jump */
pCur = p->apCsr[pOp->p1];
assert( memIsValid(pQuery) );
REGISTER_TRACE(pOp->p3, pQuery);
- assert( pCur->eCurType==CURTYPE_VTAB );
- pVCur = pCur->uc.pVCur;
- pVtab = pVCur->pVtab;
+ assert( pCur->pVtabCursor );
+ pVtabCursor = pCur->pVtabCursor;
+ pVtab = pVtabCursor->pVtab;
pModule = pVtab->pModule;
/* Grab the index number and argc parameters */
@@ -83171,10 +77002,11 @@ case OP_VFilter: { /* jump */
for(i = 0; i<nArg; i++){
apArg[i] = &pArgc[i+1];
}
- rc = pModule->xFilter(pVCur, iQuery, pOp->p4.z, nArg, apArg);
+ rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
sqlite3VtabImportErrmsg(p, pVtab);
- if( rc ) goto abort_due_to_error;
- res = pModule->xEof(pVCur);
+ if( rc==SQLITE_OK ){
+ res = pModule->xEof(pVtabCursor);
+ }
pCur->nullRow = 0;
VdbeBranchTaken(res!=0,2);
if( res ) goto jump_to_p2;
@@ -83197,21 +77029,21 @@ case OP_VColumn: {
sqlite3_context sContext;
VdbeCursor *pCur = p->apCsr[pOp->p1];
- assert( pCur->eCurType==CURTYPE_VTAB );
- assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
+ assert( pCur->pVtabCursor );
+ assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
pDest = &aMem[pOp->p3];
memAboutToChange(p, pDest);
if( pCur->nullRow ){
sqlite3VdbeMemSetNull(pDest);
break;
}
- pVtab = pCur->uc.pVCur->pVtab;
+ pVtab = pCur->pVtabCursor->pVtab;
pModule = pVtab->pModule;
assert( pModule->xColumn );
memset(&sContext, 0, sizeof(sContext));
sContext.pOut = pDest;
MemSetTypeFlag(pDest, MEM_Null);
- rc = pModule->xColumn(pCur->uc.pVCur, &sContext, pOp->p2);
+ rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2);
sqlite3VtabImportErrmsg(p, pVtab);
if( sContext.isError ){
rc = sContext.isError;
@@ -83223,7 +77055,6 @@ case OP_VColumn: {
if( sqlite3VdbeMemTooBig(pDest) ){
goto too_big;
}
- if( rc ) goto abort_due_to_error;
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -83243,11 +77074,11 @@ case OP_VNext: { /* jump */
res = 0;
pCur = p->apCsr[pOp->p1];
- assert( pCur->eCurType==CURTYPE_VTAB );
+ assert( pCur->pVtabCursor );
if( pCur->nullRow ){
break;
}
- pVtab = pCur->uc.pVCur->pVtab;
+ pVtab = pCur->pVtabCursor->pVtab;
pModule = pVtab->pModule;
assert( pModule->xNext );
@@ -83257,10 +77088,11 @@ case OP_VNext: { /* jump */
** data is available) and the error code returned when xColumn or
** some other method is next invoked on the save virtual table cursor.
*/
- rc = pModule->xNext(pCur->uc.pVCur);
+ rc = pModule->xNext(pCur->pVtabCursor);
sqlite3VtabImportErrmsg(p, pVtab);
- if( rc ) goto abort_due_to_error;
- res = pModule->xEof(pCur->uc.pVCur);
+ if( rc==SQLITE_OK ){
+ res = pModule->xEof(pCur->pVtabCursor);
+ }
VdbeBranchTaken(!res,2);
if( !res ){
/* If there is data, jump to P2 */
@@ -83292,11 +77124,11 @@ case OP_VRename: {
testcase( pName->enc==SQLITE_UTF16BE );
testcase( pName->enc==SQLITE_UTF16LE );
rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8);
- if( rc ) goto abort_due_to_error;
- rc = pVtab->pModule->xRename(pVtab, pName->z);
- sqlite3VtabImportErrmsg(p, pVtab);
- p->expired = 0;
- if( rc ) goto abort_due_to_error;
+ if( rc==SQLITE_OK ){
+ rc = pVtab->pModule->xRename(pVtab, pName->z);
+ sqlite3VtabImportErrmsg(p, pVtab);
+ p->expired = 0;
+ }
break;
}
#endif
@@ -83345,7 +77177,7 @@ case OP_VUpdate: {
pVtab = pOp->p4.pVtab->pVtab;
if( pVtab==0 || NEVER(pVtab->pModule==0) ){
rc = SQLITE_LOCKED;
- goto abort_due_to_error;
+ break;
}
pModule = pVtab->pModule;
nArg = pOp->p2;
@@ -83377,7 +77209,6 @@ case OP_VUpdate: {
}else{
p->nChange++;
}
- if( rc ) goto abort_due_to_error;
}
break;
}
@@ -83469,28 +77300,6 @@ case OP_Init: { /* jump */
break;
}
-#ifdef SQLITE_ENABLE_CURSOR_HINTS
-/* Opcode: CursorHint P1 * * P4 *
-**
-** Provide a hint to cursor P1 that it only needs to return rows that
-** satisfy the Expr in P4. TK_REGISTER terms in the P4 expression refer
-** to values currently held in registers. TK_COLUMN terms in the P4
-** expression refer to columns in the b-tree to which cursor P1 is pointing.
-*/
-case OP_CursorHint: {
- VdbeCursor *pC;
-
- assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- assert( pOp->p4type==P4_EXPR );
- pC = p->apCsr[pOp->p1];
- if( pC ){
- assert( pC->eCurType==CURTYPE_BTREE );
- sqlite3BtreeCursorHint(pC->uc.pCursor, BTREE_HINT_RANGE,
- pOp->p4.pExpr, aMem);
- }
- break;
-}
-#endif /* SQLITE_ENABLE_CURSOR_HINTS */
/* Opcode: Noop * * * * *
**
@@ -83534,12 +77343,11 @@ default: { /* This is really OP_Noop and OP_Explain */
#ifdef SQLITE_DEBUG
if( db->flags & SQLITE_VdbeTrace ){
- u8 opProperty = sqlite3OpcodeProperty[pOrigOp->opcode];
if( rc!=0 ) printf("rc=%d\n",rc);
- if( opProperty & (OPFLG_OUT2) ){
+ if( pOrigOp->opflags & (OPFLG_OUT2) ){
registerTrace(pOrigOp->p2, &aMem[pOrigOp->p2]);
}
- if( opProperty & OPFLG_OUT3 ){
+ if( pOrigOp->opflags & OPFLG_OUT3 ){
registerTrace(pOrigOp->p3, &aMem[pOrigOp->p3]);
}
}
@@ -83550,19 +77358,14 @@ default: { /* This is really OP_Noop and OP_Explain */
/* If we reach this point, it means that execution is finished with
** an error of some kind.
*/
-abort_due_to_error:
- if( db->mallocFailed ) rc = SQLITE_NOMEM_BKPT;
+vdbe_error_halt:
assert( rc );
- if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){
- sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
- }
p->rc = rc;
- sqlite3SystemError(db, rc);
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(rc, "statement aborts at %d: [%s] %s",
(int)(pOp - aOp), p->zSql, p->zErrMsg);
sqlite3VdbeHalt(p);
- if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db);
+ if( rc==SQLITE_IOERR_NOMEM ) db->mallocFailed = 1;
rc = SQLITE_ERROR;
if( resetSchemaOnFault>0 ){
sqlite3ResetOneSchema(db, resetSchemaOnFault-1);
@@ -83576,36 +77379,44 @@ vdbe_return:
testcase( nVmStep>0 );
p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep;
sqlite3VdbeLeave(p);
- assert( rc!=SQLITE_OK || nExtraDelete==0
- || sqlite3_strlike("DELETE%",p->zSql,0)!=0
- );
return rc;
/* Jump to here if a string or blob larger than SQLITE_MAX_LENGTH
** is encountered.
*/
too_big:
- sqlite3VdbeError(p, "string or blob too big");
+ sqlite3SetString(&p->zErrMsg, db, "string or blob too big");
rc = SQLITE_TOOBIG;
- goto abort_due_to_error;
+ goto vdbe_error_halt;
/* Jump to here if a malloc() fails.
*/
no_mem:
- sqlite3OomFault(db);
- sqlite3VdbeError(p, "out of memory");
- rc = SQLITE_NOMEM_BKPT;
- goto abort_due_to_error;
+ db->mallocFailed = 1;
+ sqlite3SetString(&p->zErrMsg, db, "out of memory");
+ rc = SQLITE_NOMEM;
+ goto vdbe_error_halt;
+
+ /* Jump to here for any other kind of fatal error. The "rc" variable
+ ** should hold the error number.
+ */
+abort_due_to_error:
+ assert( p->zErrMsg==0 );
+ if( db->mallocFailed ) rc = SQLITE_NOMEM;
+ if( rc!=SQLITE_IOERR_NOMEM ){
+ sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3ErrStr(rc));
+ }
+ goto vdbe_error_halt;
/* Jump to here if the sqlite3_interrupt() API sets the interrupt
** flag.
*/
abort_due_to_interrupt:
assert( db->u1.isInterrupted );
- rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
+ rc = SQLITE_INTERRUPT;
p->rc = rc;
- sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
- goto abort_due_to_error;
+ sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3ErrStr(rc));
+ goto vdbe_error_halt;
}
@@ -83626,8 +77437,6 @@ abort_due_to_interrupt:
** This file contains code used to implement incremental BLOB I/O.
*/
-/* #include "sqliteInt.h" */
-/* #include "vdbeInt.h" */
#ifndef SQLITE_OMIT_INCRBLOB
@@ -83643,8 +77452,6 @@ struct Incrblob {
BtCursor *pCsr; /* Cursor pointing at blob row */
sqlite3_stmt *pStmt; /* Statement holding cursor open */
sqlite3 *db; /* The associated database */
- char *zDb; /* Database name */
- Table *pTab; /* Table object */
};
@@ -83691,7 +77498,7 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
}else{
p->iOffset = pC->aType[p->iCol + pC->nField];
p->nByte = sqlite3VdbeSerialTypeLen(type);
- p->pCsr = pC->uc.pCursor;
+ p->pCsr = pC->pCursor;
sqlite3BtreeIncrblobCursor(p->pCsr);
}
}
@@ -83730,6 +77537,38 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
){
int nAttempt = 0;
int iCol; /* Index of zColumn in row-record */
+
+ /* This VDBE program seeks a btree cursor to the identified
+ ** db/table/row entry. The reason for using a vdbe program instead
+ ** of writing code to use the b-tree layer directly is that the
+ ** vdbe program will take advantage of the various transaction,
+ ** locking and error handling infrastructure built into the vdbe.
+ **
+ ** After seeking the cursor, the vdbe executes an OP_ResultRow.
+ ** Code external to the Vdbe then "borrows" the b-tree cursor and
+ ** uses it to implement the blob_read(), blob_write() and
+ ** blob_bytes() functions.
+ **
+ ** The sqlite3_blob_close() function finalizes the vdbe program,
+ ** which closes the b-tree cursor and (possibly) commits the
+ ** transaction.
+ */
+ static const int iLn = VDBE_OFFSET_LINENO(4);
+ static const VdbeOpList openBlob[] = {
+ /* {OP_Transaction, 0, 0, 0}, // 0: Inserted separately */
+ {OP_TableLock, 0, 0, 0}, /* 1: Acquire a read or write lock */
+ /* One of the following two instructions is replaced by an OP_Noop. */
+ {OP_OpenRead, 0, 0, 0}, /* 2: Open cursor 0 for reading */
+ {OP_OpenWrite, 0, 0, 0}, /* 3: Open cursor 0 for read/write */
+ {OP_Variable, 1, 1, 1}, /* 4: Push the rowid to the stack */
+ {OP_NotExists, 0, 10, 1}, /* 5: Seek the cursor */
+ {OP_Column, 0, 0, 1}, /* 6 */
+ {OP_ResultRow, 1, 0, 0}, /* 7 */
+ {OP_Goto, 0, 4, 0}, /* 8 */
+ {OP_Close, 0, 0, 0}, /* 9 */
+ {OP_Halt, 0, 0, 0}, /* 10 */
+ };
+
int rc = SQLITE_OK;
char *zErr = 0;
Table *pTab;
@@ -83788,8 +77627,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
sqlite3BtreeLeaveAll(db);
goto blob_open_out;
}
- pBlob->pTab = pTab;
- pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zName;
/* Now search pTab for the exact column. */
for(iCol=0; iCol<pTab->nCol; iCol++) {
@@ -83832,8 +77669,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int j;
for(j=0; j<pIdx->nKeyCol; j++){
- /* FIXME: Be smarter about indexes that use expressions */
- if( pIdx->aiColumn[j]==iCol || pIdx->aiColumn[j]==XN_EXPR ){
+ if( pIdx->aiColumn[j]==iCol ){
zFault = "indexed";
}
}
@@ -83850,78 +77686,45 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse);
assert( pBlob->pStmt || db->mallocFailed );
if( pBlob->pStmt ){
-
- /* This VDBE program seeks a btree cursor to the identified
- ** db/table/row entry. The reason for using a vdbe program instead
- ** of writing code to use the b-tree layer directly is that the
- ** vdbe program will take advantage of the various transaction,
- ** locking and error handling infrastructure built into the vdbe.
- **
- ** After seeking the cursor, the vdbe executes an OP_ResultRow.
- ** Code external to the Vdbe then "borrows" the b-tree cursor and
- ** uses it to implement the blob_read(), blob_write() and
- ** blob_bytes() functions.
- **
- ** The sqlite3_blob_close() function finalizes the vdbe program,
- ** which closes the b-tree cursor and (possibly) commits the
- ** transaction.
- */
- static const int iLn = VDBE_OFFSET_LINENO(2);
- static const VdbeOpList openBlob[] = {
- {OP_TableLock, 0, 0, 0}, /* 0: Acquire a read or write lock */
- {OP_OpenRead, 0, 0, 0}, /* 1: Open a cursor */
- {OP_Variable, 1, 1, 0}, /* 2: Move ?1 into reg[1] */
- {OP_NotExists, 0, 7, 1}, /* 3: Seek the cursor */
- {OP_Column, 0, 0, 1}, /* 4 */
- {OP_ResultRow, 1, 0, 0}, /* 5 */
- {OP_Goto, 0, 2, 0}, /* 6 */
- {OP_Close, 0, 0, 0}, /* 7 */
- {OP_Halt, 0, 0, 0}, /* 8 */
- };
Vdbe *v = (Vdbe *)pBlob->pStmt;
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
- VdbeOp *aOp;
+
sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, flags,
pTab->pSchema->schema_cookie,
pTab->pSchema->iGeneration);
sqlite3VdbeChangeP5(v, 1);
- aOp = sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn);
+ sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn);
/* Make sure a mutex is held on the table to be accessed */
sqlite3VdbeUsesBtree(v, iDb);
- if( db->mallocFailed==0 ){
- assert( aOp!=0 );
- /* Configure the OP_TableLock instruction */
+ /* Configure the OP_TableLock instruction */
#ifdef SQLITE_OMIT_SHARED_CACHE
- aOp[0].opcode = OP_Noop;
+ sqlite3VdbeChangeToNoop(v, 1);
#else
- aOp[0].p1 = iDb;
- aOp[0].p2 = pTab->tnum;
- aOp[0].p3 = flags;
- sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT);
- }
- if( db->mallocFailed==0 ){
-#endif
-
- /* Remove either the OP_OpenWrite or OpenRead. Set the P2
- ** parameter of the other to pTab->tnum. */
- if( flags ) aOp[1].opcode = OP_OpenWrite;
- aOp[1].p2 = pTab->tnum;
- aOp[1].p3 = iDb;
-
- /* Configure the number of columns. Configure the cursor to
- ** think that the table has one more column than it really
- ** does. An OP_Column to retrieve this imaginary column will
- ** always return an SQL NULL. This is useful because it means
- ** we can invoke OP_Column to fill in the vdbe cursors type
- ** and offset cache without causing any IO.
- */
- aOp[1].p4type = P4_INT32;
- aOp[1].p4.i = pTab->nCol+1;
- aOp[4].p2 = pTab->nCol;
-
+ sqlite3VdbeChangeP1(v, 1, iDb);
+ sqlite3VdbeChangeP2(v, 1, pTab->tnum);
+ sqlite3VdbeChangeP3(v, 1, flags);
+ sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT);
+#endif
+
+ /* Remove either the OP_OpenWrite or OpenRead. Set the P2
+ ** parameter of the other to pTab->tnum. */
+ sqlite3VdbeChangeToNoop(v, 3 - flags);
+ sqlite3VdbeChangeP2(v, 2 + flags, pTab->tnum);
+ sqlite3VdbeChangeP3(v, 2 + flags, iDb);
+
+ /* Configure the number of columns. Configure the cursor to
+ ** think that the table has one more column than it really
+ ** does. An OP_Column to retrieve this imaginary column will
+ ** always return an SQL NULL. This is useful because it means
+ ** we can invoke OP_Column to fill in the vdbe cursors type
+ ** and offset cache without causing any IO.
+ */
+ sqlite3VdbeChangeP4(v, 2+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32);
+ sqlite3VdbeChangeP2(v, 6, pTab->nCol);
+ if( !db->mallocFailed ){
pParse->nVar = 1;
pParse->nMem = 1;
pParse->nTab = 1;
@@ -84011,30 +77814,6 @@ static int blobReadWrite(
*/
assert( db == v->db );
sqlite3BtreeEnterCursor(p->pCsr);
-
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
- if( xCall==sqlite3BtreePutData && db->xPreUpdateCallback ){
- /* If a pre-update hook is registered and this is a write cursor,
- ** invoke it here.
- **
- ** TODO: The preupdate-hook is passed SQLITE_DELETE, even though this
- ** operation should really be an SQLITE_UPDATE. This is probably
- ** incorrect, but is convenient because at this point the new.* values
- ** are not easily obtainable. And for the sessions module, an
- ** SQLITE_UPDATE where the PK columns do not change is handled in the
- ** same way as an SQLITE_DELETE (the SQLITE_DELETE code is actually
- ** slightly more efficient). Since you cannot write to a PK column
- ** using the incremental-blob API, this works. For the sessions module
- ** anyhow.
- */
- sqlite3_int64 iKey;
- sqlite3BtreeKeySize(p->pCsr, &iKey);
- sqlite3VdbePreUpdateHook(
- v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1
- );
- }
-#endif
-
rc = xCall(p->pCsr, iOffset+p->iOffset, n, z);
sqlite3BtreeLeaveCursor(p->pCsr);
if( rc==SQLITE_ABORT ){
@@ -84256,8 +78035,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_i
** thread to merge the output of each of the others to a single PMA for
** the main thread to read from.
*/
-/* #include "sqliteInt.h" */
-/* #include "vdbeInt.h" */
/*
** If SQLITE_DEBUG_SORTER_THREADS is defined, this module outputs various
@@ -84661,7 +78438,7 @@ static int vdbePmaReadBlob(
int nNew = MAX(128, p->nAlloc*2);
while( nByte>nNew ) nNew = nNew*2;
aNew = sqlite3Realloc(p->aAlloc, nNew);
- if( !aNew ) return SQLITE_NOMEM_BKPT;
+ if( !aNew ) return SQLITE_NOMEM;
p->nAlloc = nNew;
p->aAlloc = aNew;
}
@@ -84773,7 +78550,7 @@ static int vdbePmaReaderSeek(
int iBuf = pReadr->iReadOff % pgsz;
if( pReadr->aBuffer==0 ){
pReadr->aBuffer = (u8*)sqlite3Malloc(pgsz);
- if( pReadr->aBuffer==0 ) rc = SQLITE_NOMEM_BKPT;
+ if( pReadr->aBuffer==0 ) rc = SQLITE_NOMEM;
pReadr->nBuffer = pgsz;
}
if( rc==SQLITE_OK && iBuf ){
@@ -84858,7 +78635,7 @@ static int vdbePmaReaderInit(
rc = vdbePmaReaderSeek(pTask, pReadr, pFile, iStart);
if( rc==SQLITE_OK ){
- u64 nByte = 0; /* Size of PMA in bytes */
+ u64 nByte; /* Size of PMA in bytes */
rc = vdbePmaReadVarint(pReadr, &nByte);
pReadr->iEof = pReadr->iReadOff + nByte;
*pnByte += nByte;
@@ -85052,6 +78829,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
){
int pgsz; /* Page size of main database */
int i; /* Used to iterate through aTask[] */
+ int mxCache; /* Cache size */
VdbeSorter *pSorter; /* The new sorter */
KeyInfo *pKeyInfo; /* Copy of pCsr->pKeyInfo with db==0 */
int szKeyInfo; /* Size of pCsr->pKeyInfo in bytes */
@@ -85081,14 +78859,13 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
#endif
assert( pCsr->pKeyInfo && pCsr->pBt==0 );
- assert( pCsr->eCurType==CURTYPE_SORTER );
szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*);
sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask);
pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo);
- pCsr->uc.pSorter = pSorter;
+ pCsr->pSorter = pSorter;
if( pSorter==0 ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}else{
pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz);
memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo);
@@ -85099,7 +78876,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
}
pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
pSorter->nTask = nWorker + 1;
- pSorter->iPrev = (u8)(nWorker - 1);
+ pSorter->iPrev = nWorker-1;
pSorter->bUseThreads = (pSorter->nTask>1);
pSorter->db = db;
for(i=0; i<pSorter->nTask; i++){
@@ -85108,20 +78885,11 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
}
if( !sqlite3TempInMemory(db) ){
- i64 mxCache; /* Cache size in bytes*/
u32 szPma = sqlite3GlobalConfig.szPma;
pSorter->mnPmaSize = szPma * pgsz;
-
mxCache = db->aDb[0].pSchema->cache_size;
- if( mxCache<0 ){
- /* A negative cache-size value C indicates that the cache is abs(C)
- ** KiB in size. */
- mxCache = mxCache * -1024;
- }else{
- mxCache = mxCache * pgsz;
- }
- mxCache = MIN(mxCache, SQLITE_MAX_PMASZ);
- pSorter->mxPmaSize = MAX(pSorter->mnPmaSize, (int)mxCache);
+ if( mxCache<(int)szPma ) mxCache = (int)szPma;
+ pSorter->mxPmaSize = MIN((i64)mxCache*pgsz, SQLITE_MAX_PMASZ);
/* EVIDENCE-OF: R-26747-61719 When the application provides any amount of
** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary
@@ -85131,7 +78899,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
assert( pSorter->iMemory==0 );
pSorter->nMemory = pgsz;
pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz);
- if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM_BKPT;
+ if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM;
}
}
@@ -85379,14 +79147,12 @@ SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){
** Free any cursor components allocated by sqlite3VdbeSorterXXX routines.
*/
SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){
- VdbeSorter *pSorter;
- assert( pCsr->eCurType==CURTYPE_SORTER );
- pSorter = pCsr->uc.pSorter;
+ VdbeSorter *pSorter = pCsr->pSorter;
if( pSorter ){
sqlite3VdbeSorterReset(db, pSorter);
sqlite3_free(pSorter->list.aMemory);
sqlite3DbFree(db, pSorter);
- pCsr->uc.pSorter = 0;
+ pCsr->pSorter = 0;
}
}
@@ -85453,7 +79219,7 @@ static int vdbeSortAllocUnpacked(SortSubtask *pTask){
pTask->pSorter->pKeyInfo, 0, 0, &pFree
);
assert( pTask->pUnpacked==(UnpackedRecord*)pFree );
- if( pFree==0 ) return SQLITE_NOMEM_BKPT;
+ if( pFree==0 ) return SQLITE_NOMEM;
pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nField;
pTask->pUnpacked->errCode = 0;
}
@@ -85528,7 +79294,7 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *));
if( !aSlot ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
while( p ){
@@ -85578,7 +79344,7 @@ static void vdbePmaWriterInit(
memset(p, 0, sizeof(PmaWriter));
p->aBuffer = (u8*)sqlite3Malloc(nBuf);
if( !p->aBuffer ){
- p->eFWErr = SQLITE_NOMEM_BKPT;
+ p->eFWErr = SQLITE_NOMEM;
}else{
p->iBufEnd = p->iBufStart = (iStart % nBuf);
p->iWriteOff = iStart - p->iBufStart;
@@ -85866,7 +79632,7 @@ static int vdbeSorterFlushPMA(VdbeSorter *pSorter){
pSorter->nMemory = sqlite3MallocSize(aMem);
}else if( pSorter->list.aMemory ){
pSorter->list.aMemory = sqlite3Malloc(pSorter->nMemory);
- if( !pSorter->list.aMemory ) return SQLITE_NOMEM_BKPT;
+ if( !pSorter->list.aMemory ) return SQLITE_NOMEM;
}
rc = vdbeSorterCreateThread(pTask, vdbeSorterFlushThread, pCtx);
@@ -85884,16 +79650,15 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite(
const VdbeCursor *pCsr, /* Sorter cursor */
Mem *pVal /* Memory cell containing record */
){
- VdbeSorter *pSorter;
+ VdbeSorter *pSorter = pCsr->pSorter;
int rc = SQLITE_OK; /* Return Code */
SorterRecord *pNew; /* New list element */
+
int bFlush; /* True to flush contents of memory to PMA */
int nReq; /* Bytes of memory required */
int nPMA; /* Bytes of PMA space required */
int t; /* serial type of first record field */
- assert( pCsr->eCurType==CURTYPE_SORTER );
- pSorter = pCsr->uc.pSorter;
getVarint32((const u8*)&pVal->z[1], t);
if( t>0 && t<10 && t!=7 ){
pSorter->typeMask &= SORTER_TYPE_INTEGER;
@@ -85950,28 +79715,27 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite(
if( nMin>pSorter->nMemory ){
u8 *aNew;
- int iListOff = (u8*)pSorter->list.pList - pSorter->list.aMemory;
int nNew = pSorter->nMemory * 2;
while( nNew < nMin ) nNew = nNew*2;
if( nNew > pSorter->mxPmaSize ) nNew = pSorter->mxPmaSize;
if( nNew < nMin ) nNew = nMin;
aNew = sqlite3Realloc(pSorter->list.aMemory, nNew);
- if( !aNew ) return SQLITE_NOMEM_BKPT;
- pSorter->list.pList = (SorterRecord*)&aNew[iListOff];
+ if( !aNew ) return SQLITE_NOMEM;
+ pSorter->list.pList = (SorterRecord*)(
+ aNew + ((u8*)pSorter->list.pList - pSorter->list.aMemory)
+ );
pSorter->list.aMemory = aNew;
pSorter->nMemory = nNew;
}
pNew = (SorterRecord*)&pSorter->list.aMemory[pSorter->iMemory];
pSorter->iMemory += ROUND8(nReq);
- if( pSorter->list.pList ){
- pNew->u.iNext = (int)((u8*)(pSorter->list.pList) - pSorter->list.aMemory);
- }
+ pNew->u.iNext = (int)((u8*)(pSorter->list.pList) - pSorter->list.aMemory);
}else{
pNew = (SorterRecord *)sqlite3Malloc(nReq);
if( pNew==0 ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
pNew->u.pNext = pSorter->list.pList;
}
@@ -86118,7 +79882,7 @@ static int vdbeIncrMergerNew(
pTask->file2.iEof += pIncr->mxSz;
}else{
vdbeMergeEngineFree(pMerger);
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}
return rc;
}
@@ -86423,10 +80187,10 @@ static int vdbeMergeEngineLevel0(
int rc = SQLITE_OK;
*ppOut = pNew = vdbeMergeEngineNew(nPMA);
- if( pNew==0 ) rc = SQLITE_NOMEM_BKPT;
+ if( pNew==0 ) rc = SQLITE_NOMEM;
for(i=0; i<nPMA && rc==SQLITE_OK; i++){
- i64 nDummy = 0;
+ i64 nDummy;
PmaReader *pReadr = &pNew->aReadr[i];
rc = vdbePmaReaderInit(pTask, &pTask->file, iOff, pReadr, &nDummy);
iOff = pReadr->iEof;
@@ -86494,7 +80258,7 @@ static int vdbeSorterAddToTree(
if( pReadr->pIncr==0 ){
MergeEngine *pNew = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT);
if( pNew==0 ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}else{
rc = vdbeIncrMergerNew(pTask, pNew, &pReadr->pIncr);
}
@@ -86539,7 +80303,7 @@ static int vdbeSorterMergeTreeBuild(
assert( pSorter->bUseThreads || pSorter->nTask==1 );
if( pSorter->nTask>1 ){
pMain = vdbeMergeEngineNew(pSorter->nTask);
- if( pMain==0 ) rc = SQLITE_NOMEM_BKPT;
+ if( pMain==0 ) rc = SQLITE_NOMEM;
}
#endif
@@ -86557,7 +80321,7 @@ static int vdbeSorterMergeTreeBuild(
int i;
int iSeq = 0;
pRoot = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT);
- if( pRoot==0 ) rc = SQLITE_NOMEM_BKPT;
+ if( pRoot==0 ) rc = SQLITE_NOMEM;
for(i=0; i<pTask->nPMA && rc==SQLITE_OK; i += SORTER_MAX_MERGE_COUNT){
MergeEngine *pMerger = 0; /* New level-0 PMA merger */
int nReader; /* Number of level-0 PMAs to merge */
@@ -86628,7 +80392,7 @@ static int vdbeSorterSetupMerge(VdbeSorter *pSorter){
if( rc==SQLITE_OK ){
pReadr = (PmaReader*)sqlite3DbMallocZero(db, sizeof(PmaReader));
pSorter->pReader = pReadr;
- if( pReadr==0 ) rc = SQLITE_NOMEM_BKPT;
+ if( pReadr==0 ) rc = SQLITE_NOMEM;
}
if( rc==SQLITE_OK ){
rc = vdbeIncrMergerNew(pLast, pMain, &pReadr->pIncr);
@@ -86686,11 +80450,9 @@ static int vdbeSorterSetupMerge(VdbeSorter *pSorter){
** in sorted order.
*/
SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){
- VdbeSorter *pSorter;
+ VdbeSorter *pSorter = pCsr->pSorter;
int rc = SQLITE_OK; /* Return code */
- assert( pCsr->eCurType==CURTYPE_SORTER );
- pSorter = pCsr->uc.pSorter;
assert( pSorter );
/* If no data has been written to disk, then do not do so now. Instead,
@@ -86734,11 +80496,9 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){
** Advance to the next element in the sorter.
*/
SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
- VdbeSorter *pSorter;
+ VdbeSorter *pSorter = pCsr->pSorter;
int rc; /* Return code */
- assert( pCsr->eCurType==CURTYPE_SORTER );
- pSorter = pCsr->uc.pSorter;
assert( pSorter->bUsePMA || (pSorter->pReader==0 && pSorter->pMerger==0) );
if( pSorter->bUsePMA ){
assert( pSorter->pReader==0 || pSorter->pMerger==0 );
@@ -86798,14 +80558,12 @@ static void *vdbeSorterRowkey(
** Copy the current sorter key into the memory cell pOut.
*/
SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){
- VdbeSorter *pSorter;
+ VdbeSorter *pSorter = pCsr->pSorter;
void *pKey; int nKey; /* Sorter key to copy into pOut */
- assert( pCsr->eCurType==CURTYPE_SORTER );
- pSorter = pCsr->uc.pSorter;
pKey = vdbeSorterRowkey(pSorter, &nKey);
if( sqlite3VdbeMemClearAndResize(pOut, nKey) ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
pOut->n = nKey;
MemSetTypeFlag(pOut, MEM_Blob);
@@ -86836,21 +80594,17 @@ SQLITE_PRIVATE int sqlite3VdbeSorterCompare(
int nKeyCol, /* Compare this many columns */
int *pRes /* OUT: Result of comparison */
){
- VdbeSorter *pSorter;
- UnpackedRecord *r2;
- KeyInfo *pKeyInfo;
+ VdbeSorter *pSorter = pCsr->pSorter;
+ UnpackedRecord *r2 = pSorter->pUnpacked;
+ KeyInfo *pKeyInfo = pCsr->pKeyInfo;
int i;
void *pKey; int nKey; /* Sorter key to compare pVal with */
- assert( pCsr->eCurType==CURTYPE_SORTER );
- pSorter = pCsr->uc.pSorter;
- r2 = pSorter->pUnpacked;
- pKeyInfo = pCsr->pKeyInfo;
if( r2==0 ){
char *p;
r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo,0,0,&p);
assert( pSorter->pUnpacked==(UnpackedRecord*)p );
- if( r2==0 ) return SQLITE_NOMEM_BKPT;
+ if( r2==0 ) return SQLITE_NOMEM;
r2->nField = nKeyCol;
}
assert( r2->nField==nKeyCol );
@@ -86869,6 +80623,264 @@ SQLITE_PRIVATE int sqlite3VdbeSorterCompare(
}
/************** End of vdbesort.c ********************************************/
+/************** Begin file journal.c *****************************************/
+/*
+** 2007 August 22
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** This file implements a special kind of sqlite3_file object used
+** by SQLite to create journal files if the atomic-write optimization
+** is enabled.
+**
+** The distinctive characteristic of this sqlite3_file is that the
+** actual on disk file is created lazily. When the file is created,
+** the caller specifies a buffer size for an in-memory buffer to
+** be used to service read() and write() requests. The actual file
+** on disk is not created or populated until either:
+**
+** 1) The in-memory representation grows too large for the allocated
+** buffer, or
+** 2) The sqlite3JournalCreate() function is called.
+*/
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+
+
+/*
+** A JournalFile object is a subclass of sqlite3_file used by
+** as an open file handle for journal files.
+*/
+struct JournalFile {
+ sqlite3_io_methods *pMethod; /* I/O methods on journal files */
+ int nBuf; /* Size of zBuf[] in bytes */
+ char *zBuf; /* Space to buffer journal writes */
+ int iSize; /* Amount of zBuf[] currently used */
+ int flags; /* xOpen flags */
+ sqlite3_vfs *pVfs; /* The "real" underlying VFS */
+ sqlite3_file *pReal; /* The "real" underlying file descriptor */
+ const char *zJournal; /* Name of the journal file */
+};
+typedef struct JournalFile JournalFile;
+
+/*
+** If it does not already exists, create and populate the on-disk file
+** for JournalFile p.
+*/
+static int createFile(JournalFile *p){
+ int rc = SQLITE_OK;
+ if( !p->pReal ){
+ sqlite3_file *pReal = (sqlite3_file *)&p[1];
+ rc = sqlite3OsOpen(p->pVfs, p->zJournal, pReal, p->flags, 0);
+ if( rc==SQLITE_OK ){
+ p->pReal = pReal;
+ if( p->iSize>0 ){
+ assert(p->iSize<=p->nBuf);
+ rc = sqlite3OsWrite(p->pReal, p->zBuf, p->iSize, 0);
+ }
+ if( rc!=SQLITE_OK ){
+ /* If an error occurred while writing to the file, close it before
+ ** returning. This way, SQLite uses the in-memory journal data to
+ ** roll back changes made to the internal page-cache before this
+ ** function was called. */
+ sqlite3OsClose(pReal);
+ p->pReal = 0;
+ }
+ }
+ }
+ return rc;
+}
+
+/*
+** Close the file.
+*/
+static int jrnlClose(sqlite3_file *pJfd){
+ JournalFile *p = (JournalFile *)pJfd;
+ if( p->pReal ){
+ sqlite3OsClose(p->pReal);
+ }
+ sqlite3_free(p->zBuf);
+ return SQLITE_OK;
+}
+
+/*
+** Read data from the file.
+*/
+static int jrnlRead(
+ sqlite3_file *pJfd, /* The journal file from which to read */
+ void *zBuf, /* Put the results here */
+ int iAmt, /* Number of bytes to read */
+ sqlite_int64 iOfst /* Begin reading at this offset */
+){
+ int rc = SQLITE_OK;
+ JournalFile *p = (JournalFile *)pJfd;
+ if( p->pReal ){
+ rc = sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
+ }else if( (iAmt+iOfst)>p->iSize ){
+ rc = SQLITE_IOERR_SHORT_READ;
+ }else{
+ memcpy(zBuf, &p->zBuf[iOfst], iAmt);
+ }
+ return rc;
+}
+
+/*
+** Write data to the file.
+*/
+static int jrnlWrite(
+ sqlite3_file *pJfd, /* The journal file into which to write */
+ const void *zBuf, /* Take data to be written from here */
+ int iAmt, /* Number of bytes to write */
+ sqlite_int64 iOfst /* Begin writing at this offset into the file */
+){
+ int rc = SQLITE_OK;
+ JournalFile *p = (JournalFile *)pJfd;
+ if( !p->pReal && (iOfst+iAmt)>p->nBuf ){
+ rc = createFile(p);
+ }
+ if( rc==SQLITE_OK ){
+ if( p->pReal ){
+ rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
+ }else{
+ memcpy(&p->zBuf[iOfst], zBuf, iAmt);
+ if( p->iSize<(iOfst+iAmt) ){
+ p->iSize = (iOfst+iAmt);
+ }
+ }
+ }
+ return rc;
+}
+
+/*
+** Truncate the file.
+*/
+static int jrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
+ int rc = SQLITE_OK;
+ JournalFile *p = (JournalFile *)pJfd;
+ if( p->pReal ){
+ rc = sqlite3OsTruncate(p->pReal, size);
+ }else if( size<p->iSize ){
+ p->iSize = size;
+ }
+ return rc;
+}
+
+/*
+** Sync the file.
+*/
+static int jrnlSync(sqlite3_file *pJfd, int flags){
+ int rc;
+ JournalFile *p = (JournalFile *)pJfd;
+ if( p->pReal ){
+ rc = sqlite3OsSync(p->pReal, flags);
+ }else{
+ rc = SQLITE_OK;
+ }
+ return rc;
+}
+
+/*
+** Query the size of the file in bytes.
+*/
+static int jrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
+ int rc = SQLITE_OK;
+ JournalFile *p = (JournalFile *)pJfd;
+ if( p->pReal ){
+ rc = sqlite3OsFileSize(p->pReal, pSize);
+ }else{
+ *pSize = (sqlite_int64) p->iSize;
+ }
+ return rc;
+}
+
+/*
+** Table of methods for JournalFile sqlite3_file object.
+*/
+static struct sqlite3_io_methods JournalFileMethods = {
+ 1, /* iVersion */
+ jrnlClose, /* xClose */
+ jrnlRead, /* xRead */
+ jrnlWrite, /* xWrite */
+ jrnlTruncate, /* xTruncate */
+ jrnlSync, /* xSync */
+ jrnlFileSize, /* xFileSize */
+ 0, /* xLock */
+ 0, /* xUnlock */
+ 0, /* xCheckReservedLock */
+ 0, /* xFileControl */
+ 0, /* xSectorSize */
+ 0, /* xDeviceCharacteristics */
+ 0, /* xShmMap */
+ 0, /* xShmLock */
+ 0, /* xShmBarrier */
+ 0 /* xShmUnmap */
+};
+
+/*
+** Open a journal file.
+*/
+SQLITE_PRIVATE int sqlite3JournalOpen(
+ sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */
+ const char *zName, /* Name of the journal file */
+ sqlite3_file *pJfd, /* Preallocated, blank file handle */
+ int flags, /* Opening flags */
+ int nBuf /* Bytes buffered before opening the file */
+){
+ JournalFile *p = (JournalFile *)pJfd;
+ memset(p, 0, sqlite3JournalSize(pVfs));
+ if( nBuf>0 ){
+ p->zBuf = sqlite3MallocZero(nBuf);
+ if( !p->zBuf ){
+ return SQLITE_NOMEM;
+ }
+ }else{
+ return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
+ }
+ p->pMethod = &JournalFileMethods;
+ p->nBuf = nBuf;
+ p->flags = flags;
+ p->zJournal = zName;
+ p->pVfs = pVfs;
+ return SQLITE_OK;
+}
+
+/*
+** If the argument p points to a JournalFile structure, and the underlying
+** file has not yet been created, create it now.
+*/
+SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *p){
+ if( p->pMethods!=&JournalFileMethods ){
+ return SQLITE_OK;
+ }
+ return createFile((JournalFile *)p);
+}
+
+/*
+** The file-handle passed as the only argument is guaranteed to be an open
+** file. It may or may not be of class JournalFile. If the file is a
+** JournalFile, and the underlying file on disk has not yet been opened,
+** return 0. Otherwise, return 1.
+*/
+SQLITE_PRIVATE int sqlite3JournalExists(sqlite3_file *p){
+ return (p->pMethods!=&JournalFileMethods || ((JournalFile *)p)->pReal!=0);
+}
+
+/*
+** Return the number of bytes required to store a JournalFile that uses vfs
+** pVfs to create the underlying on-disk files.
+*/
+SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){
+ return (pVfs->szOsFile+sizeof(JournalFile));
+}
+#endif
+
+/************** End of journal.c *********************************************/
/************** Begin file memjournal.c **************************************/
/*
** 2008 October 7
@@ -86885,46 +80897,32 @@ SQLITE_PRIVATE int sqlite3VdbeSorterCompare(
** This file contains code use to implement an in-memory rollback journal.
** The in-memory rollback journal is used to journal transactions for
** ":memory:" databases and when the journal_mode=MEMORY pragma is used.
-**
-** Update: The in-memory journal is also used to temporarily cache
-** smaller journals that are not critical for power-loss recovery.
-** For example, statement journals that are not too big will be held
-** entirely in memory, thus reducing the number of file I/O calls, and
-** more importantly, reducing temporary file creation events. If these
-** journals become too large for memory, they are spilled to disk. But
-** in the common case, they are usually small and no file I/O needs to
-** occur.
*/
-/* #include "sqliteInt.h" */
/* Forward references to internal structures */
typedef struct MemJournal MemJournal;
typedef struct FilePoint FilePoint;
typedef struct FileChunk FileChunk;
+/* Space to hold the rollback journal is allocated in increments of
+** this many bytes.
+**
+** The size chosen is a little less than a power of two. That way,
+** the FileChunk object will have a size that almost exactly fills
+** a power-of-two allocation. This minimizes wasted space in power-of-two
+** memory allocators.
+*/
+#define JOURNAL_CHUNKSIZE ((int)(1024-sizeof(FileChunk*)))
+
/*
** The rollback journal is composed of a linked list of these structures.
-**
-** The zChunk array is always at least 8 bytes in size - usually much more.
-** Its actual size is stored in the MemJournal.nChunkSize variable.
*/
struct FileChunk {
FileChunk *pNext; /* Next chunk in the journal */
- u8 zChunk[8]; /* Content of this chunk */
+ u8 zChunk[JOURNAL_CHUNKSIZE]; /* Content of this chunk */
};
/*
-** By default, allocate this many bytes of memory for each FileChunk object.
-*/
-#define MEMJOURNAL_DFLT_FILECHUNKSIZE 1024
-
-/*
-** For chunk size nChunkSize, return the number of bytes that should
-** be allocated for each FileChunk structure.
-*/
-#define fileChunkSize(nChunkSize) (sizeof(FileChunk) + ((nChunkSize)-8))
-
-/*
** An instance of this object serves as a cursor into the rollback journal.
** The cursor can be either for reading or writing.
*/
@@ -86934,22 +80932,14 @@ struct FilePoint {
};
/*
-** This structure is a subclass of sqlite3_file. Each open memory-journal
+** This subclass is a subclass of sqlite3_file. Each open memory-journal
** is an instance of this class.
*/
struct MemJournal {
- const sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */
- int nChunkSize; /* In-memory chunk-size */
-
- int nSpill; /* Bytes of data before flushing */
- int nSize; /* Bytes of data currently in memory */
+ sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */
FileChunk *pFirst; /* Head of in-memory chunk-list */
FilePoint endpoint; /* Pointer to the end of the file */
FilePoint readpoint; /* Pointer to the end of the last xRead() */
-
- int flags; /* xOpen flags */
- sqlite3_vfs *pVfs; /* The "real" underlying VFS */
- const char *zJournal; /* Name of the journal file */
};
/*
@@ -86968,95 +80958,37 @@ static int memjrnlRead(
int iChunkOffset;
FileChunk *pChunk;
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
- if( (iAmt+iOfst)>p->endpoint.iOffset ){
- return SQLITE_IOERR_SHORT_READ;
- }
-#endif
+ /* SQLite never tries to read past the end of a rollback journal file */
+ assert( iOfst+iAmt<=p->endpoint.iOffset );
- assert( (iAmt+iOfst)<=p->endpoint.iOffset );
- assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 );
if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
sqlite3_int64 iOff = 0;
for(pChunk=p->pFirst;
- ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst;
+ ALWAYS(pChunk) && (iOff+JOURNAL_CHUNKSIZE)<=iOfst;
pChunk=pChunk->pNext
){
- iOff += p->nChunkSize;
+ iOff += JOURNAL_CHUNKSIZE;
}
}else{
pChunk = p->readpoint.pChunk;
- assert( pChunk!=0 );
}
- iChunkOffset = (int)(iOfst%p->nChunkSize);
+ iChunkOffset = (int)(iOfst%JOURNAL_CHUNKSIZE);
do {
- int iSpace = p->nChunkSize - iChunkOffset;
- int nCopy = MIN(nRead, (p->nChunkSize - iChunkOffset));
- memcpy(zOut, (u8*)pChunk->zChunk + iChunkOffset, nCopy);
+ int iSpace = JOURNAL_CHUNKSIZE - iChunkOffset;
+ int nCopy = MIN(nRead, (JOURNAL_CHUNKSIZE - iChunkOffset));
+ memcpy(zOut, &pChunk->zChunk[iChunkOffset], nCopy);
zOut += nCopy;
nRead -= iSpace;
iChunkOffset = 0;
} while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 );
- p->readpoint.iOffset = pChunk ? iOfst+iAmt : 0;
+ p->readpoint.iOffset = iOfst+iAmt;
p->readpoint.pChunk = pChunk;
return SQLITE_OK;
}
/*
-** Free the list of FileChunk structures headed at MemJournal.pFirst.
-*/
-static void memjrnlFreeChunks(MemJournal *p){
- FileChunk *pIter;
- FileChunk *pNext;
- for(pIter=p->pFirst; pIter; pIter=pNext){
- pNext = pIter->pNext;
- sqlite3_free(pIter);
- }
- p->pFirst = 0;
-}
-
-/*
-** Flush the contents of memory to a real file on disk.
-*/
-static int memjrnlCreateFile(MemJournal *p){
- int rc;
- sqlite3_file *pReal = (sqlite3_file*)p;
- MemJournal copy = *p;
-
- memset(p, 0, sizeof(MemJournal));
- rc = sqlite3OsOpen(copy.pVfs, copy.zJournal, pReal, copy.flags, 0);
- if( rc==SQLITE_OK ){
- int nChunk = copy.nChunkSize;
- i64 iOff = 0;
- FileChunk *pIter;
- for(pIter=copy.pFirst; pIter; pIter=pIter->pNext){
- if( iOff + nChunk > copy.endpoint.iOffset ){
- nChunk = copy.endpoint.iOffset - iOff;
- }
- rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nChunk, iOff);
- if( rc ) break;
- iOff += nChunk;
- }
- if( rc==SQLITE_OK ){
- /* No error has occurred. Free the in-memory buffers. */
- memjrnlFreeChunks(&copy);
- }
- }
- if( rc!=SQLITE_OK ){
- /* If an error occurred while creating or writing to the file, restore
- ** the original before returning. This way, SQLite uses the in-memory
- ** journal data to roll back changes made to the internal page-cache
- ** before this function was called. */
- sqlite3OsClose(pReal);
- *p = copy;
- }
- return rc;
-}
-
-
-/*
** Write data to the file.
*/
static int memjrnlWrite(
@@ -87069,62 +81001,38 @@ static int memjrnlWrite(
int nWrite = iAmt;
u8 *zWrite = (u8 *)zBuf;
- /* If the file should be created now, create it and write the new data
- ** into the file on disk. */
- if( p->nSpill>0 && (iAmt+iOfst)>p->nSpill ){
- int rc = memjrnlCreateFile(p);
- if( rc==SQLITE_OK ){
- rc = sqlite3OsWrite(pJfd, zBuf, iAmt, iOfst);
- }
- return rc;
- }
+ /* An in-memory journal file should only ever be appended to. Random
+ ** access writes are not required by sqlite.
+ */
+ assert( iOfst==p->endpoint.iOffset );
+ UNUSED_PARAMETER(iOfst);
- /* If the contents of this write should be stored in memory */
- else{
- /* An in-memory journal file should only ever be appended to. Random
- ** access writes are not required. The only exception to this is when
- ** the in-memory journal is being used by a connection using the
- ** atomic-write optimization. In this case the first 28 bytes of the
- ** journal file may be written as part of committing the transaction. */
- assert( iOfst==p->endpoint.iOffset || iOfst==0 );
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
- if( iOfst==0 && p->pFirst ){
- assert( p->nChunkSize>iAmt );
- memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
- }else
-#else
- assert( iOfst>0 || p->pFirst==0 );
-#endif
- {
- while( nWrite>0 ){
- FileChunk *pChunk = p->endpoint.pChunk;
- int iChunkOffset = (int)(p->endpoint.iOffset%p->nChunkSize);
- int iSpace = MIN(nWrite, p->nChunkSize - iChunkOffset);
-
- if( iChunkOffset==0 ){
- /* New chunk is required to extend the file. */
- FileChunk *pNew = sqlite3_malloc(fileChunkSize(p->nChunkSize));
- if( !pNew ){
- return SQLITE_IOERR_NOMEM_BKPT;
- }
- pNew->pNext = 0;
- if( pChunk ){
- assert( p->pFirst );
- pChunk->pNext = pNew;
- }else{
- assert( !p->pFirst );
- p->pFirst = pNew;
- }
- p->endpoint.pChunk = pNew;
- }
+ while( nWrite>0 ){
+ FileChunk *pChunk = p->endpoint.pChunk;
+ int iChunkOffset = (int)(p->endpoint.iOffset%JOURNAL_CHUNKSIZE);
+ int iSpace = MIN(nWrite, JOURNAL_CHUNKSIZE - iChunkOffset);
- memcpy((u8*)p->endpoint.pChunk->zChunk + iChunkOffset, zWrite, iSpace);
- zWrite += iSpace;
- nWrite -= iSpace;
- p->endpoint.iOffset += iSpace;
+ if( iChunkOffset==0 ){
+ /* New chunk is required to extend the file. */
+ FileChunk *pNew = sqlite3_malloc(sizeof(FileChunk));
+ if( !pNew ){
+ return SQLITE_IOERR_NOMEM;
}
- p->nSize = iAmt + iOfst;
+ pNew->pNext = 0;
+ if( pChunk ){
+ assert( p->pFirst );
+ pChunk->pNext = pNew;
+ }else{
+ assert( !p->pFirst );
+ p->pFirst = pNew;
+ }
+ p->endpoint.pChunk = pNew;
}
+
+ memcpy(&p->endpoint.pChunk->zChunk[iChunkOffset], zWrite, iSpace);
+ zWrite += iSpace;
+ nWrite -= iSpace;
+ p->endpoint.iOffset += iSpace;
}
return SQLITE_OK;
@@ -87132,21 +81040,19 @@ static int memjrnlWrite(
/*
** Truncate the file.
-**
-** If the journal file is already on disk, truncate it there. Or, if it
-** is still in main memory but is being truncated to zero bytes in size,
-** ignore
*/
static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
MemJournal *p = (MemJournal *)pJfd;
- if( ALWAYS(size==0) ){
- memjrnlFreeChunks(p);
- p->nSize = 0;
- p->endpoint.pChunk = 0;
- p->endpoint.iOffset = 0;
- p->readpoint.pChunk = 0;
- p->readpoint.iOffset = 0;
- }
+ FileChunk *pChunk;
+ assert(size==0);
+ UNUSED_PARAMETER(size);
+ pChunk = p->pFirst;
+ while( pChunk ){
+ FileChunk *pTmp = pChunk;
+ pChunk = pChunk->pNext;
+ sqlite3_free(pTmp);
+ }
+ sqlite3MemJournalOpen(pJfd);
return SQLITE_OK;
}
@@ -87154,19 +81060,21 @@ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
** Close the file.
*/
static int memjrnlClose(sqlite3_file *pJfd){
- MemJournal *p = (MemJournal *)pJfd;
- memjrnlFreeChunks(p);
+ memjrnlTruncate(pJfd, 0);
return SQLITE_OK;
}
+
/*
** Sync the file.
**
-** If the real file has been created, call its xSync method. Otherwise,
-** syncing an in-memory journal is a no-op.
+** Syncing an in-memory journal is a no-op. And, in fact, this routine
+** is never called in a working implementation. This implementation
+** exists purely as a contingency, in case some malfunction in some other
+** part of SQLite causes Sync to be called by mistake.
*/
-static int memjrnlSync(sqlite3_file *pJfd, int flags){
- UNUSED_PARAMETER2(pJfd, flags);
+static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){
+ UNUSED_PARAMETER2(NotUsed, NotUsed2);
return SQLITE_OK;
}
@@ -87205,88 +81113,28 @@ static const struct sqlite3_io_methods MemJournalMethods = {
};
/*
-** Open a journal file.
-**
-** The behaviour of the journal file depends on the value of parameter
-** nSpill. If nSpill is 0, then the journal file is always create and
-** accessed using the underlying VFS. If nSpill is less than zero, then
-** all content is always stored in main-memory. Finally, if nSpill is a
-** positive value, then the journal file is initially created in-memory
-** but may be flushed to disk later on. In this case the journal file is
-** flushed to disk either when it grows larger than nSpill bytes in size,
-** or when sqlite3JournalCreate() is called.
-*/
-SQLITE_PRIVATE int sqlite3JournalOpen(
- sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */
- const char *zName, /* Name of the journal file */
- sqlite3_file *pJfd, /* Preallocated, blank file handle */
- int flags, /* Opening flags */
- int nSpill /* Bytes buffered before opening the file */
-){
- MemJournal *p = (MemJournal*)pJfd;
-
- /* Zero the file-handle object. If nSpill was passed zero, initialize
- ** it using the sqlite3OsOpen() function of the underlying VFS. In this
- ** case none of the code in this module is executed as a result of calls
- ** made on the journal file-handle. */
- memset(p, 0, sizeof(MemJournal));
- if( nSpill==0 ){
- return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
- }
-
- if( nSpill>0 ){
- p->nChunkSize = nSpill;
- }else{
- p->nChunkSize = 8 + MEMJOURNAL_DFLT_FILECHUNKSIZE - sizeof(FileChunk);
- assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) );
- }
-
- p->pMethod = (const sqlite3_io_methods*)&MemJournalMethods;
- p->nSpill = nSpill;
- p->flags = flags;
- p->zJournal = zName;
- p->pVfs = pVfs;
- return SQLITE_OK;
-}
-
-/*
-** Open an in-memory journal file.
+** Open a journal file.
*/
SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *pJfd){
- sqlite3JournalOpen(0, 0, pJfd, 0, -1);
-}
-
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
-/*
-** If the argument p points to a MemJournal structure that is not an
-** in-memory-only journal file (i.e. is one that was opened with a +ve
-** nSpill parameter), and the underlying file has not yet been created,
-** create it now.
-*/
-SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *p){
- int rc = SQLITE_OK;
- if( p->pMethods==&MemJournalMethods && ((MemJournal*)p)->nSpill>0 ){
- rc = memjrnlCreateFile((MemJournal*)p);
- }
- return rc;
+ MemJournal *p = (MemJournal *)pJfd;
+ assert( EIGHT_BYTE_ALIGNMENT(p) );
+ memset(p, 0, sqlite3MemJournalSize());
+ p->pMethod = (sqlite3_io_methods*)&MemJournalMethods;
}
-#endif
/*
-** The file-handle passed as the only argument is open on a journal file.
-** Return true if this "journal file" is currently stored in heap memory,
-** or false otherwise.
+** Return true if the file-handle passed as an argument is
+** an in-memory journal
*/
-SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p){
- return p->pMethods==&MemJournalMethods;
+SQLITE_PRIVATE int sqlite3IsMemJournal(sqlite3_file *pJfd){
+ return pJfd->pMethods==&MemJournalMethods;
}
/*
-** Return the number of bytes required to store a JournalFile 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 sqlite3JournalSize(sqlite3_vfs *pVfs){
- return MAX(pVfs->szOsFile, (int)sizeof(MemJournal));
+SQLITE_PRIVATE int sqlite3MemJournalSize(void){
+ return sizeof(MemJournal);
}
/************** End of memjournal.c ******************************************/
@@ -87305,7 +81153,6 @@ SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){
** This file contains routines used for walking the parser tree for
** an SQL statement.
*/
-/* #include "sqliteInt.h" */
/* #include <stdlib.h> */
/* #include <string.h> */
@@ -87329,8 +81176,9 @@ SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){
** The return value from this routine is WRC_Abort to abandon the tree walk
** and WRC_Continue to continue.
*/
-static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
+SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
int rc;
+ if( pExpr==0 ) return WRC_Continue;
testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
testcase( ExprHasProperty(pExpr, EP_Reduced) );
rc = pWalker->xExprCallback(pWalker, pExpr);
@@ -87346,9 +81194,6 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
}
return rc & WRC_Abort;
}
-SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
- return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue;
-}
/*
** Call sqlite3WalkExpr() for every expression in list p or until
@@ -87400,11 +81245,6 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
if( sqlite3WalkSelect(pWalker, pItem->pSelect) ){
return WRC_Abort;
}
- if( pItem->fg.isTabFunc
- && sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg)
- ){
- return WRC_Abort;
- }
}
}
return WRC_Continue;
@@ -87471,7 +81311,6 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){
** resolve all identifiers by associating them with a particular
** table and column.
*/
-/* #include "sqliteInt.h" */
/* #include <stdlib.h> */
/* #include <string.h> */
@@ -87502,6 +81341,30 @@ static void incrAggFunctionDepth(Expr *pExpr, int N){
** Turn the pExpr expression into an alias for the iCol-th column of the
** result set in pEList.
**
+** If the result set column is a simple column reference, then this routine
+** makes an exact copy. But for any other kind of expression, this
+** routine make a copy of the result set column as the argument to the
+** TK_AS operator. The TK_AS operator causes the expression to be
+** evaluated just once and then reused for each alias.
+**
+** The reason for suppressing the TK_AS term when the expression is a simple
+** column reference is so that the column reference will be recognized as
+** usable by indices within the WHERE clause processing logic.
+**
+** The TK_AS operator is inhibited if zType[0]=='G'. This means
+** that in a GROUP BY clause, the expression is evaluated twice. Hence:
+**
+** SELECT random()%5 AS x, count(*) FROM tab GROUP BY x
+**
+** Is equivalent to:
+**
+** SELECT random()%5 AS x, count(*) FROM tab GROUP BY random()%5
+**
+** The result of random()%5 in the GROUP BY clause is probably different
+** from the result in the result-set. On the other hand Standard SQL does
+** not allow the GROUP BY clause to contain references to result-set columns.
+** So this should never come up in well-formed queries.
+**
** If the reference is followed by a COLLATE operator, then make sure
** the COLLATE operator is preserved. For example:
**
@@ -87535,11 +81398,19 @@ static void resolveAlias(
db = pParse->db;
pDup = sqlite3ExprDup(db, pOrig, 0);
if( pDup==0 ) return;
- if( zType[0]!='G' ) incrAggFunctionDepth(pDup, nSubquery);
+ if( pOrig->op!=TK_COLUMN && zType[0]!='G' ){
+ incrAggFunctionDepth(pDup, nSubquery);
+ pDup = sqlite3PExpr(pParse, TK_AS, pDup, 0, 0);
+ if( pDup==0 ) return;
+ ExprSetProperty(pDup, EP_Skip);
+ if( pEList->a[iCol].u.x.iAlias==0 ){
+ pEList->a[iCol].u.x.iAlias = (u16)(++pParse->nAlias);
+ }
+ pDup->iTable = pEList->a[iCol].u.x.iAlias;
+ }
if( pExpr->op==TK_COLLATE ){
pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken);
}
- ExprSetProperty(pDup, EP_Alias);
/* Before calling sqlite3ExprDelete(), set the EP_Static flag. This
** prevents ExprDelete() from deleting the Expr structure itself,
@@ -87731,7 +81602,7 @@ static int lookupName(
** USING clause, then skip this match.
*/
if( cnt==1 ){
- if( pItem->fg.jointype & JT_NATURAL ) continue;
+ if( pItem->jointype & JT_NATURAL ) continue;
if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
}
cnt++;
@@ -87746,8 +81617,8 @@ static int lookupName(
pExpr->iTable = pMatch->iCursor;
pExpr->pTab = pMatch->pTab;
/* RIGHT JOIN not (yet) supported */
- assert( (pMatch->fg.jointype & JT_RIGHT)==0 );
- if( (pMatch->fg.jointype & JT_LEFT)!=0 ){
+ assert( (pMatch->jointype & JT_RIGHT)==0 );
+ if( (pMatch->jointype & JT_LEFT)!=0 ){
ExprSetProperty(pExpr, EP_CanBeNull);
}
pSchema = pExpr->pTab->pSchema;
@@ -87783,8 +81654,9 @@ static int lookupName(
break;
}
}
- if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && VisibleRowid(pTab) ){
+ if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && HasRowid(pTab) ){
/* IMP: R-51414-32910 */
+ /* IMP: R-44911-55124 */
iCol = -1;
}
if( iCol<pTab->nCol ){
@@ -87811,15 +81683,10 @@ static int lookupName(
/*
** Perhaps the name is a reference to the ROWID
*/
- if( cnt==0
- && cntTab==1
- && pMatch
- && (pNC->ncFlags & NC_IdxExpr)==0
- && sqlite3IsRowid(zCol)
- && VisibleRowid(pMatch->pTab)
- ){
+ if( cnt==0 && cntTab==1 && pMatch && sqlite3IsRowid(zCol)
+ && HasRowid(pMatch->pTab) ){
cnt = 1;
- pExpr->iColumn = -1;
+ pExpr->iColumn = -1; /* IMP: R-44911-55124 */
pExpr->affinity = SQLITE_AFF_INTEGER;
}
@@ -87836,9 +81703,9 @@ static int lookupName(
** resolved by the time the WHERE clause is resolved.
**
** The ability to use an output result-set column in the WHERE, GROUP BY,
- ** or HAVING clauses, or as part of a larger expression in the ORDER BY
+ ** or HAVING clauses, or as part of a larger expression in the ORDRE BY
** clause is not standard SQL. This is a (goofy) SQLite extension, that
- ** is supported for backwards compatibility only. Hence, we issue a warning
+ ** is supported for backwards compatibility only. TO DO: Issue a warning
** on sqlite3_log() whenever the capability is used.
*/
if( (pEList = pNC->pEList)!=0
@@ -87935,7 +81802,7 @@ static int lookupName(
lookupname_end:
if( cnt==1 ){
assert( pNC!=0 );
- if( !ExprHasProperty(pExpr, EP_Alias) ){
+ if( pExpr->op!=TK_AS ){
sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList);
}
/* Increment the nRef value on all name contexts from TopNC up to
@@ -87976,25 +81843,36 @@ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSr
}
/*
-** Report an error that an expression is not valid for some set of
-** pNC->ncFlags values determined by validMask.
+** Report an error that an expression is not valid for a partial index WHERE
+** clause.
*/
-static void notValid(
+static void notValidPartIdxWhere(
Parse *pParse, /* Leave error message here */
NameContext *pNC, /* The name context */
- const char *zMsg, /* Type of error */
- int validMask /* Set of contexts for which prohibited */
+ const char *zMsg /* Type of error */
){
- assert( (validMask&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr))==0 );
- if( (pNC->ncFlags & validMask)!=0 ){
- const char *zIn = "partial index WHERE clauses";
- if( pNC->ncFlags & NC_IdxExpr ) zIn = "index expressions";
+ if( (pNC->ncFlags & NC_PartIdx)!=0 ){
+ sqlite3ErrorMsg(pParse, "%s prohibited in partial index WHERE clauses",
+ zMsg);
+ }
+}
+
#ifndef SQLITE_OMIT_CHECK
- else if( pNC->ncFlags & NC_IsCheck ) zIn = "CHECK constraints";
-#endif
- sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn);
+/*
+** Report an error that an expression is not valid for a CHECK constraint.
+*/
+static void notValidCheckConstraint(
+ Parse *pParse, /* Leave error message here */
+ NameContext *pNC, /* The name context */
+ const char *zMsg /* Type of error */
+){
+ if( (pNC->ncFlags & NC_IsCheck)!=0 ){
+ sqlite3ErrorMsg(pParse,"%s prohibited in CHECK constraints", zMsg);
}
}
+#else
+# define notValidCheckConstraint(P,N,M)
+#endif
/*
** Expression p should encode a floating point value between 1.0 and 0.0.
@@ -88079,8 +81957,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
Expr *pRight;
/* if( pSrcList==0 ) break; */
- notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr);
- /*notValid(pParse, pNC, "the \".\" operator", NC_PartIdx|NC_IsCheck, 1);*/
pRight = pExpr->pRight;
if( pRight->op==TK_ID ){
zDb = 0;
@@ -88110,19 +81986,19 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
u8 enc = ENC(pParse->db); /* The database encoding */
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
- notValid(pParse, pNC, "functions", NC_PartIdx);
+ notValidPartIdxWhere(pParse, pNC, "functions");
zId = pExpr->u.zToken;
nId = sqlite3Strlen30(zId);
- pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0);
+ pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
if( pDef==0 ){
- pDef = sqlite3FindFunction(pParse->db, zId, -2, enc, 0);
+ pDef = sqlite3FindFunction(pParse->db, zId, nId, -2, enc, 0);
if( pDef==0 ){
no_such_func = 1;
}else{
wrong_num_args = 1;
}
}else{
- is_agg = pDef->xFinalize!=0;
+ is_agg = pDef->xFunc==0;
if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){
ExprSetProperty(pExpr, EP_Unlikely|EP_Skip);
if( n==2 ){
@@ -88158,18 +82034,9 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
return WRC_Prune;
}
#endif
- if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){
- /* For the purposes of the EP_ConstFunc flag, date and time
- ** functions and other functions that change slowly are considered
- ** constant because they are constant for the duration of one query */
+ if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ){
ExprSetProperty(pExpr,EP_ConstFunc);
}
- if( (pDef->funcFlags & SQLITE_FUNC_CONSTANT)==0 ){
- /* Date/time functions that use 'now', and other functions like
- ** sqlite_version() that might change over time cannot be used
- ** in an index. */
- notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr);
- }
}
if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
@@ -88215,18 +82082,19 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
testcase( pExpr->op==TK_IN );
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
int nRef = pNC->nRef;
- notValid(pParse, pNC, "subqueries", NC_IsCheck|NC_PartIdx|NC_IdxExpr);
+ notValidCheckConstraint(pParse, pNC, "subqueries");
+ notValidPartIdxWhere(pParse, pNC, "subqueries");
sqlite3WalkSelect(pWalker, pExpr->x.pSelect);
assert( pNC->nRef>=nRef );
if( nRef!=pNC->nRef ){
ExprSetProperty(pExpr, EP_VarSelect);
- pNC->ncFlags |= NC_VarSelect;
}
}
break;
}
case TK_VARIABLE: {
- notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr);
+ notValidCheckConstraint(pParse, pNC, "parameters");
+ notValidPartIdxWhere(pParse, pNC, "parameters");
break;
}
}
@@ -88570,6 +82438,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
int isCompound; /* True if p is a compound select */
int nCompound; /* Number of compound terms processed so far */
Parse *pParse; /* Parsing context */
+ ExprList *pEList; /* Result set expression list */
int i; /* Loop counter */
ExprList *pGroupBy; /* The GROUP BY clause */
Select *pLeftmost; /* Left-most of SELECT of a compound */
@@ -88642,7 +82511,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
** parent contexts. After resolving references to expressions in
** pItem->pSelect, check if this value has changed. If so, then
** SELECT statement pItem->pSelect must be correlated. Set the
- ** pItem->fg.isCorrelated flag if this is the case. */
+ ** pItem->isCorrelated flag if this is the case. */
for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef += pNC->nRef;
if( pItem->zName ) pParse->zAuthContext = pItem->zName;
@@ -88651,8 +82520,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
if( pParse->nErr || db->mallocFailed ) return WRC_Abort;
for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef -= pNC->nRef;
- assert( pItem->fg.isCorrelated==0 && nRef<=0 );
- pItem->fg.isCorrelated = (nRef!=0);
+ assert( pItem->isCorrelated==0 && nRef<=0 );
+ pItem->isCorrelated = (nRef!=0);
}
}
@@ -88664,7 +82533,14 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
sNC.pNext = pOuterNC;
/* Resolve names in the result set. */
- if( sqlite3ResolveExprListNames(&sNC, p->pEList) ) return WRC_Abort;
+ pEList = p->pEList;
+ assert( pEList!=0 );
+ for(i=0; i<pEList->nExpr; i++){
+ Expr *pX = pEList->a[i].pExpr;
+ if( sqlite3ResolveExprNames(&sNC, pX) ){
+ return WRC_Abort;
+ }
+ }
/* If there are no aggregate functions in the result-set, and no GROUP BY
** expression, do not allow aggregates in any of the other expressions.
@@ -88697,16 +82573,6 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
- /* Resolve names in table-valued-function arguments */
- for(i=0; i<p->pSrc->nSrc; i++){
- struct SrcList_item *pItem = &p->pSrc->a[i];
- if( pItem->fg.isTabFunc
- && sqlite3ResolveExprListNames(&sNC, pItem->u1.pFuncArg)
- ){
- return WRC_Abort;
- }
- }
-
/* The ORDER BY and GROUP BY clauses may not refer to terms in
** outer queries
*/
@@ -88761,13 +82627,6 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
}
}
- /* If this is part of a compound SELECT, check that it has the right
- ** number of expressions in the select list. */
- if( p->pNext && p->pEList->nExpr!=p->pNext->pEList->nExpr ){
- sqlite3SelectWrongNumTermsError(pParse, p->pNext);
- return WRC_Abort;
- }
-
/* Advance to the next term of the compound
*/
p = p->pPrior;
@@ -88851,12 +82710,10 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
#endif
savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg);
pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg);
- w.pParse = pNC->pParse;
+ memset(&w, 0, sizeof(w));
w.xExprCallback = resolveExprStep;
w.xSelectCallback = resolveSelectStep;
- w.xSelectCallback2 = 0;
- w.walkerDepth = 0;
- w.eCode = 0;
+ w.pParse = pNC->pParse;
w.u.pNC = pNC;
sqlite3WalkExpr(&w, pExpr);
#if SQLITE_MAX_EXPR_DEPTH>0
@@ -88872,23 +82729,6 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
return ExprHasProperty(pExpr, EP_Error);
}
-/*
-** Resolve all names for all expression in an expression list. This is
-** just like sqlite3ResolveExprNames() except that it works for an expression
-** list rather than a single expression.
-*/
-SQLITE_PRIVATE int sqlite3ResolveExprListNames(
- NameContext *pNC, /* Namespace to resolve expressions in. */
- ExprList *pList /* The expression list to be analyzed. */
-){
- int i;
- if( pList ){
- for(i=0; i<pList->nExpr; i++){
- if( sqlite3ResolveExprNames(pNC, pList->a[i].pExpr) ) return WRC_Abort;
- }
- }
- return WRC_Continue;
-}
/*
** Resolve all names in all expressions of a SELECT and in all
@@ -88932,14 +82772,15 @@ SQLITE_PRIVATE void sqlite3ResolveSelectNames(
SQLITE_PRIVATE void sqlite3ResolveSelfReference(
Parse *pParse, /* Parsing context */
Table *pTab, /* The table being referenced */
- int type, /* NC_IsCheck or NC_PartIdx or NC_IdxExpr */
+ int type, /* NC_IsCheck or NC_PartIdx */
Expr *pExpr, /* Expression to resolve. May be NULL. */
ExprList *pList /* Expression list to resolve. May be NUL. */
){
SrcList sSrc; /* Fake SrcList for pParse->pNewTable */
NameContext sNC; /* Name context for pParse->pNewTable */
+ int i; /* Loop counter */
- assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr );
+ assert( type==NC_IsCheck || type==NC_PartIdx );
memset(&sNC, 0, sizeof(sNC));
memset(&sSrc, 0, sizeof(sSrc));
sSrc.nSrc = 1;
@@ -88950,7 +82791,13 @@ SQLITE_PRIVATE void sqlite3ResolveSelfReference(
sNC.pSrcList = &sSrc;
sNC.ncFlags = type;
if( sqlite3ResolveExprNames(&sNC, pExpr) ) return;
- if( pList ) sqlite3ResolveExprListNames(&sNC, pList);
+ if( pList ){
+ for(i=0; i<pList->nExpr; i++){
+ if( sqlite3ResolveExprNames(&sNC, pList->a[i].pExpr) ){
+ return;
+ }
+ }
+ }
}
/************** End of resolve.c *********************************************/
@@ -88969,7 +82816,6 @@ SQLITE_PRIVATE void sqlite3ResolveSelfReference(
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
*/
-/* #include "sqliteInt.h" */
/*
** Return the 'affinity' of the expression pExpr if any.
@@ -89042,12 +82888,13 @@ SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){
Token s;
assert( zC!=0 );
- sqlite3TokenInit(&s, (char*)zC);
+ s.z = zC;
+ s.n = sqlite3Strlen30(s.z);
return sqlite3ExprAddCollateToken(pParse, pExpr, &s, 0);
}
/*
-** Skip over any TK_COLLATE operators and any unlikely()
+** Skip over any TK_COLLATE or TK_AS operators and any unlikely()
** or likelihood() function at the root of an expression.
*/
SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){
@@ -89058,7 +82905,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){
assert( pExpr->op==TK_FUNCTION );
pExpr = pExpr->x.pList->a[0].pExpr;
}else{
- assert( pExpr->op==TK_COLLATE );
+ assert( pExpr->op==TK_COLLATE || pExpr->op==TK_AS );
pExpr = pExpr->pLeft;
}
}
@@ -89147,13 +82994,13 @@ SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2){
if( sqlite3IsNumericAffinity(aff1) || sqlite3IsNumericAffinity(aff2) ){
return SQLITE_AFF_NUMERIC;
}else{
- return SQLITE_AFF_BLOB;
+ return SQLITE_AFF_NONE;
}
}else if( !aff1 && !aff2 ){
/* Neither side of the comparison is a column. Compare the
** results directly.
*/
- return SQLITE_AFF_BLOB;
+ return SQLITE_AFF_NONE;
}else{
/* One side is a column, the other is not. Use the columns affinity. */
assert( aff1==0 || aff2==0 );
@@ -89177,7 +83024,7 @@ static char comparisonAffinity(Expr *pExpr){
}else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff);
}else if( !aff ){
- aff = SQLITE_AFF_BLOB;
+ aff = SQLITE_AFF_NONE;
}
return aff;
}
@@ -89191,7 +83038,7 @@ static char comparisonAffinity(Expr *pExpr){
SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){
char aff = comparisonAffinity(pExpr);
switch( aff ){
- case SQLITE_AFF_BLOB:
+ case SQLITE_AFF_NONE:
return 1;
case SQLITE_AFF_TEXT:
return idx_affinity==SQLITE_AFF_TEXT;
@@ -89389,7 +83236,7 @@ SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
** is responsible for making sure the node eventually gets freed.
**
** If dequote is true, then the token (if it exists) is dequoted.
-** If dequote is false, no dequoting is performed. The deQuote
+** If dequote is false, no dequoting is performance. The deQuote
** parameter is ignored if pToken is NULL or if the token does not
** appear to be quoted. If the quotes were of the form "..." (double-quotes)
** then the EP_DblQuoted flag is set on the expression node.
@@ -89410,7 +83257,6 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc(
int nExtra = 0;
int iValue = 0;
- assert( db!=0 );
if( pToken ){
if( op!=TK_INTEGER || pToken->z==0
|| sqlite3GetInt32(pToken->z, &iValue)==0 ){
@@ -89418,9 +83264,8 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc(
assert( iValue>=0 );
}
}
- pNew = sqlite3DbMallocRawNN(db, sizeof(Expr)+nExtra);
+ pNew = sqlite3DbMallocZero(db, sizeof(Expr)+nExtra);
if( pNew ){
- memset(pNew, 0, sizeof(Expr));
pNew->op = (u8)op;
pNew->iAgg = -1;
if( pToken ){
@@ -89428,13 +83273,15 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc(
pNew->flags |= EP_IntValue;
pNew->u.iValue = iValue;
}else{
+ int c;
pNew->u.zToken = (char*)&pNew[1];
assert( pToken->z!=0 || pToken->n==0 );
if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n);
pNew->u.zToken[pToken->n] = 0;
- if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){
- if( pNew->u.zToken[0]=='"' ) pNew->flags |= EP_DblQuoted;
+ if( dequote && nExtra>=3
+ && ((c = pToken->z[0])=='\'' || c=='"' || c=='[' || c=='`') ){
sqlite3Dequote(pNew->u.zToken);
+ if( c=='"' ) pNew->flags |= EP_DblQuoted;
}
}
}
@@ -89504,11 +83351,11 @@ SQLITE_PRIVATE Expr *sqlite3PExpr(
const Token *pToken /* Argument token */
){
Expr *p;
- if( op==TK_AND && pParse->nErr==0 ){
+ if( op==TK_AND && pLeft && pRight && pParse->nErr==0 ){
/* Take advantage of short-circuit false optimization for AND */
p = sqlite3ExprAnd(pParse->db, pLeft, pRight);
}else{
- p = sqlite3ExprAlloc(pParse->db, op & TKFLG_MASK, pToken, 1);
+ p = sqlite3ExprAlloc(pParse->db, op, pToken, 1);
sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight);
}
if( p ) {
@@ -89518,22 +83365,6 @@ SQLITE_PRIVATE Expr *sqlite3PExpr(
}
/*
-** Add pSelect to the Expr.x.pSelect field. Or, if pExpr is NULL (due
-** do a memory allocation failure) then delete the pSelect object.
-*/
-SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pSelect){
- if( pExpr ){
- pExpr->x.pSelect = pSelect;
- ExprSetProperty(pExpr, EP_xIsSelect|EP_Subquery);
- sqlite3ExprSetHeightAndFlags(pParse, pExpr);
- }else{
- assert( pParse->db->mallocFailed );
- sqlite3SelectDelete(pParse->db, pSelect);
- }
-}
-
-
-/*
** If the expression is always either TRUE or FALSE (respectively),
** then return 1. If one cannot determine the truth value of the
** expression at compile-time return 0.
@@ -89671,10 +83502,7 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
if( x>pParse->nzVar ){
char **a;
a = sqlite3DbRealloc(db, pParse->azVar, x*sizeof(a[0]));
- if( a==0 ){
- assert( db->mallocFailed ); /* Error reported through mallocFailed */
- return;
- }
+ if( a==0 ) return; /* Error reported through db->mallocFailed */
pParse->azVar = a;
memset(&a[pParse->nzVar], 0, (x-pParse->nzVar)*sizeof(a[0]));
pParse->nzVar = x;
@@ -89693,8 +83521,8 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
/*
** Recursively delete an expression tree.
*/
-static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
- assert( p!=0 );
+SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){
+ if( p==0 ) return;
/* Sanity check: Assert that the IntValue is non-negative if it exists */
assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 );
if( !ExprHasProperty(p, EP_TokenOnly) ){
@@ -89713,9 +83541,6 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
sqlite3DbFree(db, p);
}
}
-SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){
- if( p ) sqlite3ExprDeleteNN(db, p);
-}
/*
** Return the number of bytes allocated for the expression structure
@@ -89767,7 +83592,7 @@ static int dupedExprStructSize(Expr *p, int flags){
assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */
assert( EXPR_FULLSIZE<=0xfff );
assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 );
- if( 0==flags ){
+ if( 0==(flags&EXPRDUP_REDUCE) ){
nSize = EXPR_FULLSIZE;
}else{
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
@@ -89829,88 +83654,84 @@ static int dupedExprSize(Expr *p, int flags){
** if any. Before returning, *pzBuffer is set to the first byte past the
** portion of the buffer copied into by this function.
*/
-static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
- Expr *pNew; /* Value to return */
- u8 *zAlloc; /* Memory space from which to build Expr object */
- u32 staticFlag; /* EP_Static if space not obtained from malloc */
-
- assert( db!=0 );
- assert( p );
- assert( dupFlags==0 || dupFlags==EXPRDUP_REDUCE );
- assert( pzBuffer==0 || dupFlags==EXPRDUP_REDUCE );
+static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
+ Expr *pNew = 0; /* Value to return */
+ if( p ){
+ const int isReduced = (flags&EXPRDUP_REDUCE);
+ u8 *zAlloc;
+ u32 staticFlag = 0;
- /* Figure out where to write the new Expr structure. */
- if( pzBuffer ){
- zAlloc = *pzBuffer;
- staticFlag = EP_Static;
- }else{
- zAlloc = sqlite3DbMallocRawNN(db, dupedExprSize(p, dupFlags));
- staticFlag = 0;
- }
- pNew = (Expr *)zAlloc;
+ assert( pzBuffer==0 || isReduced );
- if( pNew ){
- /* Set nNewSize to the size allocated for the structure pointed to
- ** by pNew. This is either EXPR_FULLSIZE, EXPR_REDUCEDSIZE or
- ** EXPR_TOKENONLYSIZE. nToken is set to the number of bytes consumed
- ** by the copy of the p->u.zToken string (if any).
- */
- const unsigned nStructSize = dupedExprStructSize(p, dupFlags);
- const int nNewSize = nStructSize & 0xfff;
- int nToken;
- if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
- nToken = sqlite3Strlen30(p->u.zToken) + 1;
+ /* Figure out where to write the new Expr structure. */
+ if( pzBuffer ){
+ zAlloc = *pzBuffer;
+ staticFlag = EP_Static;
}else{
- nToken = 0;
+ zAlloc = sqlite3DbMallocRaw(db, dupedExprSize(p, flags));
}
- if( dupFlags ){
- assert( ExprHasProperty(p, EP_Reduced)==0 );
- memcpy(zAlloc, p, nNewSize);
- }else{
- u32 nSize = (u32)exprStructSize(p);
- memcpy(zAlloc, p, nSize);
- if( nSize<EXPR_FULLSIZE ){
+ pNew = (Expr *)zAlloc;
+
+ if( pNew ){
+ /* Set nNewSize to the size allocated for the structure pointed to
+ ** by pNew. This is either EXPR_FULLSIZE, EXPR_REDUCEDSIZE or
+ ** EXPR_TOKENONLYSIZE. nToken is set to the number of bytes consumed
+ ** by the copy of the p->u.zToken string (if any).
+ */
+ const unsigned nStructSize = dupedExprStructSize(p, flags);
+ const int nNewSize = nStructSize & 0xfff;
+ int nToken;
+ if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
+ nToken = sqlite3Strlen30(p->u.zToken) + 1;
+ }else{
+ nToken = 0;
+ }
+ if( isReduced ){
+ assert( ExprHasProperty(p, EP_Reduced)==0 );
+ memcpy(zAlloc, p, nNewSize);
+ }else{
+ int nSize = exprStructSize(p);
+ memcpy(zAlloc, p, nSize);
memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
}
- }
- /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
- pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
- pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
- pNew->flags |= staticFlag;
-
- /* Copy the p->u.zToken string, if any. */
- if( nToken ){
- char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize];
- memcpy(zToken, p->u.zToken, nToken);
- }
+ /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
+ pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
+ pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
+ pNew->flags |= staticFlag;
- if( 0==((p->flags|pNew->flags) & EP_TokenOnly) ){
- /* Fill in the pNew->x.pSelect or pNew->x.pList member. */
- if( ExprHasProperty(p, EP_xIsSelect) ){
- pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags);
- }else{
- pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags);
+ /* Copy the p->u.zToken string, if any. */
+ if( nToken ){
+ char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize];
+ memcpy(zToken, p->u.zToken, nToken);
}
- }
- /* Fill in pNew->pLeft and pNew->pRight. */
- if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){
- zAlloc += dupedExprNodeSize(p, dupFlags);
- if( ExprHasProperty(pNew, EP_Reduced) ){
- pNew->pLeft = p->pLeft ?
- exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc) : 0;
- pNew->pRight = p->pRight ?
- exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc) : 0;
- }
- if( pzBuffer ){
- *pzBuffer = zAlloc;
+ if( 0==((p->flags|pNew->flags) & EP_TokenOnly) ){
+ /* Fill in the pNew->x.pSelect or pNew->x.pList member. */
+ if( ExprHasProperty(p, EP_xIsSelect) ){
+ pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, isReduced);
+ }else{
+ pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, isReduced);
+ }
}
- }else{
- if( !ExprHasProperty(p, EP_TokenOnly) ){
- pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
- pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
+
+ /* Fill in pNew->pLeft and pNew->pRight. */
+ if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){
+ zAlloc += dupedExprNodeSize(p, flags);
+ if( ExprHasProperty(pNew, EP_Reduced) ){
+ pNew->pLeft = exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc);
+ pNew->pRight = exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc);
+ }
+ if( pzBuffer ){
+ *pzBuffer = zAlloc;
+ }
+ }else{
+ if( !ExprHasProperty(p, EP_TokenOnly) ){
+ pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
+ pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
+ }
}
+
}
}
return pNew;
@@ -89961,20 +83782,18 @@ static With *withDup(sqlite3 *db, With *p){
** part of the in-memory representation of the database schema.
*/
SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3 *db, Expr *p, int flags){
- assert( flags==0 || flags==EXPRDUP_REDUCE );
- return p ? exprDup(db, p, flags, 0) : 0;
+ return exprDup(db, p, flags, 0);
}
SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
ExprList *pNew;
struct ExprList_item *pItem, *pOldItem;
int i;
- assert( db!=0 );
if( p==0 ) return 0;
- pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
+ pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
if( pNew==0 ) return 0;
pNew->nExpr = i = p->nExpr;
if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; i<p->nExpr; i+=i){}
- pNew->a = pItem = sqlite3DbMallocRawNN(db, i*sizeof(p->a[0]) );
+ pNew->a = pItem = sqlite3DbMallocRaw(db, i*sizeof(p->a[0]) );
if( pItem==0 ){
sqlite3DbFree(db, pNew);
return 0;
@@ -90005,10 +83824,9 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
SrcList *pNew;
int i;
int nByte;
- assert( db!=0 );
if( p==0 ) return 0;
nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0);
- pNew = sqlite3DbMallocRawNN(db, nByte );
+ pNew = sqlite3DbMallocRaw(db, nByte );
if( pNew==0 ) return 0;
pNew->nSrc = pNew->nAlloc = p->nSrc;
for(i=0; i<p->nSrc; i++){
@@ -90019,18 +83837,16 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
- pNewItem->fg = pOldItem->fg;
+ pNewItem->jointype = pOldItem->jointype;
pNewItem->iCursor = pOldItem->iCursor;
pNewItem->addrFillSub = pOldItem->addrFillSub;
pNewItem->regReturn = pOldItem->regReturn;
- if( pNewItem->fg.isIndexedBy ){
- pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy);
- }
- pNewItem->pIBIndex = pOldItem->pIBIndex;
- if( pNewItem->fg.isTabFunc ){
- pNewItem->u1.pFuncArg =
- sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags);
- }
+ pNewItem->isCorrelated = pOldItem->isCorrelated;
+ pNewItem->viaCoroutine = pOldItem->viaCoroutine;
+ pNewItem->isRecursive = pOldItem->isRecursive;
+ pNewItem->zIndex = sqlite3DbStrDup(db, pOldItem->zIndex);
+ pNewItem->notIndexed = pOldItem->notIndexed;
+ pNewItem->pIndex = pOldItem->pIndex;
pTab = pNewItem->pTab = pOldItem->pTab;
if( pTab ){
pTab->nRef++;
@@ -90045,12 +83861,11 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
IdList *pNew;
int i;
- assert( db!=0 );
if( p==0 ) return 0;
- pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
+ pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
if( pNew==0 ) return 0;
pNew->nId = p->nId;
- pNew->a = sqlite3DbMallocRawNN(db, p->nId*sizeof(p->a[0]) );
+ pNew->a = sqlite3DbMallocRaw(db, p->nId*sizeof(p->a[0]) );
if( pNew->a==0 ){
sqlite3DbFree(db, pNew);
return 0;
@@ -90068,9 +83883,8 @@ SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
}
SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
Select *pNew, *pPrior;
- assert( db!=0 );
if( p==0 ) return 0;
- pNew = sqlite3DbMallocRawNN(db, sizeof(*p) );
+ pNew = sqlite3DbMallocRaw(db, sizeof(*p) );
if( pNew==0 ) return 0;
pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags);
pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags);
@@ -90116,14 +83930,12 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(
Expr *pExpr /* Expression to be appended. Might be NULL */
){
sqlite3 *db = pParse->db;
- assert( db!=0 );
if( pList==0 ){
- pList = sqlite3DbMallocRawNN(db, sizeof(ExprList) );
+ pList = sqlite3DbMallocZero(db, sizeof(ExprList) );
if( pList==0 ){
goto no_mem;
}
- pList->nExpr = 0;
- pList->a = sqlite3DbMallocRawNN(db, sizeof(pList->a[0]));
+ pList->a = sqlite3DbMallocRaw(db, sizeof(pList->a[0]));
if( pList->a==0 ) goto no_mem;
}else if( (pList->nExpr & (pList->nExpr-1))==0 ){
struct ExprList_item *a;
@@ -90150,20 +83962,6 @@ no_mem:
}
/*
-** Set the sort order for the last element on the given ExprList.
-*/
-SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder){
- if( p==0 ) return;
- assert( SQLITE_SO_UNDEFINED<0 && SQLITE_SO_ASC>=0 && SQLITE_SO_DESC>0 );
- assert( p->nExpr>0 );
- if( iSortOrder<0 ){
- assert( p->a[p->nExpr-1].sortOrder==SQLITE_SO_ASC );
- return;
- }
- p->a[p->nExpr-1].sortOrder = (u8)iSortOrder;
-}
-
-/*
** Set the ExprList.a[].zName element of the most recently added item
** on the expression list.
**
@@ -90184,7 +83982,7 @@ SQLITE_PRIVATE void sqlite3ExprListSetName(
pItem = &pList->a[pList->nExpr-1];
assert( pItem->zName==0 );
pItem->zName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
- if( dequote ) sqlite3Dequote(pItem->zName);
+ if( dequote && pItem->zName ) sqlite3Dequote(pItem->zName);
}
}
@@ -90233,9 +84031,10 @@ SQLITE_PRIVATE void sqlite3ExprListCheckLength(
/*
** Delete an entire expression list.
*/
-static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
+SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
int i;
struct ExprList_item *pItem;
+ if( pList==0 ) return;
assert( pList->a!=0 || pList->nExpr==0 );
for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){
sqlite3ExprDelete(db, pItem->pExpr);
@@ -90245,9 +84044,6 @@ static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
sqlite3DbFree(db, pList->a);
sqlite3DbFree(db, pList);
}
-SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
- if( pList ) exprListDeleteNN(db, pList);
-}
/*
** Return the bitwise-OR of all Expr.flags fields in the given
@@ -90259,8 +84055,7 @@ SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList *pList){
if( pList ){
for(i=0; i<pList->nExpr; i++){
Expr *pExpr = pList->a[i].pExpr;
- assert( pExpr!=0 );
- m |= pExpr->flags;
+ if( ALWAYS(pExpr) ) m |= pExpr->flags;
}
}
return m;
@@ -90276,7 +84071,7 @@ SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList *pList){
**
** sqlite3ExprIsConstant() pWalker->eCode==1
** sqlite3ExprIsConstantNotJoin() pWalker->eCode==2
-** sqlite3ExprIsTableConstant() pWalker->eCode==3
+** sqlite3ExprRefOneTableOnly() pWalker->eCode==3
** sqlite3ExprIsConstantOrFunction() pWalker->eCode==4 or 5
**
** In all cases, the callbacks set Walker.eCode=0 and abort if the expression
@@ -90384,7 +84179,7 @@ SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){
}
/*
-** Walk an expression tree. Return non-zero if the expression is constant
+** Walk an expression tree. Return non-zero if the expression constant
** for any single row of the table with cursor iCur. In other words, the
** expression must not refer to any non-deterministic function nor any
** table other than iCur.
@@ -90407,22 +84202,6 @@ SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){
return exprIsConst(p, 4+isInit, 0);
}
-#ifdef SQLITE_ENABLE_CURSOR_HINTS
-/*
-** Walk an expression tree. Return 1 if the expression contains a
-** subquery of some kind. Return 0 if there are no subqueries.
-*/
-SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr *p){
- Walker w;
- memset(&w, 0, sizeof(w));
- w.eCode = 1;
- w.xExprCallback = sqlite3ExprWalkNoop;
- w.xSelectCallback = selectNodeIsConstant;
- sqlite3WalkExpr(&w, p);
- return w.eCode==0;
-}
-#endif
-
/*
** If the expression p codes a constant integer that is small enough
** to fit in a 32-bit integer, return 1 and put the value of the integer
@@ -90506,7 +84285,7 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){
*/
SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr *p, char aff){
u8 op;
- if( aff==SQLITE_AFF_BLOB ) return 1;
+ if( aff==SQLITE_AFF_NONE ) return 1;
while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ p = p->pLeft; }
op = p->op;
if( op==TK_REGISTER ) op = p->op2;
@@ -90545,22 +84324,23 @@ SQLITE_PRIVATE int sqlite3IsRowid(const char *z){
}
/*
-** pX is the RHS of an IN operator. If pX is a SELECT statement
-** that can be simplified to a direct table access, then return
-** a pointer to the SELECT statement. If pX is not a SELECT statement,
-** or if the SELECT statement needs to be manifested into a transient
-** table, then return NULL.
+** Return true if we are able to the IN operator optimization on a
+** query of the form
+**
+** x IN (SELECT ...)
+**
+** Where the SELECT... clause is as specified by the parameter to this
+** routine.
+**
+** The Select object passed in has already been preprocessed and no
+** errors have been found.
*/
#ifndef SQLITE_OMIT_SUBQUERY
-static Select *isCandidateForInOpt(Expr *pX){
- Select *p;
+static int isCandidateForInOpt(Select *p){
SrcList *pSrc;
ExprList *pEList;
- Expr *pRes;
Table *pTab;
- if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0; /* Not a subquery */
- if( ExprHasProperty(pX, EP_VarSelect) ) return 0; /* Correlated subq */
- p = pX->x.pSelect;
+ if( p==0 ) return 0; /* right-hand side of IN is SELECT */
if( p->pPrior ) return 0; /* Not a compound SELECT */
if( p->selFlags & (SF_Distinct|SF_Aggregate) ){
testcase( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
@@ -90576,15 +84356,13 @@ static Select *isCandidateForInOpt(Expr *pX){
if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */
if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */
pTab = pSrc->a[0].pTab;
- assert( pTab!=0 );
+ if( NEVER(pTab==0) ) return 0;
assert( pTab->pSelect==0 ); /* FROM clause is not a view */
if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */
pEList = p->pEList;
if( pEList->nExpr!=1 ) return 0; /* One column in the result set */
- pRes = pEList->a[0].pExpr;
- if( pRes->op!=TK_COLUMN ) return 0; /* Result is a column */
- assert( pRes->iTable==pSrc->a[0].iCursor ); /* Not a correlated subquery */
- return p;
+ if( pEList->a[0].pExpr->op!=TK_COLUMN ) return 0; /* Result is a column */
+ return 1;
}
#endif /* SQLITE_OMIT_SUBQUERY */
@@ -90604,13 +84382,13 @@ SQLITE_PRIVATE int sqlite3CodeOnce(Parse *pParse){
** to be set to NULL if iCur contains one or more NULL values.
*/
static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){
- int addr1;
+ int j1;
sqlite3VdbeAddOp2(v, OP_Integer, 0, regHasNull);
- addr1 = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v);
+ j1 = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_Column, iCur, 0, regHasNull);
sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
VdbeComment((v, "first_entry_in(%d)", iCur));
- sqlite3VdbeJumpHere(v, addr1);
+ sqlite3VdbeJumpHere(v, j1);
}
@@ -90716,13 +84494,15 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int
** satisfy the query. This is preferable to generating a new
** ephemeral table.
*/
- if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){
+ p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
+ if( pParse->nErr==0 && isCandidateForInOpt(p) ){
sqlite3 *db = pParse->db; /* Database connection */
Table *pTab; /* Table <table>. */
Expr *pExpr; /* Expression <column> */
i16 iCol; /* Index of column <column> */
i16 iDb; /* Database idx for pTab */
+ assert( p ); /* Because of isCandidateForInOpt(p) */
assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */
assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */
@@ -90880,10 +84660,9 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
#ifndef SQLITE_OMIT_EXPLAIN
if( pParse->explain==2 ){
- char *zMsg = sqlite3MPrintf(pParse->db, "EXECUTE %s%s SUBQUERY %d",
- jmpIfDynamic>=0?"":"CORRELATED ",
- pExpr->op==TK_IN?"LIST":"SCALAR",
- pParse->iNextSelectId
+ char *zMsg = sqlite3MPrintf(
+ pParse->db, "EXECUTE %s%s SUBQUERY %d", jmpIfDynamic>=0?"":"CORRELATED ",
+ pExpr->op==TK_IN?"LIST":"SCALAR", pParse->iNextSelectId
);
sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC);
}
@@ -90957,7 +84736,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
int r1, r2, r3;
if( !affinity ){
- affinity = SQLITE_AFF_BLOB;
+ affinity = SQLITE_AFF_NONE;
}
if( pKeyInfo ){
assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
@@ -91153,7 +84932,7 @@ static void sqlite3ExprCodeIN(
}
if( regCkNull ){
sqlite3VdbeAddOp2(v, OP_IsNull, regCkNull, destIfNull); VdbeCoverage(v);
- sqlite3VdbeGoto(v, destIfFalse);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse);
}
sqlite3VdbeResolveLabel(v, labelOk);
sqlite3ReleaseTempReg(pParse, regCkNull);
@@ -91171,7 +84950,7 @@ static void sqlite3ExprCodeIN(
int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
VdbeCoverage(v);
- sqlite3VdbeGoto(v, destIfNull);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
sqlite3VdbeJumpHere(v, addr1);
}
}
@@ -91209,7 +84988,7 @@ static void sqlite3ExprCodeIN(
** the presence of a NULL on the RHS makes a difference in the
** outcome.
*/
- int addr1;
+ int j1;
/* First check to see if the LHS is contained in the RHS. If so,
** then the answer is TRUE the presence of NULLs in the RHS does
@@ -91217,12 +84996,12 @@ static void sqlite3ExprCodeIN(
** answer is NULL if the RHS contains NULLs and the answer is
** FALSE if the RHS is NULL-free.
*/
- addr1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1);
+ j1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1);
VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_IsNull, rRhsHasNull, destIfNull);
VdbeCoverage(v);
- sqlite3VdbeGoto(v, destIfFalse);
- sqlite3VdbeJumpHere(v, addr1);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse);
+ sqlite3VdbeJumpHere(v, j1);
}
}
}
@@ -91232,6 +85011,17 @@ static void sqlite3ExprCodeIN(
}
#endif /* SQLITE_OMIT_SUBQUERY */
+/*
+** Duplicate an 8-byte value
+*/
+static char *dup8bytes(Vdbe *v, const char *in){
+ char *out = sqlite3DbMallocRaw(sqlite3VdbeDb(v), 8);
+ if( out ){
+ memcpy(out, in, 8);
+ }
+ return out;
+}
+
#ifndef SQLITE_OMIT_FLOATING_POINT
/*
** Generate an instruction that will put the floating point
@@ -91244,10 +85034,12 @@ static void sqlite3ExprCodeIN(
static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){
if( ALWAYS(z!=0) ){
double value;
+ char *zV;
sqlite3AtoF(z, &value, sqlite3Strlen30(z), SQLITE_UTF8);
assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */
if( negateFlag ) value = -value;
- sqlite3VdbeAddOp4Dup8(v, OP_Real, 0, iMem, 0, (u8*)&value, P4_REAL);
+ zV = dup8bytes(v, (char*)&value);
+ sqlite3VdbeAddOp4(v, OP_Real, 0, iMem, 0, zV, P4_REAL);
}
}
#endif
@@ -91273,8 +85065,10 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
assert( z!=0 );
c = sqlite3DecOrHexToI64(z, &value);
if( c==0 || (c==2 && negFlag) ){
+ char *zV;
if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; }
- sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64);
+ zV = dup8bytes(v, (char*)&value);
+ sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64);
}else{
#ifdef SQLITE_OMIT_FLOATING_POINT
sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
@@ -91292,19 +85086,6 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
}
}
-#if defined(SQLITE_DEBUG)
-/*
-** Verify the consistency of the column cache
-*/
-static int cacheIsValid(Parse *pParse){
- int i, n;
- for(i=n=0; i<SQLITE_N_COLCACHE; i++){
- if( pParse->aColCache[i].iReg>0 ) n++;
- }
- return n==pParse->nColCache;
-}
-#endif
-
/*
** Clear a cache entry.
*/
@@ -91315,9 +85096,6 @@ static void cacheEntryClear(Parse *pParse, struct yColCache *p){
}
p->tempReg = 0;
}
- p->iReg = 0;
- pParse->nColCache--;
- assert( pParse->db->mallocFailed || cacheIsValid(pParse) );
}
@@ -91361,8 +85139,6 @@ SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int
p->iReg = iReg;
p->tempReg = 0;
p->lru = pParse->iCacheCnt++;
- pParse->nColCache++;
- assert( pParse->db->mallocFailed || cacheIsValid(pParse) );
return;
}
}
@@ -91384,7 +85160,6 @@ SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int
p->iReg = iReg;
p->tempReg = 0;
p->lru = pParse->iCacheCnt++;
- assert( cacheIsValid(pParse) );
return;
}
}
@@ -91394,13 +85169,15 @@ SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int
** Purge the range of registers from the column cache.
*/
SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse *pParse, int iReg, int nReg){
+ int i;
+ int iLast = iReg + nReg - 1;
struct yColCache *p;
- if( iReg<=0 || pParse->nColCache==0 ) return;
- p = &pParse->aColCache[SQLITE_N_COLCACHE-1];
- while(1){
- if( p->iReg >= iReg && p->iReg < iReg+nReg ) cacheEntryClear(pParse, p);
- if( p==pParse->aColCache ) break;
- p--;
+ for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
+ int r = p->iReg;
+ if( r>=iReg && r<=iLast ){
+ cacheEntryClear(pParse, p);
+ p->iReg = 0;
+ }
}
}
@@ -91436,6 +85213,7 @@ SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
if( p->iReg && p->iLevel>pParse->iCacheLevel ){
cacheEntryClear(pParse, p);
+ p->iReg = 0;
}
}
}
@@ -91456,28 +85234,6 @@ static void sqlite3ExprCachePinRegister(Parse *pParse, int iReg){
}
}
-/* Generate code that will load into register regOut a value that is
-** appropriate for the iIdxCol-th column of index pIdx.
-*/
-SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn(
- Parse *pParse, /* The parsing context */
- Index *pIdx, /* The index whose column is to be loaded */
- int iTabCur, /* Cursor pointing to a table row */
- int iIdxCol, /* The column of the index to be loaded */
- int regOut /* Store the index column value in this register */
-){
- i16 iTabCol = pIdx->aiColumn[iIdxCol];
- if( iTabCol==XN_EXPR ){
- assert( pIdx->aColExpr );
- assert( pIdx->aColExpr->nExpr>iIdxCol );
- pParse->iSelfTab = iTabCur;
- sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut);
- }else{
- sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur,
- iTabCol, regOut);
- }
-}
-
/*
** Generate code to extract the value of the iCol-th column of a table.
*/
@@ -91505,12 +85261,9 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(
/*
** Generate code that will extract the iColumn-th column from
-** table pTab and store the column value in a register.
-**
-** An effort is made to store the column value in register iReg. This
-** is not garanteeed for GetColumn() - the result can be stored in
-** any register. But the result is guaranteed to land in register iReg
-** for GetColumnToReg().
+** table pTab and store the column value in a register. An effort
+** is made to store the column value in register iReg, but this is
+** not guaranteed. The location of the column value is returned.
**
** There must be an open cursor to pTab in iTable when this routine
** is called. If iColumn<0 then code is generated that extracts the rowid.
@@ -91521,7 +85274,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(
int iColumn, /* Index of the table column */
int iTable, /* The cursor pointing to the table */
int iReg, /* Store results here */
- u8 p5 /* P5 value for OP_Column + FLAGS */
+ u8 p5 /* P5 value for OP_Column */
){
Vdbe *v = pParse->pVdbe;
int i;
@@ -91543,17 +85296,6 @@ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(
}
return iReg;
}
-SQLITE_PRIVATE void sqlite3ExprCodeGetColumnToReg(
- Parse *pParse, /* Parsing and code generating context */
- Table *pTab, /* Description of the table we are reading from */
- int iColumn, /* Index of the table column */
- int iTable, /* The cursor pointing to the table */
- int iReg /* Store results here */
-){
- int r1 = sqlite3ExprCodeGetColumn(pParse, pTab, iColumn, iTable, iReg, 0);
- if( r1!=iReg ) sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, r1, iReg);
-}
-
/*
** Clear all column cache entries.
@@ -91570,6 +85312,7 @@ SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse *pParse){
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
if( p->iReg ){
cacheEntryClear(pParse, p);
+ p->iReg = 0;
}
}
}
@@ -91611,7 +85354,6 @@ static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){
}
#endif /* SQLITE_DEBUG || SQLITE_COVERAGE_TEST */
-
/*
** Convert an expression node to a TK_REGISTER
*/
@@ -91677,9 +85419,8 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
inReg = pExpr->iColumn + pParse->ckBase;
break;
}else{
- /* Coding an expression that is part of an index where column names
- ** in the index refer to the table to which the index belongs */
- iTab = pParse->iSelfTab;
+ /* Deleting from a partial index */
+ iTab = pParse->iPartIdxTab;
}
}
inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
@@ -91700,7 +85441,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
#endif
case TK_STRING: {
assert( !ExprHasProperty(pExpr, EP_IntValue) );
- sqlite3VdbeLoadString(v, target, pExpr->u.zToken);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, target, 0, pExpr->u.zToken, 0);
break;
}
case TK_NULL: {
@@ -91739,6 +85480,10 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
inReg = pExpr->iTable;
break;
}
+ case TK_AS: {
+ inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
+ break;
+ }
#ifndef SQLITE_OMIT_CAST
case TK_CAST: {
/* Expressions of the form: CAST(pLeft AS token) */
@@ -91880,6 +85625,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
ExprList *pFarg; /* List of function arguments */
int nFarg; /* Number of function arguments */
FuncDef *pDef; /* The function definition object */
+ int nId; /* Length of the function name in bytes */
const char *zId; /* The function name */
u32 constMask = 0; /* Mask of function arguments that are constant */
int i; /* Loop counter */
@@ -91895,9 +85641,10 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
nFarg = pFarg ? pFarg->nExpr : 0;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
zId = pExpr->u.zToken;
- pDef = sqlite3FindFunction(db, zId, nFarg, enc, 0);
- if( pDef==0 || pDef->xFinalize!=0 ){
- sqlite3ErrorMsg(pParse, "unknown function: %s()", zId);
+ nId = sqlite3Strlen30(zId);
+ pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0);
+ if( pDef==0 || pDef->xFunc==0 ){
+ sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId);
break;
}
@@ -91926,7 +85673,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
*/
if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){
assert( nFarg>=1 );
- inReg = sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target);
+ sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target);
break;
}
@@ -91967,7 +85714,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
}
sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */
- sqlite3ExprCodeExprList(pParse, pFarg, r1, 0,
+ sqlite3ExprCodeExprList(pParse, pFarg, r1,
SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
sqlite3ExprCachePop(pParse); /* Ticket 2ea2425d34be */
}else{
@@ -91996,7 +85743,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
if( !pColl ) pColl = db->pDfltColl;
sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
}
- sqlite3VdbeAddOp4(v, OP_Function0, constMask, r1, target,
+ sqlite3VdbeAddOp4(v, OP_Function, constMask, r1, target,
(char*)pDef, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, (u8)nFarg);
if( nFarg && constMask==0 ){
@@ -92062,7 +85809,6 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
sqlite3ReleaseTempReg(pParse, r4);
break;
}
- case TK_SPAN:
case TK_COLLATE:
case TK_UPLUS: {
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
@@ -92192,7 +85938,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL);
testcase( aListelem[i+1].pExpr->op==TK_COLUMN );
sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target);
- sqlite3VdbeGoto(v, endLabel);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel);
sqlite3ExprCachePop(pParse);
sqlite3VdbeResolveLabel(v, nextCase);
}
@@ -92323,7 +86069,7 @@ SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, pExpr->iTable, target);
}else{
inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
- assert( pParse->pVdbe!=0 || pParse->db->mallocFailed );
+ assert( pParse->pVdbe || pParse->db->mallocFailed );
if( inReg!=target && pParse->pVdbe ){
sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
}
@@ -92331,18 +86077,6 @@ SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
}
/*
-** Make a transient copy of expression pExpr and then code it using
-** sqlite3ExprCode(). This routine works just like sqlite3ExprCode()
-** except that the input expression is guaranteed to be unchanged.
-*/
-SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse *pParse, Expr *pExpr, int target){
- sqlite3 *db = pParse->db;
- pExpr = sqlite3ExprDup(db, pExpr, 0);
- if( !db->mallocFailed ) sqlite3ExprCode(pParse, pExpr, target);
- sqlite3ExprDelete(db, pExpr);
-}
-
-/*
** Generate code that will evaluate expression pExpr and store the
** results in register target. The results are guaranteed to appear
** in register target. If the expression is constant, then this routine
@@ -92380,6 +86114,268 @@ SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int targ
exprToRegister(pExpr, iMem);
}
+#ifdef SQLITE_DEBUG
+/*
+** Generate a human-readable explanation of an expression tree.
+*/
+SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
+ const char *zBinOp = 0; /* Binary operator */
+ const char *zUniOp = 0; /* Unary operator */
+ pView = sqlite3TreeViewPush(pView, moreToFollow);
+ if( pExpr==0 ){
+ sqlite3TreeViewLine(pView, "nil");
+ sqlite3TreeViewPop(pView);
+ return;
+ }
+ switch( pExpr->op ){
+ case TK_AGG_COLUMN: {
+ sqlite3TreeViewLine(pView, "AGG{%d:%d}",
+ pExpr->iTable, pExpr->iColumn);
+ break;
+ }
+ case TK_COLUMN: {
+ if( pExpr->iTable<0 ){
+ /* This only happens when coding check constraints */
+ sqlite3TreeViewLine(pView, "COLUMN(%d)", pExpr->iColumn);
+ }else{
+ sqlite3TreeViewLine(pView, "{%d:%d}",
+ pExpr->iTable, pExpr->iColumn);
+ }
+ break;
+ }
+ case TK_INTEGER: {
+ if( pExpr->flags & EP_IntValue ){
+ sqlite3TreeViewLine(pView, "%d", pExpr->u.iValue);
+ }else{
+ sqlite3TreeViewLine(pView, "%s", pExpr->u.zToken);
+ }
+ break;
+ }
+#ifndef SQLITE_OMIT_FLOATING_POINT
+ case TK_FLOAT: {
+ sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken);
+ break;
+ }
+#endif
+ case TK_STRING: {
+ sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken);
+ break;
+ }
+ case TK_NULL: {
+ sqlite3TreeViewLine(pView,"NULL");
+ break;
+ }
+#ifndef SQLITE_OMIT_BLOB_LITERAL
+ case TK_BLOB: {
+ sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken);
+ break;
+ }
+#endif
+ case TK_VARIABLE: {
+ sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)",
+ pExpr->u.zToken, pExpr->iColumn);
+ break;
+ }
+ case TK_REGISTER: {
+ sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable);
+ break;
+ }
+ case TK_AS: {
+ sqlite3TreeViewLine(pView,"AS %Q", pExpr->u.zToken);
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
+ break;
+ }
+ case TK_ID: {
+ sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken);
+ break;
+ }
+#ifndef SQLITE_OMIT_CAST
+ case TK_CAST: {
+ /* Expressions of the form: CAST(pLeft AS token) */
+ sqlite3TreeViewLine(pView,"CAST %Q", pExpr->u.zToken);
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
+ break;
+ }
+#endif /* SQLITE_OMIT_CAST */
+ case TK_LT: zBinOp = "LT"; break;
+ case TK_LE: zBinOp = "LE"; break;
+ case TK_GT: zBinOp = "GT"; break;
+ case TK_GE: zBinOp = "GE"; break;
+ case TK_NE: zBinOp = "NE"; break;
+ case TK_EQ: zBinOp = "EQ"; break;
+ case TK_IS: zBinOp = "IS"; break;
+ case TK_ISNOT: zBinOp = "ISNOT"; break;
+ case TK_AND: zBinOp = "AND"; break;
+ case TK_OR: zBinOp = "OR"; break;
+ case TK_PLUS: zBinOp = "ADD"; break;
+ case TK_STAR: zBinOp = "MUL"; break;
+ case TK_MINUS: zBinOp = "SUB"; break;
+ case TK_REM: zBinOp = "REM"; break;
+ case TK_BITAND: zBinOp = "BITAND"; break;
+ case TK_BITOR: zBinOp = "BITOR"; break;
+ case TK_SLASH: zBinOp = "DIV"; break;
+ case TK_LSHIFT: zBinOp = "LSHIFT"; break;
+ case TK_RSHIFT: zBinOp = "RSHIFT"; break;
+ case TK_CONCAT: zBinOp = "CONCAT"; break;
+ case TK_DOT: zBinOp = "DOT"; break;
+
+ case TK_UMINUS: zUniOp = "UMINUS"; break;
+ case TK_UPLUS: zUniOp = "UPLUS"; break;
+ case TK_BITNOT: zUniOp = "BITNOT"; break;
+ case TK_NOT: zUniOp = "NOT"; break;
+ case TK_ISNULL: zUniOp = "ISNULL"; break;
+ case TK_NOTNULL: zUniOp = "NOTNULL"; break;
+
+ case TK_COLLATE: {
+ sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken);
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
+ break;
+ }
+
+ case TK_AGG_FUNCTION:
+ case TK_FUNCTION: {
+ ExprList *pFarg; /* List of function arguments */
+ if( ExprHasProperty(pExpr, EP_TokenOnly) ){
+ pFarg = 0;
+ }else{
+ pFarg = pExpr->x.pList;
+ }
+ if( pExpr->op==TK_AGG_FUNCTION ){
+ sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q",
+ pExpr->op2, pExpr->u.zToken);
+ }else{
+ sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken);
+ }
+ if( pFarg ){
+ sqlite3TreeViewExprList(pView, pFarg, 0, 0);
+ }
+ break;
+ }
+#ifndef SQLITE_OMIT_SUBQUERY
+ case TK_EXISTS: {
+ sqlite3TreeViewLine(pView, "EXISTS-expr");
+ sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
+ break;
+ }
+ case TK_SELECT: {
+ sqlite3TreeViewLine(pView, "SELECT-expr");
+ sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
+ break;
+ }
+ case TK_IN: {
+ sqlite3TreeViewLine(pView, "IN");
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+ sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
+ }else{
+ sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0);
+ }
+ break;
+ }
+#endif /* SQLITE_OMIT_SUBQUERY */
+
+ /*
+ ** x BETWEEN y AND z
+ **
+ ** This is equivalent to
+ **
+ ** x>=y AND x<=z
+ **
+ ** X is stored in pExpr->pLeft.
+ ** Y is stored in pExpr->pList->a[0].pExpr.
+ ** Z is stored in pExpr->pList->a[1].pExpr.
+ */
+ case TK_BETWEEN: {
+ Expr *pX = pExpr->pLeft;
+ Expr *pY = pExpr->x.pList->a[0].pExpr;
+ Expr *pZ = pExpr->x.pList->a[1].pExpr;
+ sqlite3TreeViewLine(pView, "BETWEEN");
+ sqlite3TreeViewExpr(pView, pX, 1);
+ sqlite3TreeViewExpr(pView, pY, 1);
+ sqlite3TreeViewExpr(pView, pZ, 0);
+ break;
+ }
+ case TK_TRIGGER: {
+ /* If the opcode is TK_TRIGGER, then the expression is a reference
+ ** to a column in the new.* or old.* pseudo-tables available to
+ ** trigger programs. In this case Expr.iTable is set to 1 for the
+ ** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn
+ ** is set to the column of the pseudo-table to read, or to -1 to
+ ** read the rowid field.
+ */
+ sqlite3TreeViewLine(pView, "%s(%d)",
+ pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn);
+ break;
+ }
+ case TK_CASE: {
+ sqlite3TreeViewLine(pView, "CASE");
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
+ sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0);
+ break;
+ }
+#ifndef SQLITE_OMIT_TRIGGER
+ case TK_RAISE: {
+ const char *zType = "unk";
+ switch( pExpr->affinity ){
+ case OE_Rollback: zType = "rollback"; break;
+ case OE_Abort: zType = "abort"; break;
+ case OE_Fail: zType = "fail"; break;
+ case OE_Ignore: zType = "ignore"; break;
+ }
+ sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken);
+ break;
+ }
+#endif
+ default: {
+ sqlite3TreeViewLine(pView, "op=%d", pExpr->op);
+ break;
+ }
+ }
+ if( zBinOp ){
+ sqlite3TreeViewLine(pView, "%s", zBinOp);
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
+ sqlite3TreeViewExpr(pView, pExpr->pRight, 0);
+ }else if( zUniOp ){
+ sqlite3TreeViewLine(pView, "%s", zUniOp);
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
+ }
+ sqlite3TreeViewPop(pView);
+}
+#endif /* SQLITE_DEBUG */
+
+#ifdef SQLITE_DEBUG
+/*
+** Generate a human-readable explanation of an expression list.
+*/
+SQLITE_PRIVATE void sqlite3TreeViewExprList(
+ TreeView *pView,
+ const ExprList *pList,
+ u8 moreToFollow,
+ const char *zLabel
+){
+ int i;
+ pView = sqlite3TreeViewPush(pView, moreToFollow);
+ if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST";
+ if( pList==0 ){
+ sqlite3TreeViewLine(pView, "%s (empty)", zLabel);
+ }else{
+ sqlite3TreeViewLine(pView, "%s", zLabel);
+ for(i=0; i<pList->nExpr; i++){
+ sqlite3TreeViewExpr(pView, pList->a[i].pExpr, i<pList->nExpr-1);
+#if 0
+ if( pList->a[i].zName ){
+ sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName);
+ }
+ if( pList->a[i].bSpanIsTab ){
+ sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan);
+ }
+#endif
+ }
+ }
+ sqlite3TreeViewPop(pView);
+}
+#endif /* SQLITE_DEBUG */
+
/*
** Generate code that pushes the value of every element of the given
** expression list into a sequence of registers beginning at target.
@@ -92391,22 +86387,16 @@ SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int targ
**
** The SQLITE_ECEL_FACTOR argument allows constant arguments to be
** factored out into initialization code.
-**
-** The SQLITE_ECEL_REF flag means that expressions in the list with
-** ExprList.a[].u.x.iOrderByCol>0 have already been evaluated and stored
-** in registers at srcReg, and so the value can be copied from there.
*/
SQLITE_PRIVATE int sqlite3ExprCodeExprList(
Parse *pParse, /* Parsing context */
ExprList *pList, /* The expression list to be coded */
int target, /* Where to write results */
- int srcReg, /* Source registers if SQLITE_ECEL_REF */
u8 flags /* SQLITE_ECEL_* flags */
){
struct ExprList_item *pItem;
- int i, j, n;
+ int i, n;
u8 copyOp = (flags & SQLITE_ECEL_DUP) ? OP_Copy : OP_SCopy;
- Vdbe *v = pParse->pVdbe;
assert( pList!=0 );
assert( target>0 );
assert( pParse->pVdbe!=0 ); /* Never gets this far otherwise */
@@ -92414,14 +86404,13 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
if( !ConstFactorOk(pParse) ) flags &= ~SQLITE_ECEL_FACTOR;
for(pItem=pList->a, i=0; i<n; i++, pItem++){
Expr *pExpr = pItem->pExpr;
- if( (flags & SQLITE_ECEL_REF)!=0 && (j = pList->a[i].u.x.iOrderByCol)>0 ){
- sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
- }else if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
+ if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
sqlite3ExprCodeAtInit(pParse, pExpr, target+i, 0);
}else{
int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
if( inReg!=target+i ){
VdbeOp *pOp;
+ Vdbe *v = pParse->pVdbe;
if( copyOp==OP_Copy
&& (pOp=sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy
&& pOp->p1+pOp->p3+1==inReg
@@ -92541,13 +86530,6 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
break;
}
- case TK_IS:
- case TK_ISNOT:
- testcase( op==TK_IS );
- testcase( op==TK_ISNOT );
- op = (op==TK_IS) ? TK_EQ : TK_NE;
- jumpIfNull = SQLITE_NULLEQ;
- /* Fall thru */
case TK_LT:
case TK_LE:
case TK_GT:
@@ -92563,12 +86545,23 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
- assert(TK_EQ==OP_Eq); testcase(op==OP_Eq);
- VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ);
- VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ);
- assert(TK_NE==OP_Ne); testcase(op==OP_Ne);
- VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ);
- VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ);
+ assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
+ assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
+ testcase( regFree1==0 );
+ testcase( regFree2==0 );
+ break;
+ }
+ case TK_IS:
+ case TK_ISNOT: {
+ testcase( op==TK_IS );
+ testcase( op==TK_ISNOT );
+ r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
+ r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
+ op = (op==TK_IS) ? TK_EQ : TK_NE;
+ codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
+ r1, r2, dest, SQLITE_NULLEQ);
+ VdbeCoverageIf(v, op==TK_EQ);
+ VdbeCoverageIf(v, op==TK_NE);
testcase( regFree1==0 );
testcase( regFree2==0 );
break;
@@ -92594,14 +86587,14 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
int destIfFalse = sqlite3VdbeMakeLabel(v);
int destIfNull = jumpIfNull ? dest : destIfFalse;
sqlite3ExprCodeIN(pParse, pExpr, destIfFalse, destIfNull);
- sqlite3VdbeGoto(v, dest);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, dest);
sqlite3VdbeResolveLabel(v, destIfFalse);
break;
}
#endif
default: {
if( exprAlwaysTrue(pExpr) ){
- sqlite3VdbeGoto(v, dest);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, dest);
}else if( exprAlwaysFalse(pExpr) ){
/* No-op */
}else{
@@ -92693,13 +86686,6 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
break;
}
- case TK_IS:
- case TK_ISNOT:
- testcase( pExpr->op==TK_IS );
- testcase( pExpr->op==TK_ISNOT );
- op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
- jumpIfNull = SQLITE_NULLEQ;
- /* Fall thru */
case TK_LT:
case TK_LE:
case TK_GT:
@@ -92715,12 +86701,23 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
- assert(TK_EQ==OP_Eq); testcase(op==OP_Eq);
- VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ);
- VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ);
- assert(TK_NE==OP_Ne); testcase(op==OP_Ne);
- VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ);
- VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ);
+ assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
+ assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
+ testcase( regFree1==0 );
+ testcase( regFree2==0 );
+ break;
+ }
+ case TK_IS:
+ case TK_ISNOT: {
+ testcase( pExpr->op==TK_IS );
+ testcase( pExpr->op==TK_ISNOT );
+ r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
+ r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
+ op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
+ codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
+ r1, r2, dest, SQLITE_NULLEQ);
+ VdbeCoverageIf(v, op==TK_EQ);
+ VdbeCoverageIf(v, op==TK_NE);
testcase( regFree1==0 );
testcase( regFree2==0 );
break;
@@ -92753,7 +86750,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
#endif
default: {
if( exprAlwaysFalse(pExpr) ){
- sqlite3VdbeGoto(v, dest);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, dest);
}else if( exprAlwaysTrue(pExpr) ){
/* no-op */
}else{
@@ -92771,21 +86768,6 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
}
/*
-** Like sqlite3ExprIfFalse() except that a copy is made of pExpr before
-** code generation, and that copy is deleted after code generation. This
-** ensures that the original pExpr is unchanged.
-*/
-SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,int jumpIfNull){
- sqlite3 *db = pParse->db;
- Expr *pCopy = sqlite3ExprDup(db, pExpr, 0);
- if( db->mallocFailed==0 ){
- sqlite3ExprIfFalse(pParse, pCopy, dest, jumpIfNull);
- }
- sqlite3ExprDelete(db, pCopy);
-}
-
-
-/*
** Do a deep comparison of two expression trees. Return 0 if the two
** expressions are completely identical. Return 1 if they differ only
** by a COLLATE operator at the top level. Return 2 if there are differences
@@ -92828,10 +86810,8 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){
}
return 2;
}
- if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){
- if( pA->op==TK_FUNCTION ){
- if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2;
- }else if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
+ if( pA->op!=TK_COLUMN && ALWAYS(pA->op!=TK_AGG_COLUMN) && pA->u.zToken ){
+ if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
return pA->op==TK_COLLATE ? 1 : 2;
}
}
@@ -93115,7 +87095,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
pItem->iMem = ++pParse->nMem;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
pItem->pFunc = sqlite3FindFunction(pParse->db,
- pExpr->u.zToken,
+ pExpr->u.zToken, sqlite3Strlen30(pExpr->u.zToken),
pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0);
if( pExpr->flags & EP_Distinct ){
pItem->iDistinct = pParse->nTab++;
@@ -93244,29 +87224,6 @@ SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse *pParse){
pParse->nRangeReg = 0;
}
-/*
-** Validate that no temporary register falls within the range of
-** iFirst..iLast, inclusive. This routine is only call from within assert()
-** statements.
-*/
-#ifdef SQLITE_DEBUG
-SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){
- int i;
- if( pParse->nRangeReg>0
- && pParse->iRangeReg+pParse->nRangeReg<iLast
- && pParse->iRangeReg>=iFirst
- ){
- return 0;
- }
- for(i=0; i<pParse->nTempReg; i++){
- if( pParse->aTempReg[i]>=iFirst && pParse->aTempReg[i]<=iLast ){
- return 0;
- }
- }
- return 1;
-}
-#endif /* SQLITE_DEBUG */
-
/************** End of expr.c ************************************************/
/************** Begin file alter.c *******************************************/
/*
@@ -93283,7 +87240,6 @@ SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){
** This file contains C code routines that used to generate VDBE code
** that implements the ALTER TABLE command.
*/
-/* #include "sqliteInt.h" */
/*
** The code in this file only exists if we are not omitting the
@@ -93500,7 +87456,7 @@ static void renameTriggerFunc(
** Register built-in functions used to help implement ALTER TABLE
*/
SQLITE_PRIVATE void sqlite3AlterFunctions(void){
- static FuncDef aAlterTableFuncs[] = {
+ static SQLITE_WSD FuncDef aAlterTableFuncs[] = {
FUNCTION(sqlite_rename_table, 2, 0, 0, renameTableFunc),
#ifndef SQLITE_OMIT_TRIGGER
FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc),
@@ -93509,7 +87465,13 @@ SQLITE_PRIVATE void sqlite3AlterFunctions(void){
FUNCTION(sqlite_rename_parent, 3, 0, 0, renameParentFunc),
#endif
};
- sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
+ int i;
+ FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
+ FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAlterTableFuncs);
+
+ for(i=0; i<ArraySize(aAlterTableFuncs); i++){
+ sqlite3FuncDefInsert(pHash, &aFunc[i]);
+ }
}
/*
@@ -93756,7 +87718,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( pVTab ){
int i = ++pParse->nMem;
- sqlite3VdbeLoadString(v, i, zName);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, i, 0, zName, 0);
sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB);
sqlite3MayAbort(pParse);
}
@@ -93853,6 +87815,33 @@ exit_rename_table:
db->flags = savedDbFlags;
}
+
+/*
+** Generate code to make sure the file format number is at least minFormat.
+** The generated code will increase the file format number if necessary.
+*/
+SQLITE_PRIVATE void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){
+ Vdbe *v;
+ v = sqlite3GetVdbe(pParse);
+ /* The VDBE should have been allocated before this routine is called.
+ ** If that allocation failed, we would have quit before reaching this
+ ** point */
+ if( ALWAYS(v) ){
+ int r1 = sqlite3GetTempReg(pParse);
+ int r2 = sqlite3GetTempReg(pParse);
+ int j1;
+ sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT);
+ sqlite3VdbeUsesBtree(v, iDb);
+ sqlite3VdbeAddOp2(v, OP_Integer, minFormat, r2);
+ j1 = sqlite3VdbeAddOp3(v, OP_Ge, r2, 0, r1);
+ sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); VdbeCoverage(v);
+ sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, r2);
+ sqlite3VdbeJumpHere(v, j1);
+ sqlite3ReleaseTempReg(pParse, r1);
+ sqlite3ReleaseTempReg(pParse, r2);
+ }
+}
+
/*
** This function is called after an "ALTER TABLE ... ADD" statement
** has been parsed. Argument pColDef contains the text of the new
@@ -93871,11 +87860,9 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
Column *pCol; /* The new column */
Expr *pDflt; /* Default value for the new column */
sqlite3 *db; /* The database connection; */
- Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */
db = pParse->db;
if( pParse->nErr || db->mallocFailed ) return;
- assert( v!=0 );
pNew = pParse->pNewTable;
assert( pNew );
@@ -93899,8 +87886,7 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
** literal NULL, then set pDflt to 0. This simplifies checking
** for an SQL NULL default below.
*/
- assert( pDflt==0 || pDflt->op==TK_SPAN );
- if( pDflt && pDflt->pLeft->op==TK_NULL ){
+ if( pDflt && pDflt->op==TK_NULL ){
pDflt = 0;
}
@@ -93933,10 +87919,10 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
if( pDflt ){
sqlite3_value *pVal = 0;
int rc;
- rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal);
+ rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal);
assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
if( rc!=SQLITE_OK ){
- assert( db->mallocFailed == 1 );
+ db->mallocFailed = 1;
return;
}
if( !pVal ){
@@ -93966,16 +87952,11 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
db->flags = savedDbFlags;
}
- /* If the default value of the new column is NULL, then the file
+ /* If the default value of the new column is NULL, then set the file
** format to 2. If the default value of the new column is not NULL,
- ** the file format be 3. Back when this feature was first added
- ** in 2006, we went to the trouble to upgrade the file format to the
- ** minimum support values. But 10-years on, we can assume that all
- ** extent versions of SQLite support file-format 4, so we always and
- ** unconditionally upgrade to 4.
+ ** the file format becomes 3.
*/
- sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT,
- SQLITE_MAX_FILE_FORMAT);
+ sqlite3MinimumFileFormat(pParse, iDb, pDflt ? 3 : 2);
/* Reload the schema of the modified table. */
reloadTableSchema(pParse, pTab, pTab->zName);
@@ -94049,7 +88030,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*nAlloc);
pNew->zName = sqlite3MPrintf(db, "sqlite_altertab_%s", pTab->zName);
if( !pNew->aCol || !pNew->zName ){
- assert( db->mallocFailed );
+ db->mallocFailed = 1;
goto exit_begin_add_column;
}
memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol);
@@ -94057,7 +88038,9 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
Column *pCol = &pNew->aCol[i];
pCol->zName = sqlite3DbStrDup(db, pCol->zName);
pCol->zColl = 0;
+ pCol->zType = 0;
pCol->pDflt = 0;
+ pCol->zDflt = 0;
}
pNew->pSchema = db->aDb[iDb].pSchema;
pNew->addColOffset = pTab->addColOffset;
@@ -94219,7 +88202,6 @@ exit_begin_add_column:
** integer in the equivalent columns in sqlite_stat4.
*/
#ifndef SQLITE_OMIT_ANALYZE
-/* #include "sqliteInt.h" */
#if defined(SQLITE_ENABLE_STAT4)
# define IsStat4 1
@@ -94392,7 +88374,7 @@ static void sampleClear(sqlite3 *db, Stat4Sample *p){
static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
assert( db!=0 );
if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
- p->u.aRowid = sqlite3DbMallocRawNN(db, n);
+ p->u.aRowid = sqlite3DbMallocRaw(db, n);
if( p->u.aRowid ){
p->nRowid = n;
memcpy(p->u.aRowid, pData, n);
@@ -94557,10 +88539,12 @@ static const FuncDef statInitFuncdef = {
SQLITE_UTF8, /* funcFlags */
0, /* pUserData */
0, /* pNext */
- statInit, /* xSFunc */
+ statInit, /* xFunc */
+ 0, /* xStep */
0, /* xFinalize */
"stat_init", /* zName */
- {0}
+ 0, /* pHash */
+ 0 /* pDestructor */
};
#ifdef SQLITE_ENABLE_STAT4
@@ -94856,10 +88840,12 @@ static const FuncDef statPushFuncdef = {
SQLITE_UTF8, /* funcFlags */
0, /* pUserData */
0, /* pNext */
- statPush, /* xSFunc */
+ statPush, /* xFunc */
+ 0, /* xStep */
0, /* xFinalize */
"stat_push", /* zName */
- {0}
+ 0, /* pHash */
+ 0 /* pDestructor */
};
#define STAT_GET_STAT1 0 /* "stat" column of stat1 table */
@@ -95001,10 +88987,12 @@ static const FuncDef statGetFuncdef = {
SQLITE_UTF8, /* funcFlags */
0, /* pUserData */
0, /* pNext */
- statGet, /* xSFunc */
+ statGet, /* xFunc */
+ 0, /* xStep */
0, /* xFinalize */
"stat_get", /* zName */
- {0}
+ 0, /* pHash */
+ 0 /* pDestructor */
};
static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){
@@ -95016,8 +89004,8 @@ static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){
#else
UNUSED_PARAMETER( iParam );
#endif
- sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4, regOut,
- (char*)&statGetFuncdef, P4_FUNCDEF);
+ sqlite3VdbeAddOp3(v, OP_Function, 0, regStat4, regOut);
+ sqlite3VdbeChangeP4(v, -1, (char*)&statGetFuncdef, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, 1 + IsStat34);
}
@@ -95063,7 +89051,7 @@ static void analyzeOneTable(
/* Do not gather statistics on views or virtual tables */
return;
}
- if( sqlite3_strlike("sqlite_%", pTab->zName, 0)==0 ){
+ if( sqlite3_strnicmp(pTab->zName, "sqlite_", 7)==0 ){
/* Do not gather statistics on system tables */
return;
}
@@ -95087,7 +89075,7 @@ static void analyzeOneTable(
iIdxCur = iTab++;
pParse->nTab = MAX(pParse->nTab, iTab);
sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
- sqlite3VdbeLoadString(v, regTabname, pTab->zName);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int nCol; /* Number of columns in pIdx. "N" */
@@ -95109,7 +89097,7 @@ static void analyzeOneTable(
}
/* Populate the register containing the index name. */
- sqlite3VdbeLoadString(v, regIdxname, zIdxName);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, regIdxname, 0, zIdxName, 0);
VdbeComment((v, "Analysis for %s.%s", pTab->zName, zIdxName));
/*
@@ -95171,8 +89159,8 @@ static void analyzeOneTable(
#endif
sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
- sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4+1, regStat4,
- (char*)&statInitFuncdef, P4_FUNCDEF);
+ sqlite3VdbeAddOp3(v, OP_Function, 0, regStat4+1, regStat4);
+ sqlite3VdbeChangeP4(v, -1, (char*)&statInitFuncdef, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, 2+IsStat34);
/* Implementation of the following:
@@ -95191,7 +89179,7 @@ static void analyzeOneTable(
if( nColTest>0 ){
int endDistinctTest = sqlite3VdbeMakeLabel(v);
int *aGotoChng; /* Array of jump instruction addresses */
- aGotoChng = sqlite3DbMallocRawNN(db, sizeof(int)*nColTest);
+ aGotoChng = sqlite3DbMallocRaw(db, sizeof(int)*nColTest);
if( aGotoChng==0 ) continue;
/*
@@ -95223,7 +89211,7 @@ static void analyzeOneTable(
VdbeCoverage(v);
}
sqlite3VdbeAddOp2(v, OP_Integer, nColTest, regChng);
- sqlite3VdbeGoto(v, endDistinctTest);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, endDistinctTest);
/*
@@ -95259,7 +89247,6 @@ static void analyzeOneTable(
regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
for(j=0; j<pPk->nKeyCol; j++){
k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
- assert( k>=0 && k<pTab->nCol );
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
}
@@ -95268,8 +89255,8 @@ static void analyzeOneTable(
}
#endif
assert( regChng==(regStat4+1) );
- sqlite3VdbeAddOp4(v, OP_Function0, 1, regStat4, regTemp,
- (char*)&statPushFuncdef, P4_FUNCDEF);
+ sqlite3VdbeAddOp3(v, OP_Function, 1, regStat4, regTemp);
+ sqlite3VdbeChangeP4(v, -1, (char*)&statPushFuncdef, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, 2+IsStat34);
sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
@@ -95309,10 +89296,12 @@ static void analyzeOneTable(
** be taken */
VdbeCoverageNeverTaken(v);
#ifdef SQLITE_ENABLE_STAT3
- sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, 0, regSample);
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur,
+ pIdx->aiColumn[0], regSample);
#else
for(i=0; i<nCol; i++){
- sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, i, regCol+i);
+ i16 iCol = pIdx->aiColumn[i];
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regCol+i);
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol, regSample);
#endif
@@ -95599,7 +89588,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
** the old data with the new instead of allocating a new array. */
if( pIndex->aiRowEst==0 ){
pIndex->aiRowEst = (tRowcnt*)sqlite3MallocZero(sizeof(tRowcnt) * nCol);
- if( pIndex->aiRowEst==0 ) sqlite3OomFault(pInfo->db);
+ if( pIndex->aiRowEst==0 ) pInfo->db->mallocFailed = 1;
}
aiRowEst = pIndex->aiRowEst;
#endif
@@ -95746,10 +89735,10 @@ static int loadStatTbl(
Index *pPrevIdx = 0; /* Previous index in the loop */
IndexSample *pSample; /* A slot in pIdx->aSample[] */
- assert( db->lookaside.bDisable );
+ assert( db->lookaside.bEnabled==0 );
zSql = sqlite3MPrintf(db, zSql1, zDb);
if( !zSql ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
sqlite3DbFree(db, zSql);
@@ -95789,7 +89778,7 @@ static int loadStatTbl(
pIdx->aSample = sqlite3DbMallocZero(db, nByte);
if( pIdx->aSample==0 ){
sqlite3_finalize(pStmt);
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
pSpace = (tRowcnt*)&pIdx->aSample[nSample];
pIdx->aAvgEq = pSpace; pSpace += nIdxCol;
@@ -95805,7 +89794,7 @@ static int loadStatTbl(
zSql = sqlite3MPrintf(db, zSql2, zDb);
if( !zSql ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
sqlite3DbFree(db, zSql);
@@ -95843,7 +89832,7 @@ static int loadStatTbl(
pSample->p = sqlite3DbMallocZero(db, pSample->n + 2);
if( pSample->p==0 ){
sqlite3_finalize(pStmt);
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
memcpy(pSample->p, sqlite3_column_blob(pStmt, 4), pSample->n);
pIdx->nSample++;
@@ -95860,7 +89849,7 @@ static int loadStatTbl(
static int loadStat4(sqlite3 *db, const char *zDb){
int rc = SQLITE_OK; /* Result codes from subroutines */
- assert( db->lookaside.bDisable );
+ assert( db->lookaside.bEnabled==0 );
if( sqlite3FindTable(db, "sqlite_stat4", zDb) ){
rc = loadStatTbl(db, 0,
"SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx",
@@ -95905,7 +89894,7 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
analysisInfo sInfo;
HashElem *i;
char *zSql;
- int rc = SQLITE_OK;
+ int rc;
assert( iDb>=0 && iDb<db->nDb );
assert( db->aDb[iDb].pBt!=0 );
@@ -95914,40 +89903,38 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
Index *pIdx = sqliteHashData(i);
- pIdx->aiRowLogEst[0] = 0;
+ sqlite3DefaultRowEst(pIdx);
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
sqlite3DeleteIndexSamples(db, pIdx);
pIdx->aSample = 0;
#endif
}
- /* Load new statistics out of the sqlite_stat1 table */
+ /* Check to make sure the sqlite_stat1 table exists */
sInfo.db = db;
sInfo.zDatabase = db->aDb[iDb].zName;
- if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)!=0 ){
- zSql = sqlite3MPrintf(db,
- "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
- if( zSql==0 ){
- rc = SQLITE_NOMEM_BKPT;
- }else{
- rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
- sqlite3DbFree(db, zSql);
- }
+ if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)==0 ){
+ return SQLITE_ERROR;
}
- /* Set appropriate defaults on all indexes not in the sqlite_stat1 table */
- assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
- for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
- Index *pIdx = sqliteHashData(i);
- if( pIdx->aiRowLogEst[0]==0 ) sqlite3DefaultRowEst(pIdx);
+ /* Load new statistics out of the sqlite_stat1 table */
+ zSql = sqlite3MPrintf(db,
+ "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
+ sqlite3DbFree(db, zSql);
}
+
/* Load the statistics from the sqlite_stat4 table. */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
if( rc==SQLITE_OK && OptimizationEnabled(db, SQLITE_Stat34) ){
- db->lookaside.bDisable++;
+ int lookasideEnabled = db->lookaside.bEnabled;
+ db->lookaside.bEnabled = 0;
rc = loadStat4(db, sInfo.zDatabase);
- db->lookaside.bDisable--;
+ db->lookaside.bEnabled = lookasideEnabled;
}
for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
Index *pIdx = sqliteHashData(i);
@@ -95957,7 +89944,7 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
#endif
if( rc==SQLITE_NOMEM ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
}
return rc;
}
@@ -95980,7 +89967,6 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
*************************************************************************
** This file contains code used to implement the ATTACH and DETACH commands.
*/
-/* #include "sqliteInt.h" */
#ifndef SQLITE_OMIT_ATTACH
/*
@@ -96078,7 +90064,7 @@ static void attachFunc(
** hash tables.
*/
if( db->aDb==db->aDbStatic ){
- aNew = sqlite3DbMallocRawNN(db, sizeof(db->aDb[0])*3 );
+ aNew = sqlite3DbMallocRaw(db, sizeof(db->aDb[0])*3 );
if( aNew==0 ) return;
memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
}else{
@@ -96096,7 +90082,7 @@ static void attachFunc(
flags = db->openFlags;
rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr);
if( rc!=SQLITE_OK ){
- if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
+ if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
sqlite3_result_error(context, zErr, -1);
sqlite3_free(zErr);
return;
@@ -96113,7 +90099,7 @@ static void attachFunc(
Pager *pPager;
aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt);
if( !aNew->pSchema ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){
zErrDyn = sqlite3MPrintf(db,
"attached databases must use the same text encoding as main database");
@@ -96125,15 +90111,14 @@ static void attachFunc(
sqlite3BtreeSecureDelete(aNew->pBt,
sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) );
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
- sqlite3BtreeSetPagerFlags(aNew->pBt,
- PAGER_SYNCHRONOUS_FULL | (db->flags & PAGER_FLAGS_MASK));
+ sqlite3BtreeSetPagerFlags(aNew->pBt, 3 | (db->flags & PAGER_FLAGS_MASK));
#endif
sqlite3BtreeLeave(aNew->pBt);
}
- aNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
+ aNew->safety_level = 3;
aNew->zName = sqlite3DbStrDup(db, zName);
if( rc==SQLITE_OK && aNew->zName==0 ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}
@@ -96199,7 +90184,7 @@ static void attachFunc(
sqlite3ResetAllSchemasOfConnection(db);
db->nDb = iDb;
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
sqlite3DbFree(db, zErrDyn);
zErrDyn = sqlite3MPrintf(db, "out of memory");
}else if( zErrDyn==0 ){
@@ -96329,11 +90314,11 @@ static void codeAttach(
assert( v || db->mallocFailed );
if( v ){
- sqlite3VdbeAddOp4(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3,
- (char *)pFunc, P4_FUNCDEF);
+ sqlite3VdbeAddOp3(v, OP_Function, 0, regArgs+3-pFunc->nArg, regArgs+3);
assert( pFunc->nArg==-1 || (pFunc->nArg&0xff)==pFunc->nArg );
sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg));
-
+ sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF);
+
/* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
** statement only). For DETACH, set it to false (expire all existing
** statements).
@@ -96358,10 +90343,12 @@ SQLITE_PRIVATE void sqlite3Detach(Parse *pParse, Expr *pDbname){
SQLITE_UTF8, /* funcFlags */
0, /* pUserData */
0, /* pNext */
- detachFunc, /* xSFunc */
+ detachFunc, /* xFunc */
+ 0, /* xStep */
0, /* xFinalize */
"sqlite_detach", /* zName */
- {0}
+ 0, /* pHash */
+ 0 /* pDestructor */
};
codeAttach(pParse, SQLITE_DETACH, &detach_func, pDbname, 0, 0, pDbname);
}
@@ -96377,10 +90364,12 @@ SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *p
SQLITE_UTF8, /* funcFlags */
0, /* pUserData */
0, /* pNext */
- attachFunc, /* xSFunc */
+ attachFunc, /* xFunc */
+ 0, /* xStep */
0, /* xFinalize */
"sqlite_attach", /* zName */
- {0}
+ 0, /* pHash */
+ 0 /* pDestructor */
};
codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey);
}
@@ -96567,7 +90556,6 @@ SQLITE_PRIVATE int sqlite3FixTriggerStep(
** systems that do not need this facility may omit it by recompiling
** the library with -DSQLITE_OMIT_AUTHORIZATION=1
*/
-/* #include "sqliteInt.h" */
/*
** All of the code in this file may be omitted by defining a single
@@ -96838,7 +90826,15 @@ SQLITE_PRIVATE void sqlite3AuthContextPop(AuthContext *pContext){
** COMMIT
** ROLLBACK
*/
-/* #include "sqliteInt.h" */
+
+/*
+** This routine is called when a new SQL statement is beginning to
+** be parsed. Initialize the pParse structure as needed.
+*/
+SQLITE_PRIVATE void sqlite3BeginParse(Parse *pParse, int explainFlag){
+ pParse->explain = (u8)explainFlag;
+ pParse->nVar = 0;
+}
#ifndef SQLITE_OMIT_SHARED_CACHE
/*
@@ -96894,7 +90890,7 @@ SQLITE_PRIVATE void sqlite3TableLock(
p->zName = zName;
}else{
pToplevel->nTableLock = 0;
- sqlite3OomFault(pToplevel->db);
+ pToplevel->db->mallocFailed = 1;
}
}
@@ -96999,8 +90995,6 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
db->aDb[iDb].pSchema->iGeneration /* P4 */
);
if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
- VdbeComment((v,
- "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite));
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
for(i=0; i<pParse->nVtabLock; i++){
@@ -97030,7 +91024,7 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
}
/* Finally, jump back to the beginning of the executable code. */
- sqlite3VdbeGoto(v, 1);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, 1);
}
}
@@ -97044,19 +91038,15 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1;
sqlite3VdbeMakeReady(v, pParse);
pParse->rc = SQLITE_DONE;
+ pParse->colNamesSet = 0;
}else{
pParse->rc = SQLITE_ERROR;
}
-
- /* We are done with this Parse object. There is no need to de-initialize it */
-#if 0
- pParse->colNamesSet = 0;
pParse->nTab = 0;
pParse->nMem = 0;
pParse->nSet = 0;
pParse->nVar = 0;
DbMaskZero(pParse->cookieMask);
-#endif
}
/*
@@ -97169,17 +91159,6 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
p = sqlite3FindTable(pParse->db, zName, zDbase);
if( p==0 ){
const char *zMsg = isView ? "no such view" : "no such table";
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( sqlite3FindDbName(pParse->db, zDbase)<1 ){
- /* If zName is the not the name of a table in the schema created using
- ** CREATE, then check to see if it is the name of an virtual table that
- ** can be an eponymous virtual table. */
- Module *pMod = (Module*)sqlite3HashFind(&pParse->db->aModule, zName);
- if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){
- return pMod->pEpoTab;
- }
- }
-#endif
if( zDbase ){
sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
}else{
@@ -97187,7 +91166,12 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
}
pParse->checkSchema = 1;
}
-
+#if SQLITE_USER_AUTHENICATION
+ else if( pParse->db->auth.authLevel<UAUTH_User ){
+ sqlite3ErrorMsg(pParse, "user not authenticated");
+ p = 0;
+ }
+#endif
return p;
}
@@ -97253,9 +91237,8 @@ static void freeIndex(sqlite3 *db, Index *p){
sqlite3DeleteIndexSamples(db, p);
#endif
sqlite3ExprDelete(db, p->pPartIdxWhere);
- sqlite3ExprListDelete(db, p->aColExpr);
sqlite3DbFree(db, p->zColAff);
- if( p->isResized ) sqlite3DbFree(db, (void *)p->azColl);
+ if( p->isResized ) sqlite3DbFree(db, p->azColl);
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
sqlite3_free(p->aiRowEst);
#endif
@@ -97315,6 +91298,7 @@ SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3 *db){
}
j++;
}
+ memset(&db->aDb[j], 0, (db->nDb-j)*sizeof(db->aDb[j]));
db->nDb = j;
if( db->nDb<=2 && db->aDb!=db->aDbStatic ){
memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0]));
@@ -97379,7 +91363,7 @@ SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3 *db){
** Delete memory allocated for the column names of a table or view (the
** Table.aCol[] array).
*/
-SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
+static void sqliteDeleteColumnNames(sqlite3 *db, Table *pTable){
int i;
Column *pCol;
assert( pTable!=0 );
@@ -97387,6 +91371,8 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
for(i=0; i<pTable->nCol; i++, pCol++){
sqlite3DbFree(db, pCol->zName);
sqlite3ExprDelete(db, pCol->pDflt);
+ sqlite3DbFree(db, pCol->zDflt);
+ sqlite3DbFree(db, pCol->zType);
sqlite3DbFree(db, pCol->zColl);
}
sqlite3DbFree(db, pTable->aCol);
@@ -97408,10 +91394,16 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
** db parameter can be used with db->pnBytesFreed to measure the memory
** used by the Table object.
*/
-static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
+SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
Index *pIndex, *pNext;
TESTONLY( int nLookaside; ) /* Used to verify lookaside not used for schema */
+ assert( !pTable || pTable->nRef>0 );
+
+ /* Do not delete the table until the reference count reaches zero. */
+ if( !pTable ) return;
+ if( ((!db || db->pnBytesFreed==0) && (--pTable->nRef)>0) ) return;
+
/* Record the number of outstanding lookaside allocations in schema Tables
** prior to doing any free() operations. Since schema Tables do not use
** lookaside, this number should not change. */
@@ -97438,11 +91430,13 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
/* Delete the Table structure itself.
*/
- sqlite3DeleteColumnNames(db, pTable);
+ sqliteDeleteColumnNames(db, pTable);
sqlite3DbFree(db, pTable->zName);
sqlite3DbFree(db, pTable->zColAff);
sqlite3SelectDelete(db, pTable->pSelect);
+#ifndef SQLITE_OMIT_CHECK
sqlite3ExprListDelete(db, pTable->pCheck);
+#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
sqlite3VtabClear(db, pTable);
#endif
@@ -97451,13 +91445,6 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
/* Verify that no lookaside memory was used by schema tables */
assert( nLookaside==0 || nLookaside==db->lookaside.nOut );
}
-SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
- /* Do not delete the table until the reference count reaches zero. */
- if( !pTable ) return;
- if( ((!db || db->pnBytesFreed==0) && (--pTable->nRef)>0) ) return;
- deleteTable(db, pTable);
-}
-
/*
** Unlink the given table from the hash tables and the delete the
@@ -97525,8 +91512,12 @@ SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *db, const char *zName){
int i = -1; /* Database number */
if( zName ){
Db *pDb;
+ int n = sqlite3Strlen30(zName);
for(i=(db->nDb-1), pDb=&db->aDb[i]; i>=0; i--, pDb--){
- if( 0==sqlite3StrICmp(pDb->zName, zName) ) break;
+ if( (!OMIT_TEMPDB || i!=1 ) && n==sqlite3Strlen30(pDb->zName) &&
+ 0==sqlite3StrICmp(pDb->zName, zName) ){
+ break;
+ }
}
}
return i;
@@ -97572,8 +91563,7 @@ SQLITE_PRIVATE int sqlite3TwoPartName(
int iDb; /* Database holding the object */
sqlite3 *db = pParse->db;
- assert( pName2!=0 );
- if( pName2->n>0 ){
+ if( ALWAYS(pName2!=0) && pName2->n>0 ){
if( db->init.busy ) {
sqlite3ErrorMsg(pParse, "corrupt database");
return -1;
@@ -97662,46 +91652,62 @@ SQLITE_PRIVATE void sqlite3StartTable(
int iDb; /* Database number to create the table in */
Token *pName; /* Unqualified name of the table to create */
- if( db->init.busy && db->init.newTnum==1 ){
- /* Special case: Parsing the sqlite_master or sqlite_temp_master schema */
- iDb = db->init.iDb;
- zName = sqlite3DbStrDup(db, SCHEMA_TABLE(iDb));
- pName = pName1;
- }else{
- /* The common case */
- iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
- if( iDb<0 ) return;
- 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;
- }
- if( !OMIT_TEMPDB && isTemp ) iDb = 1;
- zName = sqlite3NameFromToken(db, pName);
+ /* The table or view name to create is passed to this routine via tokens
+ ** pName1 and pName2. If the table name was fully qualified, for example:
+ **
+ ** CREATE TABLE xxx.yyy (...);
+ **
+ ** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if
+ ** the table name is not fully qualified, i.e.:
+ **
+ ** CREATE TABLE yyy(...);
+ **
+ ** Then pName1 is set to "yyy" and pName2 is "".
+ **
+ ** The call below sets the pName pointer to point at the token (pName1 or
+ ** pName2) that stores the unqualified table name. The variable iDb is
+ ** set to the index of the database that the table or view is to be
+ ** created in.
+ */
+ iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
+ if( iDb<0 ) return;
+ 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;
}
+ if( !OMIT_TEMPDB && isTemp ) iDb = 1;
+
pParse->sNameToken = *pName;
+ zName = sqlite3NameFromToken(db, pName);
if( zName==0 ) return;
if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
goto begin_table_error;
}
if( db->init.iDb==1 ) isTemp = 1;
#ifndef SQLITE_OMIT_AUTHORIZATION
- assert( isTemp==0 || isTemp==1 );
- assert( isView==0 || isView==1 );
+ assert( (isTemp & 1)==isTemp );
{
- static const u8 aCode[] = {
- SQLITE_CREATE_TABLE,
- SQLITE_CREATE_TEMP_TABLE,
- SQLITE_CREATE_VIEW,
- SQLITE_CREATE_TEMP_VIEW
- };
+ int code;
char *zDb = db->aDb[iDb].zName;
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
goto begin_table_error;
}
- if( !isVirtual && sqlite3AuthCheck(pParse, (int)aCode[isTemp+2*isView],
- zName, 0, zDb) ){
+ if( isView ){
+ if( !OMIT_TEMPDB && isTemp ){
+ code = SQLITE_CREATE_TEMP_VIEW;
+ }else{
+ code = SQLITE_CREATE_VIEW;
+ }
+ }else{
+ if( !OMIT_TEMPDB && isTemp ){
+ code = SQLITE_CREATE_TEMP_TABLE;
+ }else{
+ code = SQLITE_CREATE_TABLE;
+ }
+ }
+ if( !isVirtual && sqlite3AuthCheck(pParse, code, zName, 0, zDb) ){
goto begin_table_error;
}
}
@@ -97737,8 +91743,8 @@ SQLITE_PRIVATE void sqlite3StartTable(
pTable = sqlite3DbMallocZero(db, sizeof(Table));
if( pTable==0 ){
- assert( db->mallocFailed );
- pParse->rc = SQLITE_NOMEM_BKPT;
+ db->mallocFailed = 1;
+ pParse->rc = SQLITE_NOMEM;
pParse->nErr++;
goto begin_table_error;
}
@@ -97770,12 +91776,10 @@ SQLITE_PRIVATE void sqlite3StartTable(
** now.
*/
if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){
- int addr1;
+ int j1;
int fileFormat;
int reg1, reg2, reg3;
- /* nullRow[] is an OP_Record encoding of a row containing 5 NULLs */
- static const char nullRow[] = { 6, 0, 0, 0, 0, 0 };
- sqlite3BeginWriteOperation(pParse, 1, iDb);
+ sqlite3BeginWriteOperation(pParse, 0, iDb);
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( isVirtual ){
@@ -97791,12 +91795,14 @@ SQLITE_PRIVATE void sqlite3StartTable(
reg3 = ++pParse->nMem;
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, reg3, BTREE_FILE_FORMAT);
sqlite3VdbeUsesBtree(v, iDb);
- addr1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v);
+ j1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v);
fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ?
1 : SQLITE_MAX_FILE_FORMAT;
- sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, fileFormat);
- sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, ENC(db));
- sqlite3VdbeJumpHere(v, addr1);
+ sqlite3VdbeAddOp2(v, OP_Integer, fileFormat, reg3);
+ sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, reg3);
+ sqlite3VdbeAddOp2(v, OP_Integer, ENC(db), reg3);
+ sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, reg3);
+ sqlite3VdbeJumpHere(v, j1);
/* This just creates a place-holder record in the sqlite_master table.
** The record created does not contain anything yet. It will be replaced
@@ -97817,7 +91823,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
}
sqlite3OpenMasterTable(pParse, iDb);
sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1);
- sqlite3VdbeAddOp4(v, OP_Blob, 6, reg3, 0, nullRow, P4_STATIC);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, reg3);
sqlite3VdbeAddOp3(v, OP_Insert, 0, reg3, reg1);
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
sqlite3VdbeAddOp0(v, OP_Close);
@@ -97832,19 +91838,18 @@ begin_table_error:
return;
}
-/* Set properties of a table column based on the (magical)
-** name of the column.
+/*
+** This macro is used to compare two strings in a case-insensitive manner.
+** It is slightly faster than calling sqlite3StrICmp() directly, but
+** produces larger code.
+**
+** WARNING: This macro is not compatible with the strcmp() family. It
+** returns true if the two strings are equal, otherwise false.
*/
-#if SQLITE_ENABLE_HIDDEN_COLUMNS
-SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){
- if( sqlite3_strnicmp(pCol->zName, "__hidden__", 10)==0 ){
- pCol->colFlags |= COLFLAG_HIDDEN;
- }else if( pTab && pCol!=pTab->aCol && (pCol[-1].colFlags & COLFLAG_HIDDEN) ){
- pTab->tabFlags |= TF_OOOHidden;
- }
-}
-#endif
-
+#define STRICMP(x, y) (\
+sqlite3UpperToLower[*(unsigned char *)(x)]== \
+sqlite3UpperToLower[*(unsigned char *)(y)] \
+&& sqlite3StrICmp((x)+1,(y)+1)==0 )
/*
** Add a new column to the table currently being constructed.
@@ -97854,11 +91859,10 @@ SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){
** first to get things going. Then this routine is called for each
** column.
*/
-SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
+SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName){
Table *p;
int i;
char *z;
- char *zType;
Column *pCol;
sqlite3 *db = pParse->db;
if( (p = pParse->pNewTable)==0 ) return;
@@ -97868,13 +91872,10 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
return;
}
#endif
- z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2);
+ z = sqlite3NameFromToken(db, pName);
if( z==0 ) return;
- memcpy(z, pName->z, pName->n);
- z[pName->n] = 0;
- sqlite3Dequote(z);
for(i=0; i<p->nCol; i++){
- if( sqlite3_stricmp(z, p->aCol[i].zName)==0 ){
+ if( STRICMP(z, p->aCol[i].zName) ){
sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
sqlite3DbFree(db, z);
return;
@@ -97892,23 +91893,14 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
pCol = &p->aCol[p->nCol];
memset(pCol, 0, sizeof(p->aCol[0]));
pCol->zName = z;
- sqlite3ColumnPropertiesFromName(p, pCol);
- if( pType->n==0 ){
- /* If there is no type specified, columns have the default affinity
- ** 'BLOB'. */
- pCol->affinity = SQLITE_AFF_BLOB;
- pCol->szEst = 1;
- }else{
- zType = z + sqlite3Strlen30(z) + 1;
- memcpy(zType, pType->z, pType->n);
- zType[pType->n] = 0;
- sqlite3Dequote(zType);
- pCol->affinity = sqlite3AffinityType(zType, &pCol->szEst);
- pCol->colFlags |= COLFLAG_HASTYPE;
- }
+ /* If there is no type specified, columns have the default affinity
+ ** 'NONE'. If there is a type specified, then sqlite3AddColumnType() will
+ ** be called next to set pCol->affinity correctly.
+ */
+ pCol->affinity = SQLITE_AFF_NONE;
+ pCol->szEst = 1;
p->nCol++;
- pParse->constraintName.n = 0;
}
/*
@@ -97941,7 +91933,7 @@ SQLITE_PRIVATE void sqlite3AddNotNull(Parse *pParse, int onError){
** 'CHAR' | SQLITE_AFF_TEXT
** 'CLOB' | SQLITE_AFF_TEXT
** 'TEXT' | SQLITE_AFF_TEXT
-** 'BLOB' | SQLITE_AFF_BLOB
+** 'BLOB' | SQLITE_AFF_NONE
** 'REAL' | SQLITE_AFF_REAL
** 'FLOA' | SQLITE_AFF_REAL
** 'DOUB' | SQLITE_AFF_REAL
@@ -97954,7 +91946,7 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){
char aff = SQLITE_AFF_NUMERIC;
const char *zChar = 0;
- assert( zIn!=0 );
+ if( zIn==0 ) return aff;
while( zIn[0] ){
h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff];
zIn++;
@@ -97967,7 +91959,7 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){
aff = SQLITE_AFF_TEXT;
}else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') /* BLOB */
&& (aff==SQLITE_AFF_NUMERIC || aff==SQLITE_AFF_REAL) ){
- aff = SQLITE_AFF_BLOB;
+ aff = SQLITE_AFF_NONE;
if( zIn[0]=='(' ) zChar = zIn;
#ifndef SQLITE_OMIT_FLOATING_POINT
}else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l') /* REAL */
@@ -98012,6 +92004,28 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){
}
/*
+** This routine is called by the parser while in the middle of
+** parsing a CREATE TABLE statement. The pFirst token is the first
+** token in the sequence of tokens that describe the type of the
+** column currently under construction. pLast is the last token
+** in the sequence. Use this information to construct a string
+** that contains the typename of the column and store that string
+** in zType.
+*/
+SQLITE_PRIVATE void sqlite3AddColumnType(Parse *pParse, Token *pType){
+ Table *p;
+ Column *pCol;
+
+ p = pParse->pNewTable;
+ if( p==0 || NEVER(p->nCol<1) ) return;
+ pCol = &p->aCol[p->nCol-1];
+ assert( pCol->zType==0 || CORRUPT_DB );
+ sqlite3DbFree(pParse->db, pCol->zType);
+ pCol->zType = sqlite3NameFromToken(pParse->db, pType);
+ pCol->affinity = sqlite3AffinityType(pCol->zType, &pCol->szEst);
+}
+
+/*
** The expression is the default value for the most recently added column
** of the table currently under construction.
**
@@ -98036,46 +92050,17 @@ SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){
** tokens that point to volatile memory. The 'span' of the expression
** is required by pragma table_info.
*/
- Expr x;
sqlite3ExprDelete(db, pCol->pDflt);
- memset(&x, 0, sizeof(x));
- x.op = TK_SPAN;
- x.u.zToken = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
- (int)(pSpan->zEnd - pSpan->zStart));
- x.pLeft = pSpan->pExpr;
- x.flags = EP_Skip;
- pCol->pDflt = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE);
- sqlite3DbFree(db, x.u.zToken);
+ pCol->pDflt = sqlite3ExprDup(db, pSpan->pExpr, EXPRDUP_REDUCE);
+ sqlite3DbFree(db, pCol->zDflt);
+ pCol->zDflt = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
+ (int)(pSpan->zEnd - pSpan->zStart));
}
}
sqlite3ExprDelete(db, pSpan->pExpr);
}
/*
-** Backwards Compatibility Hack:
-**
-** Historical versions of SQLite accepted strings as column names in
-** indexes and PRIMARY KEY constraints and in UNIQUE constraints. Example:
-**
-** CREATE TABLE xyz(a,b,c,d,e,PRIMARY KEY('a'),UNIQUE('b','c' COLLATE trim)
-** CREATE INDEX abc ON xyz('c','d' DESC,'e' COLLATE nocase DESC);
-**
-** This is goofy. But to preserve backwards compatibility we continue to
-** accept it. This routine does the necessary conversion. It converts
-** the expression given in its argument from a TK_STRING into a TK_ID
-** if the expression is just a TK_STRING with an optional COLLATE clause.
-** If the epxression is anything other than TK_STRING, the expression is
-** unchanged.
-*/
-static void sqlite3StringToId(Expr *p){
- if( p->op==TK_STRING ){
- p->op = TK_ID;
- }else if( p->op==TK_COLLATE && p->pLeft->op==TK_STRING ){
- p->pLeft->op = TK_ID;
- }
-}
-
-/*
** Designate the PRIMARY KEY for the table. pList is a list of names
** of columns that form the primary key. If pList is NULL, then the
** most recently added column of the table is the primary key.
@@ -98101,7 +92086,7 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */
){
Table *pTab = pParse->pNewTable;
- Column *pCol = 0;
+ char *zType = 0;
int iCol = -1, i;
int nTerm;
if( pTab==0 || IN_DECLARE_VTAB ) goto primary_key_exit;
@@ -98113,31 +92098,24 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
pTab->tabFlags |= TF_HasPrimaryKey;
if( pList==0 ){
iCol = pTab->nCol - 1;
- pCol = &pTab->aCol[iCol];
- pCol->colFlags |= COLFLAG_PRIMKEY;
+ pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
+ zType = pTab->aCol[iCol].zType;
nTerm = 1;
}else{
nTerm = pList->nExpr;
for(i=0; i<nTerm; i++){
- Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[i].pExpr);
- assert( pCExpr!=0 );
- sqlite3StringToId(pCExpr);
- if( pCExpr->op==TK_ID ){
- const char *zCName = pCExpr->u.zToken;
- for(iCol=0; iCol<pTab->nCol; iCol++){
- if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){
- pCol = &pTab->aCol[iCol];
- pCol->colFlags |= COLFLAG_PRIMKEY;
- break;
- }
+ for(iCol=0; iCol<pTab->nCol; iCol++){
+ if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[iCol].zName)==0 ){
+ pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
+ zType = pTab->aCol[iCol].zType;
+ break;
}
}
}
}
if( nTerm==1
- && pCol
- && sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0
- && sortOrder!=SQLITE_SO_DESC
+ && zType && sqlite3StrICmp(zType, "INTEGER")==0
+ && sortOrder==SQLITE_SO_ASC
){
pTab->iPKey = iCol;
pTab->keyConf = (u8)onError;
@@ -98150,11 +92128,14 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
"INTEGER PRIMARY KEY");
#endif
}else{
+ Vdbe *v = pParse->pVdbe;
Index *p;
+ if( v ) pParse->addrSkipPK = sqlite3VdbeAddOp0(v, OP_Noop);
p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0,
0, sortOrder, 0);
if( p ){
p->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
+ if( v ) sqlite3VdbeJumpHere(v, pParse->addrSkipPK);
}
pList = 0;
}
@@ -98276,11 +92257,13 @@ SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){
** 1 chance in 2^32. So we're safe enough.
*/
SQLITE_PRIVATE void sqlite3ChangeCookie(Parse *pParse, int iDb){
+ int r1 = sqlite3GetTempReg(pParse);
sqlite3 *db = pParse->db;
Vdbe *v = pParse->pVdbe;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
- sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION,
- db->aDb[iDb].pSchema->schema_cookie+1);
+ sqlite3VdbeAddOp2(v, OP_Integer, db->aDb[iDb].pSchema->schema_cookie+1, r1);
+ sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION, r1);
+ sqlite3ReleaseTempReg(pParse, r1);
}
/*
@@ -98362,7 +92345,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){
n += 35 + 6*p->nCol;
zStmt = sqlite3DbMallocRaw(0, n);
if( zStmt==0 ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
return 0;
}
sqlite3_snprintf(n, zStmt, "CREATE TABLE ");
@@ -98371,7 +92354,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){
zStmt[k++] = '(';
for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){
static const char * const azType[] = {
- /* SQLITE_AFF_BLOB */ "",
+ /* SQLITE_AFF_NONE */ "",
/* SQLITE_AFF_TEXT */ " TEXT",
/* SQLITE_AFF_NUMERIC */ " NUM",
/* SQLITE_AFF_INTEGER */ " INT",
@@ -98384,17 +92367,17 @@ static char *createTableStmt(sqlite3 *db, Table *p){
k += sqlite3Strlen30(&zStmt[k]);
zSep = zSep2;
identPut(zStmt, &k, pCol->zName);
- assert( pCol->affinity-SQLITE_AFF_BLOB >= 0 );
- assert( pCol->affinity-SQLITE_AFF_BLOB < ArraySize(azType) );
- testcase( pCol->affinity==SQLITE_AFF_BLOB );
+ assert( pCol->affinity-SQLITE_AFF_NONE >= 0 );
+ assert( pCol->affinity-SQLITE_AFF_NONE < ArraySize(azType) );
+ testcase( pCol->affinity==SQLITE_AFF_NONE );
testcase( pCol->affinity==SQLITE_AFF_TEXT );
testcase( pCol->affinity==SQLITE_AFF_NUMERIC );
testcase( pCol->affinity==SQLITE_AFF_INTEGER );
testcase( pCol->affinity==SQLITE_AFF_REAL );
- zType = azType[pCol->affinity - SQLITE_AFF_BLOB];
+ zType = azType[pCol->affinity - SQLITE_AFF_NONE];
len = sqlite3Strlen30(zType);
- assert( pCol->affinity==SQLITE_AFF_BLOB
+ assert( pCol->affinity==SQLITE_AFF_NONE
|| pCol->affinity==sqlite3AffinityType(zType, 0) );
memcpy(&zStmt[k], zType, len);
k += len;
@@ -98415,9 +92398,9 @@ static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){
assert( pIdx->isResized==0 );
nByte = (sizeof(char*) + sizeof(i16) + 1)*N;
zExtra = sqlite3DbMallocZero(db, nByte);
- if( zExtra==0 ) return SQLITE_NOMEM_BKPT;
+ if( zExtra==0 ) return SQLITE_NOMEM;
memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn);
- pIdx->azColl = (const char**)zExtra;
+ pIdx->azColl = (char**)zExtra;
zExtra += sizeof(char*)*N;
memcpy(zExtra, pIdx->aiColumn, sizeof(i16)*pIdx->nColumn);
pIdx->aiColumn = (i16*)zExtra;
@@ -98502,7 +92485,15 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
*/
if( pParse->addrCrTab ){
assert( v );
- sqlite3VdbeChangeOpcode(v, pParse->addrCrTab, OP_CreateIndex);
+ sqlite3VdbeGetOp(v, pParse->addrCrTab)->opcode = OP_CreateIndex;
+ }
+
+ /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master
+ ** table entry.
+ */
+ if( pParse->addrSkipPK ){
+ assert( v );
+ sqlite3VdbeGetOp(v, pParse->addrSkipPK)->opcode = OP_Goto;
}
/* Locate the PRIMARY KEY index. Or, if this table was originally
@@ -98510,11 +92501,10 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
*/
if( pTab->iPKey>=0 ){
ExprList *pList;
- Token ipkToken;
- sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zName);
- pList = sqlite3ExprListAppend(pParse, 0,
- sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0));
+ pList = sqlite3ExprListAppend(pParse, 0, 0);
if( pList==0 ) return;
+ pList->a[0].zName = sqlite3DbStrDup(pParse->db,
+ pTab->aCol[pTab->iPKey].zName);
pList->a[0].sortOrder = pParse->iPkSortOrder;
assert( pParse->pNewTable==pTab );
pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0);
@@ -98523,16 +92513,6 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
pTab->iPKey = -1;
}else{
pPk = sqlite3PrimaryKeyIndex(pTab);
-
- /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master
- ** table entry. This is only required if currently generating VDBE
- ** code for a CREATE TABLE (not when parsing one as part of reading
- ** a database schema). */
- if( v ){
- assert( db->init.busy==0 );
- sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto);
- }
-
/*
** Remove all redundant columns from the PRIMARY KEY. For example, change
** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)". Later
@@ -98555,7 +92535,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
** do not enforce this for imposter tables.) */
if( !db->init.imposterTable ){
for(i=0; i<nPk; i++){
- pTab->aCol[pPk->aiColumn[i]].notNull = OE_Abort;
+ pTab->aCol[pPk->aiColumn[i]].notNull = 1;
}
pPk->uniqNotNull = 1;
}
@@ -98597,7 +92577,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
if( !hasColumn(pPk->aiColumn, j, i) ){
assert( j<pPk->nColumn );
pPk->aiColumn[j] = i;
- pPk->azColl[j] = sqlite3StrBINARY;
+ pPk->azColl[j] = "BINARY";
j++;
}
}
@@ -98640,10 +92620,9 @@ SQLITE_PRIVATE void sqlite3EndTable(
int iDb; /* Database in which the table lives */
Index *pIdx; /* An implied index of the table */
- if( pEnd==0 && pSelect==0 ){
+ if( (pEnd==0 && pSelect==0) || db->mallocFailed ){
return;
}
- assert( !db->mallocFailed );
p = pParse->pNewTable;
if( p==0 ) return;
@@ -98654,13 +92633,9 @@ SQLITE_PRIVATE void sqlite3EndTable(
** So do not write to the disk again. Extract the root page number
** for the table from the db->init.newTnum field. (The page number
** should have been put there by the sqliteOpenCb routine.)
- **
- ** If the root page number is 1, that means this is the sqlite_master
- ** table itself. So mark it read-only.
*/
if( db->init.busy ){
p->tnum = db->init.newTnum;
- if( p->tnum==1 ) p->tabFlags |= TF_Readonly;
}
/* Special processing for WITHOUT ROWID Tables */
@@ -98673,7 +92648,7 @@ SQLITE_PRIVATE void sqlite3EndTable(
if( (p->tabFlags & TF_HasPrimaryKey)==0 ){
sqlite3ErrorMsg(pParse, "PRIMARY KEY missing on table %s", p->zName);
}else{
- p->tabFlags |= TF_WithoutRowid | TF_NoVisibleRowid;
+ p->tabFlags |= TF_WithoutRowid;
convertToWithoutRowidTable(pParse, p);
}
}
@@ -98741,46 +92716,26 @@ SQLITE_PRIVATE void sqlite3EndTable(
** be redundant.
*/
if( pSelect ){
- SelectDest dest; /* Where the SELECT should store results */
- int regYield; /* Register holding co-routine entry-point */
- int addrTop; /* Top of the co-routine */
- int regRec; /* A record to be insert into the new table */
- int regRowid; /* Rowid of the next row to insert */
- int addrInsLoop; /* Top of the loop for inserting rows */
- Table *pSelTab; /* A table that describes the SELECT results */
-
- regYield = ++pParse->nMem;
- regRec = ++pParse->nMem;
- regRowid = ++pParse->nMem;
+ SelectDest dest;
+ Table *pSelTab;
+
assert(pParse->nTab==1);
- sqlite3MayAbort(pParse);
sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
sqlite3VdbeChangeP5(v, OPFLAG_P2ISREG);
pParse->nTab = 2;
- addrTop = sqlite3VdbeCurrentAddr(v) + 1;
- sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
- sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
+ sqlite3SelectDestInit(&dest, SRT_Table, 1);
sqlite3Select(pParse, pSelect, &dest);
- sqlite3VdbeEndCoroutine(v, regYield);
- sqlite3VdbeJumpHere(v, addrTop - 1);
- if( pParse->nErr ) return;
- pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect);
- if( pSelTab==0 ) return;
- assert( p->aCol==0 );
- p->nCol = pSelTab->nCol;
- p->aCol = pSelTab->aCol;
- pSelTab->nCol = 0;
- pSelTab->aCol = 0;
- sqlite3DeleteTable(db, pSelTab);
- addrInsLoop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
- VdbeCoverage(v);
- sqlite3VdbeAddOp3(v, OP_MakeRecord, dest.iSdst, dest.nSdst, regRec);
- sqlite3TableAffinity(v, p, 0);
- sqlite3VdbeAddOp2(v, OP_NewRowid, 1, regRowid);
- sqlite3VdbeAddOp3(v, OP_Insert, 1, regRec, regRowid);
- sqlite3VdbeGoto(v, addrInsLoop);
- sqlite3VdbeJumpHere(v, addrInsLoop);
sqlite3VdbeAddOp1(v, OP_Close, 1);
+ if( pParse->nErr==0 ){
+ pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect);
+ if( pSelTab==0 ) return;
+ assert( p->aCol==0 );
+ p->nCol = pSelTab->nCol;
+ p->aCol = pSelTab->aCol;
+ pSelTab->nCol = 0;
+ pSelTab->aCol = 0;
+ sqlite3DeleteTable(db, pSelTab);
+ }
}
/* Compute the complete text of the CREATE statement */
@@ -98845,7 +92800,7 @@ SQLITE_PRIVATE void sqlite3EndTable(
pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p);
if( pOld ){
assert( p==pOld ); /* Malloc must have failed inside HashInsert() */
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
return;
}
pParse->pNewTable = 0;
@@ -98875,7 +92830,6 @@ SQLITE_PRIVATE void sqlite3CreateView(
Token *pBegin, /* The CREATE token that begins the statement */
Token *pName1, /* The token that holds the name of the view */
Token *pName2, /* The token that holds the name of the view */
- ExprList *pCNames, /* Optional list of view column names */
Select *pSelect, /* A SELECT statement that will become the new view */
int isTemp, /* TRUE for a TEMPORARY view */
int noErr /* Suppress error messages if VIEW already exists */
@@ -98891,15 +92845,22 @@ SQLITE_PRIVATE void sqlite3CreateView(
if( pParse->nVar>0 ){
sqlite3ErrorMsg(pParse, "parameters are not allowed in views");
- goto create_view_fail;
+ sqlite3SelectDelete(db, pSelect);
+ return;
}
sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr);
p = pParse->pNewTable;
- if( p==0 || pParse->nErr ) goto create_view_fail;
+ if( p==0 || pParse->nErr ){
+ sqlite3SelectDelete(db, pSelect);
+ return;
+ }
sqlite3TwoPartName(pParse, pName1, pName2, &pName);
iDb = sqlite3SchemaToIndex(db, p->pSchema);
sqlite3FixInit(&sFix, pParse, iDb, "view", pName);
- if( sqlite3FixSelect(&sFix, pSelect) ) goto create_view_fail;
+ if( sqlite3FixSelect(&sFix, pSelect) ){
+ sqlite3SelectDelete(db, pSelect);
+ return;
+ }
/* Make a copy of the entire SELECT statement that defines the view.
** This will force all the Expr.token.z values to be dynamically
@@ -98907,31 +92868,30 @@ SQLITE_PRIVATE void sqlite3CreateView(
** they will persist after the current sqlite3_exec() call returns.
*/
p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
- p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE);
- if( db->mallocFailed ) goto create_view_fail;
+ sqlite3SelectDelete(db, pSelect);
+ if( db->mallocFailed ){
+ return;
+ }
+ if( !db->init.busy ){
+ sqlite3ViewGetColumnNames(pParse, p);
+ }
/* Locate the end of the CREATE VIEW statement. Make sEnd point to
** the end.
*/
sEnd = pParse->sLastToken;
- assert( sEnd.z[0]!=0 );
- if( sEnd.z[0]!=';' ){
+ if( ALWAYS(sEnd.z[0]!=0) && sEnd.z[0]!=';' ){
sEnd.z += sEnd.n;
}
sEnd.n = 0;
n = (int)(sEnd.z - pBegin->z);
- assert( n>0 );
z = pBegin->z;
- while( sqlite3Isspace(z[n-1]) ){ n--; }
+ while( ALWAYS(n>0) && sqlite3Isspace(z[n-1]) ){ n--; }
sEnd.z = &z[n-1];
sEnd.n = 1;
/* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */
sqlite3EndTable(pParse, 0, &sEnd, 0, 0);
-
-create_view_fail:
- sqlite3SelectDelete(db, pSelect);
- sqlite3ExprListDelete(db, pCNames);
return;
}
#endif /* SQLITE_OMIT_VIEW */
@@ -98996,10 +92956,11 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
assert( pTable->pSelect );
pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
if( pSel ){
+ u8 enableLookaside = db->lookaside.bEnabled;
n = pParse->nTab;
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
pTable->nCol = -1;
- db->lookaside.bDisable++;
+ db->lookaside.bEnabled = 0;
#ifndef SQLITE_OMIT_AUTHORIZATION
xAuth = db->xAuth;
db->xAuth = 0;
@@ -99008,43 +92969,25 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
#else
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
#endif
+ db->lookaside.bEnabled = enableLookaside;
pParse->nTab = n;
- if( pTable->pCheck ){
- /* CREATE VIEW name(arglist) AS ...
- ** The names of the columns in the table are taken from
- ** arglist which is stored in pTable->pCheck. The pCheck field
- ** normally holds CHECK constraints on an ordinary table, but for
- ** a VIEW it holds the list of column names.
- */
- sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
- &pTable->nCol, &pTable->aCol);
- if( db->mallocFailed==0
- && pParse->nErr==0
- && pTable->nCol==pSel->pEList->nExpr
- ){
- sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel);
- }
- }else if( pSelTab ){
- /* CREATE VIEW name AS... without an argument list. Construct
- ** the column names from the SELECT statement that defines the view.
- */
+ if( pSelTab ){
assert( pTable->aCol==0 );
pTable->nCol = pSelTab->nCol;
pTable->aCol = pSelTab->aCol;
pSelTab->nCol = 0;
pSelTab->aCol = 0;
+ sqlite3DeleteTable(db, pSelTab);
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
+ pTable->pSchema->schemaFlags |= DB_UnresetViews;
}else{
pTable->nCol = 0;
nErr++;
}
- sqlite3DeleteTable(db, pSelTab);
sqlite3SelectDelete(db, pSel);
- db->lookaside.bDisable--;
} else {
nErr++;
}
- pTable->pSchema->schemaFlags |= DB_UnresetViews;
#endif /* SQLITE_OMIT_VIEW */
return nErr;
}
@@ -99061,7 +93004,7 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){
for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){
Table *pTab = sqliteHashData(i);
if( pTab->pSelect ){
- sqlite3DeleteColumnNames(db, pTab);
+ sqliteDeleteColumnNames(db, pTab);
pTab->aCol = 0;
pTab->nCol = 0;
}
@@ -99123,7 +93066,6 @@ SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iT
static void destroyRootPage(Parse *pParse, int iTable, int iDb){
Vdbe *v = sqlite3GetVdbe(pParse);
int r1 = sqlite3GetTempReg(pParse);
- assert( iTable>1 );
sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb);
sqlite3MayAbort(pParse);
#ifndef SQLITE_OMIT_AUTOVACUUM
@@ -99509,7 +93451,7 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey(
pFKey->zTo, (void *)pFKey
);
if( pNextTo==pFKey ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
goto fk_end;
}
if( pNextTo ){
@@ -99591,7 +93533,6 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
tnum = pIndex->tnum;
}
pKey = sqlite3KeyInfoOfIndex(pParse, pIndex);
- assert( pKey!=0 || db->mallocFailed || pParse->nErr );
/* Open the sorter cursor if we are to use one. */
iSorter = pParse->nTab++;
@@ -99615,9 +93556,10 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v);
- if( IsUniqueIndex(pIndex) ){
+ assert( pKey!=0 || db->mallocFailed || pParse->nErr );
+ if( IsUniqueIndex(pIndex) && pKey!=0 ){
int j2 = sqlite3VdbeCurrentAddr(v) + 3;
- sqlite3VdbeGoto(v, j2);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
addr2 = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord,
pIndex->nKeyCol); VdbeCoverage(v);
@@ -99662,7 +93604,7 @@ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(
p = sqlite3DbMallocZero(db, nByte + nExtra);
if( p ){
char *pExtra = ((char*)p)+ROUND8(sizeof(Index));
- p->azColl = (const char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol);
+ p->azColl = (char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol);
p->aiRowLogEst = (LogEst*)pExtra; pExtra += sizeof(LogEst)*(nCol+1);
p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol;
p->aSortOrder = (u8*)pExtra;
@@ -99714,6 +93656,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
int iDb; /* Index of the database that is being written */
Token *pName = 0; /* Unqualified name of the index to create */
struct ExprList_item *pListItem; /* For looping over pList */
+ const Column *pTabCol; /* A column in the table */
int nExtra = 0; /* Space allocated for zExtra[] */
int nExtraCol; /* Number of extra columns needed */
char *zExtra = 0; /* Extra space after the Index object */
@@ -99868,15 +93811,11 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
** So create a fake list to simulate this.
*/
if( pList==0 ){
- Token prevCol;
- sqlite3TokenInit(&prevCol, pTab->aCol[pTab->nCol-1].zName);
- pList = sqlite3ExprListAppend(pParse, 0,
- sqlite3ExprAlloc(db, TK_ID, &prevCol, 0));
+ pList = sqlite3ExprListAppend(pParse, 0, 0);
if( pList==0 ) goto exit_create_index;
- assert( pList->nExpr==1 );
- sqlite3ExprListSetSortOrder(pList, sortOrder);
- }else{
- sqlite3ExprListCheckLength(pParse, pList, "index");
+ pList->a[0].zName = sqlite3DbStrDup(pParse->db,
+ pTab->aCol[pTab->nCol-1].zName);
+ pList->a[0].sortOrder = (u8)sortOrder;
}
/* Figure out how many bytes of space are required to store explicitly
@@ -99884,8 +93823,8 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
*/
for(i=0; i<pList->nExpr; i++){
Expr *pExpr = pList->a[i].pExpr;
- assert( pExpr!=0 );
- if( pExpr->op==TK_COLLATE ){
+ if( pExpr ){
+ assert( pExpr->op==TK_COLLATE );
nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken));
}
}
@@ -99926,54 +93865,35 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
sortOrderMask = 0; /* Ignore DESC */
}
- /* Analyze the list of expressions that form the terms of the index and
- ** report any errors. In the common case where the expression is exactly
- ** a table column, store that column in aiColumn[]. For general expressions,
- ** populate pIndex->aColExpr and store XN_EXPR (-2) in aiColumn[].
+ /* Scan the names of the columns of the table to be indexed and
+ ** load the column indices into the Index structure. Report an error
+ ** if any column is not found.
**
- ** TODO: Issue a warning if two or more columns of the index are identical.
- ** TODO: Issue a warning if the table primary key is used as part of the
- ** index key.
+ ** TODO: Add a test to make sure that the same column is not named
+ ** more than once within the same index. Only the first instance of
+ ** the column will ever be used by the optimizer. Note that using the
+ ** same column more than once cannot be an error because that would
+ ** break backwards compatibility - it needs to be a warning.
*/
for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
- Expr *pCExpr; /* The i-th index expression */
- int requestedSortOrder; /* ASC or DESC on the i-th expression */
- const char *zColl; /* Collation sequence name */
-
- sqlite3StringToId(pListItem->pExpr);
- sqlite3ResolveSelfReference(pParse, pTab, NC_IdxExpr, pListItem->pExpr, 0);
- if( pParse->nErr ) goto exit_create_index;
- pCExpr = sqlite3ExprSkipCollate(pListItem->pExpr);
- if( pCExpr->op!=TK_COLUMN ){
- if( pTab==pParse->pNewTable ){
- sqlite3ErrorMsg(pParse, "expressions prohibited in PRIMARY KEY and "
- "UNIQUE constraints");
- goto exit_create_index;
- }
- if( pIndex->aColExpr==0 ){
- ExprList *pCopy = sqlite3ExprListDup(db, pList, 0);
- pIndex->aColExpr = pCopy;
- if( !db->mallocFailed ){
- assert( pCopy!=0 );
- pListItem = &pCopy->a[i];
- }
- }
- j = XN_EXPR;
- pIndex->aiColumn[i] = XN_EXPR;
- pIndex->uniqNotNull = 0;
- }else{
- j = pCExpr->iColumn;
- assert( j<=0x7fff );
- if( j<0 ){
- j = pTab->iPKey;
- }else if( pTab->aCol[j].notNull==0 ){
- pIndex->uniqNotNull = 0;
- }
- pIndex->aiColumn[i] = (i16)j;
+ const char *zColName = pListItem->zName;
+ int requestedSortOrder;
+ char *zColl; /* Collation sequence name */
+
+ for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){
+ if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break;
}
- zColl = 0;
- if( pListItem->pExpr->op==TK_COLLATE ){
+ if( j>=pTab->nCol ){
+ sqlite3ErrorMsg(pParse, "table %s has no column named %s",
+ pTab->zName, zColName);
+ pParse->checkSchema = 1;
+ goto exit_create_index;
+ }
+ assert( j<=0x7fff );
+ pIndex->aiColumn[i] = (i16)j;
+ if( pListItem->pExpr ){
int nColl;
+ assert( pListItem->pExpr->op==TK_COLLATE );
zColl = pListItem->pExpr->u.zToken;
nColl = sqlite3Strlen30(zColl) + 1;
assert( nExtra>=nColl );
@@ -99981,26 +93901,21 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
zColl = zExtra;
zExtra += nColl;
nExtra -= nColl;
- }else if( j>=0 ){
+ }else{
zColl = pTab->aCol[j].zColl;
+ if( !zColl ) zColl = "BINARY";
}
- if( !zColl ) zColl = sqlite3StrBINARY;
if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){
goto exit_create_index;
}
pIndex->azColl[i] = zColl;
requestedSortOrder = pListItem->sortOrder & sortOrderMask;
pIndex->aSortOrder[i] = (u8)requestedSortOrder;
+ if( pTab->aCol[j].notNull==0 ) pIndex->uniqNotNull = 0;
}
-
- /* Append the table key to the end of the index. For WITHOUT ROWID
- ** tables (when pPk!=0) this will be the declared PRIMARY KEY. For
- ** normal tables (when pPk==0) this will be the rowid.
- */
if( pPk ){
for(j=0; j<pPk->nKeyCol; j++){
int x = pPk->aiColumn[j];
- assert( x>=0 );
if( hasColumn(pIndex->aiColumn, pIndex->nKeyCol, x) ){
pIndex->nColumn--;
}else{
@@ -100012,26 +93927,12 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
}
assert( i==pIndex->nColumn );
}else{
- pIndex->aiColumn[i] = XN_ROWID;
- pIndex->azColl[i] = sqlite3StrBINARY;
+ pIndex->aiColumn[i] = -1;
+ pIndex->azColl[i] = "BINARY";
}
sqlite3DefaultRowEst(pIndex);
if( pParse->pNewTable==0 ) estimateIndexWidth(pIndex);
- /* If this index contains every column of its table, then mark
- ** it as a covering index */
- assert( HasRowid(pTab)
- || pTab->iPKey<0 || sqlite3ColumnOfIndex(pIndex, pTab->iPKey)>=0 );
- if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){
- pIndex->isCovering = 1;
- for(j=0; j<pTab->nCol; j++){
- if( j==pTab->iPKey ) continue;
- if( sqlite3ColumnOfIndex(pIndex,j)>=0 ) continue;
- pIndex->isCovering = 0;
- break;
- }
- }
-
if( pTab==pParse->pNewTable ){
/* This routine has been called to create an automatic index as a
** result of a PRIMARY KEY or UNIQUE clause on a column definition, or
@@ -100065,11 +93966,10 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
for(k=0; k<pIdx->nKeyCol; k++){
const char *z1;
const char *z2;
- assert( pIdx->aiColumn[k]>=0 );
if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break;
z1 = pIdx->azColl[k];
z2 = pIndex->azColl[k];
- if( sqlite3StrICmp(z1, z2) ) break;
+ if( z1!=z2 && sqlite3StrICmp(z1, z2) ) break;
}
if( k==pIdx->nKeyCol ){
if( pIdx->onError!=pIndex->onError ){
@@ -100097,7 +93997,6 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
/* Link the new Index structure to its table and to the other
** in-memory database structures.
*/
- assert( pParse->nErr==0 );
if( db->init.busy ){
Index *p;
assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
@@ -100105,7 +94004,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
pIndex->zName, pIndex);
if( p ){
assert( p==pIndex ); /* Malloc must have failed */
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
goto exit_create_index;
}
db->flags |= SQLITE_InternChanges;
@@ -100127,7 +94026,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
** has just been created, it contains no data and the index initialization
** step can be skipped.
*/
- else if( HasRowid(pTab) || pTblName!=0 ){
+ else if( pParse->nErr==0 && (HasRowid(pTab) || pTblName!=0) ){
Vdbe *v;
char *zStmt;
int iMem = ++pParse->nMem;
@@ -100135,15 +94034,10 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto exit_create_index;
- sqlite3BeginWriteOperation(pParse, 1, iDb);
- /* Create the rootpage for the index using CreateIndex. But before
- ** doing so, code a Noop instruction and store its address in
- ** Index.tnum. This is required in case this index is actually a
- ** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In
- ** that case the convertToWithoutRowidTable() routine will replace
- ** the Noop with a Goto to jump over the VDBE code generated below. */
- pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop);
+ /* Create the rootpage for the index
+ */
+ sqlite3BeginWriteOperation(pParse, 1, iDb);
sqlite3VdbeAddOp2(v, OP_CreateIndex, iDb, iMem);
/* Gather the complete text of the CREATE INDEX statement into
@@ -100183,8 +94077,6 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
sqlite3VdbeAddOp1(v, OP_Expire, 0);
}
-
- sqlite3VdbeJumpHere(v, pIndex->tnum);
}
/* When adding an index to the list of indices for a table, make
@@ -100534,12 +94426,10 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(
){
struct SrcList_item *pItem;
assert( pDatabase==0 || pTable!=0 ); /* Cannot have C without B */
- assert( db!=0 );
if( pList==0 ){
- pList = sqlite3DbMallocRawNN(db, sizeof(SrcList) );
+ pList = sqlite3DbMallocZero(db, sizeof(SrcList) );
if( pList==0 ) return 0;
pList->nAlloc = 1;
- pList->nSrc = 0;
}
pList = sqlite3SrcListEnlarge(db, pList, 1, pList->nSrc);
if( db->mallocFailed ){
@@ -100589,8 +94479,7 @@ SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
sqlite3DbFree(db, pItem->zDatabase);
sqlite3DbFree(db, pItem->zName);
sqlite3DbFree(db, pItem->zAlias);
- if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy);
- if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
+ sqlite3DbFree(db, pItem->zIndex);
sqlite3DeleteTable(db, pItem->pTab);
sqlite3SelectDelete(db, pItem->pSelect);
sqlite3ExprDelete(db, pItem->pOn);
@@ -100663,38 +94552,18 @@ SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pI
assert( pIndexedBy!=0 );
if( p && ALWAYS(p->nSrc>0) ){
struct SrcList_item *pItem = &p->a[p->nSrc-1];
- assert( pItem->fg.notIndexed==0 );
- assert( pItem->fg.isIndexedBy==0 );
- assert( pItem->fg.isTabFunc==0 );
+ assert( pItem->notIndexed==0 && pItem->zIndex==0 );
if( pIndexedBy->n==1 && !pIndexedBy->z ){
/* A "NOT INDEXED" clause was supplied. See parse.y
** construct "indexed_opt" for details. */
- pItem->fg.notIndexed = 1;
+ pItem->notIndexed = 1;
}else{
- pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy);
- pItem->fg.isIndexedBy = (pItem->u1.zIndexedBy!=0);
+ pItem->zIndex = sqlite3NameFromToken(pParse->db, pIndexedBy);
}
}
}
/*
-** Add the list of function arguments to the SrcList entry for a
-** table-valued-function.
-*/
-SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *pList){
- if( p ){
- struct SrcList_item *pItem = &p->a[p->nSrc-1];
- assert( pItem->fg.notIndexed==0 );
- assert( pItem->fg.isIndexedBy==0 );
- assert( pItem->fg.isTabFunc==0 );
- pItem->u1.pFuncArg = pList;
- pItem->fg.isTabFunc = 1;
- }else{
- sqlite3ExprListDelete(pParse->db, pList);
- }
-}
-
-/*
** When building up a FROM clause in the parser, the join operator
** is initially attached to the left operand. But the code generator
** expects the join operator to be on the right operand. This routine
@@ -100713,14 +94582,14 @@ SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList *p){
if( p ){
int i;
for(i=p->nSrc-1; i>0; i--){
- p->a[i].fg.jointype = p->a[i-1].fg.jointype;
+ p->a[i].jointype = p->a[i-1].jointype;
}
- p->a[0].fg.jointype = 0;
+ p->a[0].jointype = 0;
}
}
/*
-** Generate VDBE code for a BEGIN statement.
+** Begin a transaction
*/
SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){
sqlite3 *db;
@@ -100730,6 +94599,7 @@ SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){
assert( pParse!=0 );
db = pParse->db;
assert( db!=0 );
+/* if( db->aDb[0].pBt==0 ) return; */
if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ){
return;
}
@@ -100741,11 +94611,11 @@ SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){
sqlite3VdbeUsesBtree(v, i);
}
}
- sqlite3VdbeAddOp0(v, OP_AutoCommit);
+ sqlite3VdbeAddOp2(v, OP_AutoCommit, 0, 0);
}
/*
-** Generate VDBE code for a COMMIT statement.
+** Commit a transaction
*/
SQLITE_PRIVATE void sqlite3CommitTransaction(Parse *pParse){
Vdbe *v;
@@ -100757,12 +94627,12 @@ SQLITE_PRIVATE void sqlite3CommitTransaction(Parse *pParse){
}
v = sqlite3GetVdbe(pParse);
if( v ){
- sqlite3VdbeAddOp1(v, OP_AutoCommit, 1);
+ sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, 0);
}
}
/*
-** Generate VDBE code for a ROLLBACK statement.
+** Rollback a transaction
*/
SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse *pParse){
Vdbe *v;
@@ -100824,7 +94694,7 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){
db->aDb[1].pBt = pBt;
assert( db->aDb[1].pSchema );
if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
return 1;
}
}
@@ -100941,7 +94811,7 @@ SQLITE_PRIVATE void sqlite3HaltConstraint(
sqlite3MayAbort(pParse);
}
sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type);
- sqlite3VdbeChangeP5(v, p5Errmsg);
+ if( p5Errmsg ) sqlite3VdbeChangeP5(v, p5Errmsg);
}
/*
@@ -100958,16 +94828,12 @@ SQLITE_PRIVATE void sqlite3UniqueConstraint(
Table *pTab = pIdx->pTable;
sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200);
- if( pIdx->aColExpr ){
- sqlite3XPrintf(&errMsg, "index '%q'", pIdx->zName);
- }else{
- for(j=0; j<pIdx->nKeyCol; j++){
- char *zCol;
- assert( pIdx->aiColumn[j]>=0 );
- zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
- if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2);
- sqlite3XPrintf(&errMsg, "%s.%s", pTab->zName, zCol);
- }
+ for(j=0; j<pIdx->nKeyCol; j++){
+ char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
+ if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2);
+ sqlite3StrAccumAppendAll(&errMsg, pTab->zName);
+ sqlite3StrAccumAppend(&errMsg, ".", 1);
+ sqlite3StrAccumAppendAll(&errMsg, zCol);
}
zErr = sqlite3StrAccumFinish(&errMsg);
sqlite3HaltConstraint(pParse,
@@ -101152,8 +95018,9 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
if( pKey ){
assert( sqlite3KeyInfoIsWriteable(pKey) );
for(i=0; i<nCol; i++){
- const char *zColl = pIdx->azColl[i];
- pKey->aColl[i] = zColl==sqlite3StrBINARY ? 0 :
+ char *zColl = pIdx->azColl[i];
+ assert( zColl!=0 );
+ pKey->aColl[i] = strcmp(zColl,"BINARY")==0 ? 0 :
sqlite3LocateCollSeq(pParse, zColl);
pKey->aSortOrder[i] = pIdx->aSortOrder[i];
}
@@ -101199,9 +95066,10 @@ SQLITE_PRIVATE With *sqlite3WithAdd(
}else{
pNew = sqlite3DbMallocZero(db, sizeof(*pWith));
}
- assert( (pNew!=0 && zName!=0) || db->mallocFailed );
+ assert( zName!=0 || pNew==0 );
+ assert( db->mallocFailed==0 || pNew==0 );
- if( db->mallocFailed ){
+ if( pNew==0 ){
sqlite3ExprListDelete(db, pArglist);
sqlite3SelectDelete(db, pQuery);
sqlite3DbFree(db, zName);
@@ -101210,7 +95078,7 @@ SQLITE_PRIVATE With *sqlite3WithAdd(
pNew->a[pNew->nCte].pSelect = pQuery;
pNew->a[pNew->nCte].pCols = pArglist;
pNew->a[pNew->nCte].zName = zName;
- pNew->a[pNew->nCte].zCteErr = 0;
+ pNew->a[pNew->nCte].zErr = 0;
pNew->nCte++;
}
@@ -101252,7 +95120,6 @@ SQLITE_PRIVATE void sqlite3WithDelete(sqlite3 *db, With *pWith){
** of user defined functions and collation sequences.
*/
-/* #include "sqliteInt.h" */
/*
** Invoke the 'collation needed' callback to request a collation sequence
@@ -101415,7 +95282,7 @@ static CollSeq *findCollSeqEntry(
*/
assert( pDel==0 || pDel==pColl );
if( pDel!=0 ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
sqlite3DbFree(db, pDel);
pColl = 0;
}
@@ -101481,8 +95348,8 @@ SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(
** 5: UTF16 byte order conversion required - argument count matches exactly
** 6: Perfect match: encoding and argument count match exactly.
**
-** If nArg==(-2) then any function with a non-null xSFunc is
-** a perfect match and any function with xSFunc NULL is
+** If nArg==(-2) then any function with a non-null xStep or xFunc is
+** a perfect match and any function with both xStep and xFunc NULL is
** a non-match.
*/
#define FUNC_PERFECT_MATCH 6 /* The score for a perfect match */
@@ -101494,7 +95361,7 @@ static int matchQuality(
int match;
/* nArg of -2 is a special case */
- if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH;
+ if( nArg==(-2) ) return (p->xFunc==0 && p->xStep==0) ? 0 : FUNC_PERFECT_MATCH;
/* Wrong number of arguments means "no match" */
if( p->nArg!=nArg && p->nArg>=0 ) return 0;
@@ -101522,12 +95389,14 @@ static int matchQuality(
** a pointer to the matching FuncDef if found, or 0 if there is no match.
*/
static FuncDef *functionSearch(
+ FuncDefHash *pHash, /* Hash table to search */
int h, /* Hash of the name */
- const char *zFunc /* Name of function */
+ const char *zFunc, /* Name of function */
+ int nFunc /* Number of bytes in zFunc */
){
FuncDef *p;
- for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){
- if( sqlite3StrICmp(p->zName, zFunc)==0 ){
+ for(p=pHash->a[h]; p; p=p->pHash){
+ if( sqlite3StrNICmp(p->zName, zFunc, nFunc)==0 && p->zName[nFunc]==0 ){
return p;
}
}
@@ -101537,26 +95406,23 @@ static FuncDef *functionSearch(
/*
** Insert a new FuncDef into a FuncDefHash hash table.
*/
-SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(
- FuncDef *aDef, /* List of global functions to be inserted */
- int nDef /* Length of the apDef[] list */
+SQLITE_PRIVATE void sqlite3FuncDefInsert(
+ FuncDefHash *pHash, /* The hash table into which to insert */
+ FuncDef *pDef /* The function definition to insert */
){
- int i;
- for(i=0; i<nDef; i++){
- FuncDef *pOther;
- const char *zName = aDef[i].zName;
- int nName = sqlite3Strlen30(zName);
- int h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
- pOther = functionSearch(h, zName);
- if( pOther ){
- assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] );
- aDef[i].pNext = pOther->pNext;
- pOther->pNext = &aDef[i];
- }else{
- aDef[i].pNext = 0;
- aDef[i].u.pHash = sqlite3BuiltinFunctions.a[h];
- sqlite3BuiltinFunctions.a[h] = &aDef[i];
- }
+ FuncDef *pOther;
+ int nName = sqlite3Strlen30(pDef->zName);
+ u8 c1 = (u8)pDef->zName[0];
+ int h = (sqlite3UpperToLower[c1] + nName) % ArraySize(pHash->a);
+ pOther = functionSearch(pHash, h, pDef->zName, nName);
+ if( pOther ){
+ assert( pOther!=pDef && pOther->pNext!=pDef );
+ pDef->pNext = pOther->pNext;
+ pOther->pNext = pDef;
+ }else{
+ pDef->pNext = 0;
+ pDef->pHash = pHash->a[h];
+ pHash->a[h] = pDef;
}
}
@@ -101573,7 +95439,7 @@ SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(
** no matching function previously existed.
**
** If nArg is -2, then the first valid function found is returned. A
-** function is valid if xSFunc is non-zero. The nArg==(-2)
+** function is valid if either xFunc or xStep is non-zero. The nArg==(-2)
** case is used to see if zName is a valid function name for some number
** of arguments. If nArg is -2, then createFlag must be 0.
**
@@ -101583,7 +95449,8 @@ SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(
*/
SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
sqlite3 *db, /* An open database */
- const char *zName, /* Name of the function. zero-terminated */
+ const char *zName, /* Name of the function. Not null-terminated */
+ int nName, /* Number of characters in the name */
int nArg, /* Number of arguments. -1 means any number */
u8 enc, /* Preferred text encoding */
u8 createFlag /* Create new entry if true and does not otherwise exist */
@@ -101592,15 +95459,14 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
FuncDef *pBest = 0; /* Best match found so far */
int bestScore = 0; /* Score of best match */
int h; /* Hash value */
- int nName; /* Length of the name */
assert( nArg>=(-2) );
assert( nArg>=(-1) || createFlag==0 );
- nName = sqlite3Strlen30(zName);
+ h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db->aFunc.a);
/* First search for a match amongst the application-defined functions.
*/
- p = (FuncDef*)sqlite3HashFind(&db->aFunc, zName);
+ p = functionSearch(&db->aFunc, h, zName, nName);
while( p ){
int score = matchQuality(p, nArg, enc);
if( score>bestScore ){
@@ -101623,9 +95489,9 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
** So we must not search for built-ins when creating a new function.
*/
if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){
+ FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
bestScore = 0;
- h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
- p = functionSearch(h, zName);
+ p = functionSearch(pHash, h, zName, nName);
while( p ){
int score = matchQuality(p, nArg, enc);
if( score>bestScore ){
@@ -101642,22 +95508,15 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
*/
if( createFlag && bestScore<FUNC_PERFECT_MATCH &&
(pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
- FuncDef *pOther;
- pBest->zName = (const char*)&pBest[1];
+ pBest->zName = (char *)&pBest[1];
pBest->nArg = (u16)nArg;
pBest->funcFlags = enc;
- memcpy((char*)&pBest[1], zName, nName+1);
- pOther = (FuncDef*)sqlite3HashInsert(&db->aFunc, pBest->zName, pBest);
- if( pOther==pBest ){
- sqlite3DbFree(db, pBest);
- sqlite3OomFault(db);
- return 0;
- }else{
- pBest->pNext = pOther;
- }
+ memcpy(pBest->zName, zName, nName);
+ pBest->zName[nName] = 0;
+ sqlite3FuncDefInsert(&db->aFunc, pBest);
}
- if( pBest && (pBest->xSFunc || createFlag) ){
+ if( pBest && (pBest->xStep || pBest->xFunc || createFlag) ){
return pBest;
}
return 0;
@@ -101711,7 +95570,7 @@ SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema));
}
if( !p ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
}else if ( 0==p->file_format ){
sqlite3HashInit(&p->tblHash);
sqlite3HashInit(&p->idxHash);
@@ -101738,7 +95597,6 @@ SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
** This file contains C code routines that are called by the parser
** in order to generate code for DELETE FROM statements.
*/
-/* #include "sqliteInt.h" */
/*
** While a SrcList can in general represent multiple tables and subqueries
@@ -101832,8 +95690,7 @@ SQLITE_PRIVATE void sqlite3MaterializeView(
assert( pFrom->a[0].pOn==0 );
assert( pFrom->a[0].pUsing==0 );
}
- pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0,
- SF_IncludeHidden, 0, 0);
+ pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0);
sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
sqlite3Select(pParse, pSel, &dest);
sqlite3SelectDelete(db, pSel);
@@ -101869,7 +95726,7 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
*/
if( pOrderBy && (pLimit == 0) ) {
sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
- goto limit_where_cleanup;
+ goto limit_where_cleanup_2;
}
/* We only need to generate a select expression if there
@@ -101891,16 +95748,16 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
*/
pSelectRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
- if( pSelectRowid == 0 ) goto limit_where_cleanup;
+ if( pSelectRowid == 0 ) goto limit_where_cleanup_2;
pEList = sqlite3ExprListAppend(pParse, 0, pSelectRowid);
- if( pEList == 0 ) goto limit_where_cleanup;
+ if( pEList == 0 ) goto limit_where_cleanup_2;
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
** and the SELECT subtree. */
pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
if( pSelectSrc == 0 ) {
sqlite3ExprListDelete(pParse->db, pEList);
- goto limit_where_cleanup;
+ goto limit_where_cleanup_2;
}
/* generate the SELECT expression tree. */
@@ -101910,11 +95767,21 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
/* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
pWhereRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
- pInClause = pWhereRowid ? sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0, 0) : 0;
- sqlite3PExprAddSelect(pParse, pInClause, pSelect);
+ if( pWhereRowid == 0 ) goto limit_where_cleanup_1;
+ pInClause = sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0, 0);
+ if( pInClause == 0 ) goto limit_where_cleanup_1;
+
+ pInClause->x.pSelect = pSelect;
+ pInClause->flags |= EP_xIsSelect;
+ sqlite3ExprSetHeightAndFlags(pParse, pInClause);
return pInClause;
-limit_where_cleanup:
+ /* something went wrong. clean up anything allocated. */
+limit_where_cleanup_1:
+ sqlite3SelectDelete(pParse->db, pSelect);
+ return 0;
+
+limit_where_cleanup_2:
sqlite3ExprDelete(pParse->db, pWhere);
sqlite3ExprListDelete(pParse->db, pOrderBy);
sqlite3ExprDelete(pParse->db, pLimit);
@@ -101952,7 +95819,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
int iDb; /* Database number */
int memCnt = -1; /* Memory cell used for change counting */
int rcauth; /* Value returned by authorization callback */
- int eOnePass; /* ONEPASS_OFF or _SINGLE or _MULTI */
+ int okOnePass; /* True for one-pass algorithm without the FIFO */
int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */
u8 *aToOpen = 0; /* Open cursor iTabCur+j if aToOpen[j] is true */
Index *pPk; /* The PRIMARY KEY index on the table */
@@ -101964,9 +95831,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
int iRowSet = 0; /* Register for rowset of rows to delete */
int addrBypass = 0; /* Address of jump over the delete logic */
int addrLoop = 0; /* Top of the delete loop */
+ int addrDelete = 0; /* Jump directly to the delete logic */
int addrEphOpen = 0; /* Instruction to open the Ephemeral table */
- int bComplex; /* True if there are triggers or FKs or
- ** subqueries in the WHERE clause */
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to delete from a view */
@@ -101994,7 +95860,6 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
#ifndef SQLITE_OMIT_TRIGGER
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
isView = pTab->pSelect!=0;
- bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0);
#else
# define pTrigger 0
# define isView 0
@@ -102078,13 +95943,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
** It is easier just to erase the whole table. Prior to version 3.6.5,
** this optimization caused the row change count (the value returned by
** API function sqlite3_count_changes) to be set incorrectly. */
- if( rcauth==SQLITE_OK
- && pWhere==0
- && !bComplex
- && !IsVirtual(pTab)
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
- && db->xPreUpdateCallback==0
-#endif
+ if( rcauth==SQLITE_OK && pWhere==0 && !pTrigger && !IsVirtual(pTab)
+ && 0==sqlite3FkRequired(pParse, pTab, 0, 0)
){
assert( !isView );
sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
@@ -102099,9 +95959,6 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
}else
#endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
{
- u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK|WHERE_SEEK_TABLE;
- if( sNC.ncFlags & NC_VarSelect ) bComplex = 1;
- wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW);
if( HasRowid(pTab) ){
/* For a rowid table, initialize the RowSet to an empty set */
pPk = 0;
@@ -102122,18 +95979,13 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
}
/* Construct a query to find the rowid or primary key for every row
- ** to be deleted, based on the WHERE clause. Set variable eOnePass
- ** to indicate the strategy used to implement this delete:
- **
- ** ONEPASS_OFF: Two-pass approach - use a FIFO for rowids/PK values.
- ** ONEPASS_SINGLE: One-pass approach - at most one row deleted.
- ** ONEPASS_MULTI: One-pass approach - any number of rows may be deleted.
+ ** to be deleted, based on the WHERE clause.
*/
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, wcf, iTabCur+1);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0,
+ WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK,
+ iTabCur+1);
if( pWInfo==0 ) goto delete_from_cleanup;
- eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
- assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI );
- assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF );
+ okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
/* Keep track of the number of rows to be deleted */
if( db->flags & SQLITE_CountRows ){
@@ -102143,7 +95995,6 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
/* Extract the rowid or primary key for the current row */
if( pPk ){
for(i=0; i<nPk; i++){
- assert( pPk->aiColumn[i]>=0 );
sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur,
pPk->aiColumn[i], iPk+i);
}
@@ -102154,12 +96005,13 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
if( iKey>pParse->nMem ) pParse->nMem = iKey;
}
- if( eOnePass!=ONEPASS_OFF ){
- /* For ONEPASS, no need to store the rowid/primary-key. There is only
+ if( okOnePass ){
+ /* For ONEPASS, no need to store the rowid/primary-key. There is only
** one, so just keep it in its register(s) and fall through to the
- ** delete code. */
+ ** delete code.
+ */
nKey = nPk; /* OP_Found will use an unpacked key */
- aToOpen = sqlite3DbMallocRawNN(db, nIdx+2);
+ aToOpen = sqlite3DbMallocRaw(db, nIdx+2);
if( aToOpen==0 ){
sqlite3WhereEnd(pWInfo);
goto delete_from_cleanup;
@@ -102169,27 +96021,27 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iTabCur] = 0;
if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iTabCur] = 0;
if( addrEphOpen ) sqlite3VdbeChangeToNoop(v, addrEphOpen);
+ addrDelete = sqlite3VdbeAddOp0(v, OP_Goto); /* Jump to DELETE logic */
+ }else if( pPk ){
+ /* Construct a composite key for the row to be deleted and remember it */
+ iKey = ++pParse->nMem;
+ nKey = 0; /* Zero tells OP_Found to use a composite key */
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
+ sqlite3IndexAffinityStr(v, pPk), nPk);
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, iEphCur, iKey);
}else{
- if( pPk ){
- /* Add the PK key for this row to the temporary table */
- iKey = ++pParse->nMem;
- nKey = 0; /* Zero tells OP_Found to use a composite key */
- sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
- sqlite3IndexAffinityStr(pParse->db, pPk), nPk);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iEphCur, iKey);
- }else{
- /* Add the rowid of the row to be deleted to the RowSet */
- nKey = 1; /* OP_Seek always uses a single rowid */
- sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey);
- }
+ /* Get the rowid of the row to be deleted and remember it in the RowSet */
+ nKey = 1; /* OP_Seek always uses a single rowid */
+ sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey);
}
- /* If this DELETE cannot use the ONEPASS strategy, this is the
- ** end of the WHERE loop */
- if( eOnePass!=ONEPASS_OFF ){
+ /* End of the WHERE loop */
+ sqlite3WhereEnd(pWInfo);
+ if( okOnePass ){
+ /* Bypass the delete logic below if the WHERE loop found zero rows */
addrBypass = sqlite3VdbeMakeLabel(v);
- }else{
- sqlite3WhereEnd(pWInfo);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrBypass);
+ sqlite3VdbeJumpHere(v, addrDelete);
}
/* Unless this is a view, open cursors for the table we are
@@ -102198,24 +96050,21 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
** triggers.
*/
if( !isView ){
- int iAddrOnce = 0;
- if( eOnePass==ONEPASS_MULTI ){
- iAddrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
- }
testcase( IsVirtual(pTab) );
- sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, OPFLAG_FORDELETE,
- iTabCur, aToOpen, &iDataCur, &iIdxCur);
+ sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iTabCur, aToOpen,
+ &iDataCur, &iIdxCur);
assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur );
assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 );
- if( eOnePass==ONEPASS_MULTI ) sqlite3VdbeJumpHere(v, iAddrOnce);
}
/* Set up a loop over the rowids/primary-keys that were found in the
** where-clause loop above.
*/
- if( eOnePass!=ONEPASS_OFF ){
+ if( okOnePass ){
+ /* Just one row. Hence the top-of-loop is a no-op */
assert( nKey==nPk ); /* OP_Found will use an unpacked key */
- if( !IsVirtual(pTab) && aToOpen[iDataCur-iTabCur] ){
+ assert( !IsVirtual(pTab) );
+ if( aToOpen[iDataCur-iTabCur] ){
assert( pPk!=0 || pTab->pSelect!=0 );
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey);
VdbeCoverage(v);
@@ -102237,32 +96086,23 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
sqlite3VtabMakeWritable(pParse, pTab);
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB);
sqlite3VdbeChangeP5(v, OE_Abort);
- assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE );
sqlite3MayAbort(pParse);
- if( eOnePass==ONEPASS_SINGLE && sqlite3IsToplevel(pParse) ){
- pParse->isMultiWrite = 0;
- }
}else
#endif
{
int count = (pParse->nested==0); /* True to count changes */
- int iIdxNoSeek = -1;
- if( bComplex==0 && aiCurOnePass[1]!=iDataCur ){
- iIdxNoSeek = aiCurOnePass[1];
- }
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
- iKey, nKey, count, OE_Default, eOnePass, iIdxNoSeek);
+ iKey, nKey, count, OE_Default, okOnePass);
}
/* End of the loop over all rowids/primary-keys. */
- if( eOnePass!=ONEPASS_OFF ){
+ if( okOnePass ){
sqlite3VdbeResolveLabel(v, addrBypass);
- sqlite3WhereEnd(pWInfo);
}else if( pPk ){
sqlite3VdbeAddOp2(v, OP_Next, iEphCur, addrLoop+1); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, addrLoop);
}else{
- sqlite3VdbeGoto(v, addrLoop);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrLoop);
sqlite3VdbeJumpHere(v, addrLoop);
}
@@ -102329,25 +96169,6 @@ delete_from_cleanup:
** sequence of nPk memory cells starting at iPk. If nPk==0 that means
** that a search record formed from OP_MakeRecord is contained in the
** single memory location iPk.
-**
-** eMode:
-** Parameter eMode may be passed either ONEPASS_OFF (0), ONEPASS_SINGLE, or
-** ONEPASS_MULTI. If eMode is not ONEPASS_OFF, then the cursor
-** iDataCur already points to the row to delete. If eMode is ONEPASS_OFF
-** then this function must seek iDataCur to the entry identified by iPk
-** and nPk before reading from it.
-**
-** If eMode is ONEPASS_MULTI, then this call is being made as part
-** of a ONEPASS delete that affects multiple rows. In this case, if
-** iIdxNoSeek is a valid cursor number (>=0), then its position should
-** be preserved following the delete operation. Or, if iIdxNoSeek is not
-** a valid cursor number, the position of iDataCur should be preserved
-** instead.
-**
-** iIdxNoSeek:
-** If iIdxNoSeek is a valid cursor number (>=0), then it identifies an
-** index cursor (from within array of cursors starting at iIdxCur) that
-** already points to the index entry to be deleted.
*/
SQLITE_PRIVATE void sqlite3GenerateRowDelete(
Parse *pParse, /* Parsing context */
@@ -102359,8 +96180,7 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
i16 nPk, /* Number of PRIMARY KEY memory cells */
u8 count, /* If non-zero, increment the row change counter */
u8 onconf, /* Default ON CONFLICT policy for triggers */
- u8 eMode, /* ONEPASS_OFF, _SINGLE, or _MULTI. See above */
- int iIdxNoSeek /* Cursor number of cursor that does not need seeking */
+ u8 bNoSeek /* iDataCur is already pointing to the row to delete */
){
Vdbe *v = pParse->pVdbe; /* Vdbe */
int iOld = 0; /* First register in OLD.* array */
@@ -102377,7 +96197,7 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
** not attempt to delete it or fire any DELETE triggers. */
iLabel = sqlite3VdbeMakeLabel(v);
opSeek = HasRowid(pTab) ? OP_NotExists : OP_NotFound;
- if( eMode==ONEPASS_OFF ){
+ if( !bNoSeek ){
sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk);
VdbeCoverageIf(v, opSeek==OP_NotExists);
VdbeCoverageIf(v, opSeek==OP_NotFound);
@@ -102435,27 +96255,13 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
/* Delete the index and table entries. Skip this step if pTab is really
** a view (in which case the only effect of the DELETE statement is to
- ** fire the INSTEAD OF triggers).
- **
- ** If variable 'count' is non-zero, then this OP_Delete instruction should
- ** invoke the update-hook. The pre-update-hook, on the other hand should
- ** be invoked unless table pTab is a system table. The difference is that
- ** the update-hook is not invoked for rows removed by REPLACE, but the
- ** pre-update-hook is.
- */
+ ** fire the INSTEAD OF triggers). */
if( pTab->pSelect==0 ){
- u8 p5 = 0;
- sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek);
+ sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, 0);
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
- sqlite3VdbeChangeP4(v, -1, (char*)pTab, P4_TABLE);
- if( eMode!=ONEPASS_OFF ){
- sqlite3VdbeChangeP5(v, OPFLAG_AUXDELETE);
+ if( count ){
+ sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
}
- if( iIdxNoSeek>=0 ){
- sqlite3VdbeAddOp1(v, OP_Delete, iIdxNoSeek);
- }
- if( eMode==ONEPASS_MULTI ) p5 |= OPFLAG_SAVEPOSITION;
- sqlite3VdbeChangeP5(v, p5);
}
/* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
@@ -102498,8 +96304,7 @@ SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(
Table *pTab, /* Table containing the row to be deleted */
int iDataCur, /* Cursor of table holding data. */
int iIdxCur, /* First index cursor */
- int *aRegIdx, /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
- int iIdxNoSeek /* Do not delete from this cursor */
+ int *aRegIdx /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
){
int i; /* Index loop counter */
int r1 = -1; /* Register holding an index key */
@@ -102515,12 +96320,11 @@ SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(
assert( iIdxCur+i!=iDataCur || pPk==pIdx );
if( aRegIdx!=0 && aRegIdx[i]==0 ) continue;
if( pIdx==pPk ) continue;
- if( iIdxCur+i==iIdxNoSeek ) continue;
VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName));
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1,
- &iPartIdxLabel, pPrior, r1);
+ &iPartIdxLabel, pPrior, r1);
sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
- pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
+ pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
pPrior = pIdx;
}
@@ -102569,16 +96373,17 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey(
){
Vdbe *v = pParse->pVdbe;
int j;
+ Table *pTab = pIdx->pTable;
int regBase;
int nCol;
if( piPartIdxLabel ){
if( pIdx->pPartIdxWhere ){
*piPartIdxLabel = sqlite3VdbeMakeLabel(v);
- pParse->iSelfTab = iDataCur;
+ pParse->iPartIdxTab = iDataCur;
sqlite3ExprCachePush(pParse);
- sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
- SQLITE_JUMPIFNULL);
+ sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
+ SQLITE_JUMPIFNULL);
}else{
*piPartIdxLabel = 0;
}
@@ -102587,14 +96392,9 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey(
regBase = sqlite3GetTempRange(pParse, nCol);
if( pPrior && (regBase!=regPrior || pPrior->pPartIdxWhere) ) pPrior = 0;
for(j=0; j<nCol; j++){
- if( pPrior
- && pPrior->aiColumn[j]==pIdx->aiColumn[j]
- && pPrior->aiColumn[j]!=XN_EXPR
- ){
- /* This column was already computed by the previous index */
- continue;
- }
- sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iDataCur, j, regBase+j);
+ if( pPrior && pPrior->aiColumn[j]==pIdx->aiColumn[j] ) continue;
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pIdx->aiColumn[j],
+ regBase+j);
/* If the column affinity is REAL but the number is an integer, then it
** might be stored in the table as an integer (using a compact
** representation) then converted to REAL by an OP_RealAffinity opcode.
@@ -102639,10 +96439,8 @@ SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){
** functions of SQLite. (Some function, and in particular the date and
** time functions, are implemented separately.)
*/
-/* #include "sqliteInt.h" */
/* #include <stdlib.h> */
/* #include <assert.h> */
-/* #include "vdbeInt.h" */
/*
** Return the collating function associated with a function.
@@ -102865,8 +96663,7 @@ static void printfFunc(
x.nUsed = 0;
x.apArg = argv+1;
sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);
- str.printfFlags = SQLITE_PRINTF_SQLFUNC;
- sqlite3XPrintf(&str, zFormat, &x);
+ sqlite3XPrintf(&str, SQLITE_PRINTF_SQLFUNC, zFormat, &x);
n = str.nChar;
sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n,
SQLITE_DYNAMIC);
@@ -103194,23 +96991,25 @@ static void total_changes(
** A structure defining how to do GLOB-style comparisons.
*/
struct compareInfo {
- u8 matchAll; /* "*" or "%" */
- u8 matchOne; /* "?" or "_" */
- u8 matchSet; /* "[" or 0 */
- u8 noCase; /* true to ignore case differences */
+ u8 matchAll;
+ u8 matchOne;
+ u8 matchSet;
+ u8 noCase;
};
/*
** For LIKE and GLOB matching on EBCDIC machines, assume that every
-** character is exactly one byte in size. Also, provde the Utf8Read()
-** macro for fast reading of the next character in the common case where
-** the next character is ASCII.
+** character is exactly one byte in size. Also, all characters are
+** able to participate in upper-case-to-lower-case mappings in EBCDIC
+** whereas only characters less than 0x80 do in ASCII.
*/
#if defined(SQLITE_EBCDIC)
# define sqlite3Utf8Read(A) (*((*A)++))
-# define Utf8Read(A) (*(A++))
+# define GlobUpperToLower(A) A = sqlite3UpperToLower[A]
+# define GlobUpperToLowerAscii(A) A = sqlite3UpperToLower[A]
#else
-# define Utf8Read(A) (A[0]<0x80?*(A++):sqlite3Utf8Read(&A))
+# define GlobUpperToLower(A) if( A<=0x7f ){ A = sqlite3UpperToLower[A]; }
+# define GlobUpperToLowerAscii(A) A = sqlite3UpperToLower[A]
#endif
static const struct compareInfo globInfo = { '*', '?', '[', 0 };
@@ -103252,7 +97051,7 @@ static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 };
** Ec Where E is the "esc" character and c is any other
** character, including '%', '_', and esc, match exactly c.
**
-** The comments within this routine usually assume glob matching.
+** The comments through this routine usually assume glob matching.
**
** This routine is usually quick, but can be N**2 in the worst case.
*/
@@ -103260,20 +97059,29 @@ static int patternCompare(
const u8 *zPattern, /* The glob pattern */
const u8 *zString, /* The string to compare against the glob */
const struct compareInfo *pInfo, /* Information about how to do the compare */
- u32 matchOther /* The escape char (LIKE) or '[' (GLOB) */
+ u32 esc /* The escape character */
){
u32 c, c2; /* Next pattern and input string chars */
u32 matchOne = pInfo->matchOne; /* "?" or "_" */
u32 matchAll = pInfo->matchAll; /* "*" or "%" */
+ u32 matchOther; /* "[" or the escape character */
u8 noCase = pInfo->noCase; /* True if uppercase==lowercase */
const u8 *zEscaped = 0; /* One past the last escaped input char */
- while( (c = Utf8Read(zPattern))!=0 ){
+ /* The GLOB operator does not have an ESCAPE clause. And LIKE does not
+ ** have the matchSet operator. So we either have to look for one or
+ ** the other, never both. Hence the single variable matchOther is used
+ ** to store the one we have to look for.
+ */
+ matchOther = esc ? esc : pInfo->matchSet;
+
+ while( (c = sqlite3Utf8Read(&zPattern))!=0 ){
if( c==matchAll ){ /* Match "*" */
/* Skip over multiple "*" characters in the pattern. If there
** are also "?" characters, skip those as well, but consume a
** single character of the input string for each "?" skipped */
- while( (c=Utf8Read(zPattern)) == matchAll || c == matchOne ){
+ while( (c=sqlite3Utf8Read(&zPattern)) == matchAll
+ || c == matchOne ){
if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){
return 0;
}
@@ -103281,7 +97089,7 @@ static int patternCompare(
if( c==0 ){
return 1; /* "*" at the end of the pattern matches */
}else if( c==matchOther ){
- if( pInfo->matchSet==0 ){
+ if( esc ){
c = sqlite3Utf8Read(&zPattern);
if( c==0 ) return 0;
}else{
@@ -103289,7 +97097,7 @@ static int patternCompare(
** recursive search in this case, but it is an unusual case. */
assert( matchOther<0x80 ); /* '[' is a single-byte character */
while( *zString
- && patternCompare(&zPattern[-1],zString,pInfo,matchOther)==0 ){
+ && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){
SQLITE_SKIP_UTF8(zString);
}
return *zString!=0;
@@ -103315,18 +97123,18 @@ static int patternCompare(
}
while( (c2 = *(zString++))!=0 ){
if( c2!=c && c2!=cx ) continue;
- if( patternCompare(zPattern,zString,pInfo,matchOther) ) return 1;
+ if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
}
}else{
- while( (c2 = Utf8Read(zString))!=0 ){
+ while( (c2 = sqlite3Utf8Read(&zString))!=0 ){
if( c2!=c ) continue;
- if( patternCompare(zPattern,zString,pInfo,matchOther) ) return 1;
+ if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
}
}
return 0;
}
if( c==matchOther ){
- if( pInfo->matchSet==0 ){
+ if( esc ){
c = sqlite3Utf8Read(&zPattern);
if( c==0 ) return 0;
zEscaped = zPattern;
@@ -103364,7 +97172,7 @@ static int patternCompare(
continue;
}
}
- c2 = Utf8Read(zString);
+ c2 = sqlite3Utf8Read(&zString);
if( c==c2 ) continue;
if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){
continue;
@@ -103379,14 +97187,7 @@ static int patternCompare(
** The sqlite3_strglob() interface.
*/
SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlobPattern, const char *zString){
- return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[')==0;
-}
-
-/*
-** The sqlite3_strlike() interface.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){
- return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc)==0;
+ return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, 0)==0;
}
/*
@@ -103417,22 +97218,10 @@ static void likeFunc(
sqlite3_value **argv
){
const unsigned char *zA, *zB;
- u32 escape;
+ u32 escape = 0;
int nPat;
sqlite3 *db = sqlite3_context_db_handle(context);
- struct compareInfo *pInfo = sqlite3_user_data(context);
-#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
- if( sqlite3_value_type(argv[0])==SQLITE_BLOB
- || sqlite3_value_type(argv[1])==SQLITE_BLOB
- ){
-#ifdef SQLITE_TEST
- sqlite3_like_count++;
-#endif
- sqlite3_result_int(context, 0);
- return;
- }
-#endif
zB = sqlite3_value_text(argv[0]);
zA = sqlite3_value_text(argv[1]);
@@ -103460,13 +97249,13 @@ static void likeFunc(
return;
}
escape = sqlite3Utf8Read(&zEsc);
- }else{
- escape = pInfo->matchSet;
}
if( zA && zB ){
+ struct compareInfo *pInfo = sqlite3_user_data(context);
#ifdef SQLITE_TEST
sqlite3_like_count++;
#endif
+
sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape));
}
}
@@ -103760,14 +97549,16 @@ static void zeroblobFunc(
sqlite3_value **argv
){
i64 n;
- int rc;
+ sqlite3 *db = sqlite3_context_db_handle(context);
assert( argc==1 );
UNUSED_PARAMETER(argc);
n = sqlite3_value_int64(argv[0]);
- if( n<0 ) n = 0;
- rc = sqlite3_result_zeroblob64(context, n); /* IMP: R-00293-64994 */
- if( rc ){
- sqlite3_result_error_code(context, rc);
+ testcase( n==db->aLimit[SQLITE_LIMIT_LENGTH] );
+ testcase( n==db->aLimit[SQLITE_LIMIT_LENGTH]+1 );
+ if( n>db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ sqlite3_result_error_toobig(context);
+ }else{
+ sqlite3_result_zeroblob(context, (int)n); /* IMP: R-00293-64994 */
}
}
@@ -104012,14 +97803,6 @@ static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){
sqlite3 *db = sqlite3_context_db_handle(context);
char *zErrMsg = 0;
- /* Disallow the load_extension() SQL function unless the SQLITE_LoadExtFunc
- ** flag is set. See the sqlite3_enable_load_extension() API.
- */
- if( (db->flags & SQLITE_LoadExtFunc)==0 ){
- sqlite3_result_error(context, "not authorized", -1);
- return;
- }
-
if( argc==2 ){
zProc = (const char *)sqlite3_value_text(argv[1]);
}else{
@@ -104245,11 +98028,11 @@ static void groupConcatFinalize(sqlite3_context *context){
** of the built-in functions above are part of the global function set.
** This routine only deals with those that are not global.
*/
-SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){
+SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
int rc = sqlite3_overload_function(db, "MATCH", 2);
assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
if( rc==SQLITE_NOMEM ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
}
}
@@ -104258,7 +98041,8 @@ SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){
*/
static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){
FuncDef *pDef;
- pDef = sqlite3FindFunction(db, zName, 2, SQLITE_UTF8, 0);
+ pDef = sqlite3FindFunction(db, zName, sqlite3Strlen30(zName),
+ 2, SQLITE_UTF8, 0);
if( ALWAYS(pDef) ){
pDef->funcFlags |= flagVal;
}
@@ -104306,7 +98090,9 @@ SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocas
return 0;
}
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
- pDef = sqlite3FindFunction(db, pExpr->u.zToken, 2, SQLITE_UTF8, 0);
+ pDef = sqlite3FindFunction(db, pExpr->u.zToken,
+ sqlite3Strlen30(pExpr->u.zToken),
+ 2, SQLITE_UTF8, 0);
if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){
return 0;
}
@@ -104330,7 +98116,7 @@ SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocas
**
** After this routine runs
*/
-SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
+SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
/*
** The following array holds FuncDef structures for all of the functions
** defined in this file.
@@ -104338,27 +98124,8 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
** The array cannot be constant since changes are made to the
** FuncDef.pHash elements at start-time. The elements of this array
** are read-only after initialization is complete.
- **
- ** For peak efficiency, put the most frequently used function last.
*/
- static FuncDef aBuiltinFunc[] = {
-#ifdef SQLITE_SOUNDEX
- FUNCTION(soundex, 1, 0, 0, soundexFunc ),
-#endif
-#ifndef SQLITE_OMIT_LOAD_EXTENSION
- VFUNCTION(load_extension, 1, 0, 0, loadExt ),
- VFUNCTION(load_extension, 2, 0, 0, loadExt ),
-#endif
-#if SQLITE_USER_AUTHENTICATION
- FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ),
-#endif
-#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
- DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
- DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
-#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
- FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
- FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
- FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
+ static SQLITE_WSD FuncDef aBuiltinFunc[] = {
FUNCTION(ltrim, 1, 1, 0, trimFunc ),
FUNCTION(ltrim, 2, 1, 0, trimFunc ),
FUNCTION(rtrim, 1, 2, 0, trimFunc ),
@@ -104376,6 +98143,8 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
FUNCTION(instr, 2, 0, 0, instrFunc ),
+ FUNCTION(substr, 2, 0, 0, substrFunc ),
+ FUNCTION(substr, 3, 0, 0, substrFunc ),
FUNCTION(printf, -1, 0, 0, printfFunc ),
FUNCTION(unicode, 1, 0, 0, unicodeFunc ),
FUNCTION(char, -1, 0, 0, charFunc ),
@@ -104386,22 +98155,40 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
#endif
FUNCTION(upper, 1, 0, 0, upperFunc ),
FUNCTION(lower, 1, 0, 0, lowerFunc ),
+ FUNCTION(coalesce, 1, 0, 0, 0 ),
+ FUNCTION(coalesce, 0, 0, 0, 0 ),
+ FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
FUNCTION(hex, 1, 0, 0, hexFunc ),
FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
+ FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
+ FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
+ FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
VFUNCTION(random, 0, 0, 0, randomFunc ),
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
- DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
- DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
+ FUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
+ FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ),
+#if SQLITE_USER_AUTHENTICATION
+ FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ),
+#endif
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+ FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
+ FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
+#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
FUNCTION(quote, 1, 0, 0, quoteFunc ),
VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
VFUNCTION(changes, 0, 0, 0, changes ),
VFUNCTION(total_changes, 0, 0, 0, total_changes ),
FUNCTION(replace, 3, 0, 0, replaceFunc ),
FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ),
- FUNCTION(substr, 2, 0, 0, substrFunc ),
- FUNCTION(substr, 3, 0, 0, substrFunc ),
+ #ifdef SQLITE_SOUNDEX
+ FUNCTION(soundex, 1, 0, 0, soundexFunc ),
+ #endif
+ #ifndef SQLITE_OMIT_LOAD_EXTENSION
+ FUNCTION(load_extension, 1, 0, 0, loadExt ),
+ FUNCTION(load_extension, 2, 0, 0, loadExt ),
+ #endif
AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ),
AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),
AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ),
@@ -104419,34 +98206,22 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE),
LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE),
#endif
- FUNCTION(coalesce, 1, 0, 0, 0 ),
- FUNCTION(coalesce, 0, 0, 0, 0 ),
- FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
};
+
+ int i;
+ FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
+ FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aBuiltinFunc);
+
+ for(i=0; i<ArraySize(aBuiltinFunc); i++){
+ sqlite3FuncDefInsert(pHash, &aFunc[i]);
+ }
+ sqlite3RegisterDateTimeFunctions();
#ifndef SQLITE_OMIT_ALTERTABLE
sqlite3AlterFunctions();
#endif
#if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4)
sqlite3AnalyzeFunctions();
#endif
- sqlite3RegisterDateTimeFunctions();
- sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc));
-
-#if 0 /* Enable to print out how the built-in functions are hashed */
- {
- int i;
- FuncDef *p;
- for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){
- printf("FUNC-HASH %02d:", i);
- for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash){
- int n = sqlite3Strlen30(p->zName);
- int h = p->zName[0] + n;
- printf(" %s(%d)", p->zName, h);
- }
- printf("\n");
- }
- }
-#endif
}
/************** End of func.c ************************************************/
@@ -104464,7 +98239,6 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
** This file contains code used by the compiler to add foreign key
** support to compiled SQL statements.
*/
-/* #include "sqliteInt.h" */
#ifndef SQLITE_OMIT_FOREIGN_KEY
#ifndef SQLITE_OMIT_TRIGGER
@@ -104672,7 +98446,7 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
}
}else if( paiCol ){
assert( nCol>1 );
- aiCol = (int *)sqlite3DbMallocRawNN(pParse->db, nCol*sizeof(int));
+ aiCol = (int *)sqlite3DbMallocRaw(pParse->db, nCol*sizeof(int));
if( !aiCol ) return 1;
*paiCol = aiCol;
}
@@ -104702,16 +98476,16 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
int i, j;
for(i=0; i<nCol; i++){
i16 iCol = pIdx->aiColumn[i]; /* Index of column in parent tbl */
- const char *zDfltColl; /* Def. collation for column */
+ char *zDfltColl; /* Def. collation for column */
char *zIdxCol; /* Name of indexed column */
- if( iCol<0 ) break; /* No foreign keys against expression indexes */
-
/* If the index uses a collation sequence that is different from
** the default collation sequence for the column, this index is
** unusable. Bail out early in this case. */
zDfltColl = pParent->aCol[iCol].zColl;
- if( !zDfltColl ) zDfltColl = sqlite3StrBINARY;
+ if( !zDfltColl ){
+ zDfltColl = "BINARY";
+ }
if( sqlite3StrICmp(pIdx->azColl[i], zDfltColl) ) break;
zIdxCol = pParent->aCol[iCol].zName;
@@ -104827,7 +98601,7 @@ static void fkLookupParent(
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regTemp); VdbeCoverage(v);
- sqlite3VdbeGoto(v, iOk);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, iOk);
sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
sqlite3VdbeJumpHere(v, iMustBeInt);
sqlite3ReleaseTempReg(pParse, regTemp);
@@ -104857,7 +98631,6 @@ static void fkLookupParent(
for(i=0; i<nCol; i++){
int iChild = aiCol[i]+1+regData;
int iParent = pIdx->aiColumn[i]+1+regData;
- assert( pIdx->aiColumn[i]>=0 );
assert( aiCol[i]!=pTab->iPKey );
if( pIdx->aiColumn[i]==pTab->iPKey ){
/* The parent key is a composite key that includes the IPK column */
@@ -104866,11 +98639,11 @@ static void fkLookupParent(
sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent); VdbeCoverage(v);
sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
}
- sqlite3VdbeGoto(v, iOk);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, iOk);
}
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTemp, nCol, regRec,
- sqlite3IndexAffinityStr(pParse->db,pIdx), nCol);
+ sqlite3IndexAffinityStr(v,pIdx), nCol);
sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regRec, 0); VdbeCoverage(v);
sqlite3ReleaseTempReg(pParse, regRec);
@@ -105066,7 +98839,6 @@ static void fkScanChildren(
assert( pIdx!=0 );
for(i=0; i<pPk->nKeyCol; i++){
i16 iCol = pIdx->aiColumn[i];
- assert( iCol>=0 );
pLeft = exprTableRegister(pParse, pTab, regData, iCol);
pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, iCol);
pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight, 0);
@@ -105386,7 +99158,6 @@ SQLITE_PRIVATE void sqlite3FkCheck(
if( aiCol[i]==pTab->iPKey ){
aiCol[i] = -1;
}
- assert( pIdx==0 || pIdx->aiColumn[i]>=0 );
#ifndef SQLITE_OMIT_AUTHORIZATION
/* Request permission to read the parent key columns. If the
** authorization callback returns SQLITE_IGNORE, behave as if any
@@ -105518,10 +99289,7 @@ SQLITE_PRIVATE u32 sqlite3FkOldmask(
Index *pIdx = 0;
sqlite3FkLocateIndex(pParse, pTab, p, &pIdx, 0);
if( pIdx ){
- for(i=0; i<pIdx->nKeyCol; i++){
- assert( pIdx->aiColumn[i]>=0 );
- mask |= COLUMN_MASK(pIdx->aiColumn[i]);
- }
+ for(i=0; i<pIdx->nKeyCol; i++) mask |= COLUMN_MASK(pIdx->aiColumn[i]);
}
}
}
@@ -105615,12 +99383,10 @@ static Trigger *fkActionTrigger(
int iAction = (pChanges!=0); /* 1 for UPDATE, 0 for DELETE */
action = pFKey->aAction[iAction];
- if( action==OE_Restrict && (db->flags & SQLITE_DeferFKs) ){
- return 0;
- }
pTrigger = pFKey->apTrigger[iAction];
if( action!=OE_None && !pTrigger ){
+ u8 enableLookaside; /* Copy of db->lookaside.bEnabled */
char const *zFrom; /* Name of child table */
int nFrom; /* Length in bytes of zFrom */
Index *pIdx = 0; /* Parent key index for this FK */
@@ -105646,10 +99412,11 @@ static Trigger *fkActionTrigger(
iFromCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom;
assert( iFromCol>=0 );
assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKey<pTab->nCol) );
- assert( pIdx==0 || pIdx->aiColumn[i]>=0 );
- sqlite3TokenInit(&tToCol,
- pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName);
- sqlite3TokenInit(&tFromCol, pFKey->pFrom->aCol[iFromCol].zName);
+ tToCol.z = pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName;
+ tFromCol.z = pFKey->pFrom->aCol[iFromCol].zName;
+
+ tToCol.n = sqlite3Strlen30(tToCol.z);
+ tFromCol.n = sqlite3Strlen30(tFromCol.z);
/* Create the expression "OLD.zToCol = zFromCol". It is important
** that the "OLD.zToCol" term is on the LHS of the = operator, so
@@ -105729,7 +99496,8 @@ static Trigger *fkActionTrigger(
}
/* Disable lookaside memory allocation */
- db->lookaside.bDisable++;
+ enableLookaside = db->lookaside.bEnabled;
+ db->lookaside.bEnabled = 0;
pTrigger = (Trigger *)sqlite3DbMallocZero(db,
sizeof(Trigger) + /* struct Trigger */
@@ -105751,7 +99519,7 @@ static Trigger *fkActionTrigger(
}
/* Re-enable the lookaside buffer, if it was disabled earlier. */
- db->lookaside.bDisable--;
+ db->lookaside.bEnabled = enableLookaside;
sqlite3ExprDelete(db, pWhere);
sqlite3ExprDelete(db, pWhen);
@@ -105875,7 +99643,6 @@ SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
*/
-/* #include "sqliteInt.h" */
/*
** Generate code that will
@@ -105905,7 +99672,7 @@ SQLITE_PRIVATE void sqlite3OpenTable(
}else{
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
assert( pPk!=0 );
- assert( pPk->tnum==pTab->tnum );
+ assert( pPk->tnum=pTab->tnum );
sqlite3VdbeAddOp3(v, opcode, iCur, pPk->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pPk);
VdbeComment((v, "%s", pTab->zName));
@@ -105919,7 +99686,7 @@ SQLITE_PRIVATE void sqlite3OpenTable(
**
** Character Column affinity
** ------------------------------
-** 'A' BLOB
+** 'A' NONE
** 'B' TEXT
** 'C' NUMERIC
** 'D' INTEGER
@@ -105932,7 +99699,7 @@ SQLITE_PRIVATE void sqlite3OpenTable(
** is managed along with the rest of the Index structure. It will be
** released when sqlite3DeleteIndex() is called.
*/
-SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
+SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
if( !pIdx->zColAff ){
/* The first time a column affinity string for a particular index is
** required, it is allocated and populated here. It is then stored as
@@ -105944,25 +99711,15 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
*/
int n;
Table *pTab = pIdx->pTable;
+ sqlite3 *db = sqlite3VdbeDb(v);
pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1);
if( !pIdx->zColAff ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
return 0;
}
for(n=0; n<pIdx->nColumn; n++){
i16 x = pIdx->aiColumn[n];
- if( x>=0 ){
- pIdx->zColAff[n] = pTab->aCol[x].affinity;
- }else if( x==XN_ROWID ){
- pIdx->zColAff[n] = SQLITE_AFF_INTEGER;
- }else{
- char aff;
- assert( x==XN_EXPR );
- assert( pIdx->aColExpr!=0 );
- aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
- if( aff==0 ) aff = SQLITE_AFF_BLOB;
- pIdx->zColAff[n] = aff;
- }
+ pIdx->zColAff[n] = x<0 ? SQLITE_AFF_INTEGER : pTab->aCol[x].affinity;
}
pIdx->zColAff[n] = 0;
}
@@ -105972,9 +99729,9 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
/*
** Compute the affinity string for table pTab, if it has not already been
-** computed. As an optimization, omit trailing SQLITE_AFF_BLOB affinities.
+** computed. As an optimization, omit trailing SQLITE_AFF_NONE affinities.
**
-** If the affinity exists (if it is no entirely SQLITE_AFF_BLOB values) and
+** If the affinity exists (if it is no entirely SQLITE_AFF_NONE values) and
** if iReg>0 then code an OP_Affinity opcode that will set the affinities
** for register iReg and following. Or if affinities exists and iReg==0,
** then just set the P4 operand of the previous opcode (which should be
@@ -105984,7 +99741,7 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
**
** Character Column affinity
** ------------------------------
-** 'A' BLOB
+** 'A' NONE
** 'B' TEXT
** 'C' NUMERIC
** 'D' INTEGER
@@ -105997,7 +99754,7 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
sqlite3 *db = sqlite3VdbeDb(v);
zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1);
if( !zColAff ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
return;
}
@@ -106006,7 +99763,7 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
}
do{
zColAff[i--] = 0;
- }while( i>=0 && zColAff[i]==SQLITE_AFF_BLOB );
+ }while( i>=0 && zColAff[i]==SQLITE_AFF_NONE );
pTab->zColAff = zColAff;
}
i = sqlite3Strlen30(zColAff);
@@ -106093,7 +99850,7 @@ static int autoIncBegin(
pInfo = pToplevel->pAinc;
while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
if( pInfo==0 ){
- pInfo = sqlite3DbMallocRawNN(pParse->db, sizeof(*pInfo));
+ pInfo = sqlite3DbMallocRaw(pParse->db, sizeof(*pInfo));
if( pInfo==0 ) return 0;
pInfo->pNext = pToplevel->pAinc;
pToplevel->pAinc = pInfo;
@@ -106117,55 +99874,43 @@ SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){
sqlite3 *db = pParse->db; /* The database connection */
Db *pDb; /* Database only autoinc table */
int memId; /* Register holding max rowid */
+ int addr; /* A VDBE address */
Vdbe *v = pParse->pVdbe; /* VDBE under construction */
/* This routine is never called during trigger-generation. It is
** only called from the top-level */
assert( pParse->pTriggerTab==0 );
- assert( sqlite3IsToplevel(pParse) );
+ assert( pParse==sqlite3ParseToplevel(pParse) );
assert( v ); /* We failed long ago if this is not so */
for(p = pParse->pAinc; p; p = p->pNext){
- static const int iLn = VDBE_OFFSET_LINENO(2);
- static const VdbeOpList autoInc[] = {
- /* 0 */ {OP_Null, 0, 0, 0},
- /* 1 */ {OP_Rewind, 0, 9, 0},
- /* 2 */ {OP_Column, 0, 0, 0},
- /* 3 */ {OP_Ne, 0, 7, 0},
- /* 4 */ {OP_Rowid, 0, 0, 0},
- /* 5 */ {OP_Column, 0, 1, 0},
- /* 6 */ {OP_Goto, 0, 9, 0},
- /* 7 */ {OP_Next, 0, 2, 0},
- /* 8 */ {OP_Integer, 0, 0, 0},
- /* 9 */ {OP_Close, 0, 0, 0}
- };
- VdbeOp *aOp;
pDb = &db->aDb[p->iDb];
memId = p->regCtr;
assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
- sqlite3VdbeLoadString(v, memId-1, p->pTab->zName);
- aOp = sqlite3VdbeAddOpList(v, ArraySize(autoInc), autoInc, iLn);
- if( aOp==0 ) break;
- aOp[0].p2 = memId;
- aOp[0].p3 = memId+1;
- aOp[2].p3 = memId;
- aOp[3].p1 = memId-1;
- aOp[3].p3 = memId;
- aOp[3].p5 = SQLITE_JUMPIFNULL;
- aOp[4].p2 = memId+1;
- aOp[5].p3 = memId;
- aOp[8].p2 = memId;
+ sqlite3VdbeAddOp3(v, OP_Null, 0, memId, memId+1);
+ addr = sqlite3VdbeCurrentAddr(v);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, p->pTab->zName, 0);
+ sqlite3VdbeAddOp2(v, OP_Rewind, 0, addr+9); VdbeCoverage(v);
+ sqlite3VdbeAddOp3(v, OP_Column, 0, 0, memId);
+ sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId); VdbeCoverage(v);
+ sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
+ sqlite3VdbeAddOp2(v, OP_Rowid, 0, memId+1);
+ sqlite3VdbeAddOp3(v, OP_Column, 0, 1, memId);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addr+9);
+ sqlite3VdbeAddOp2(v, OP_Next, 0, addr+2); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, memId);
+ sqlite3VdbeAddOp0(v, OP_Close);
}
}
/*
** Update the maximum rowid for an autoincrement calculation.
**
-** This routine should be called when the regRowid register holds a
+** This routine should be called when the top of the stack holds a
** new rowid that is about to be inserted. If that new rowid is
** larger than the maximum rowid in the memId memory cell, then the
-** memory cell is updated.
+** memory cell is updated. The stack is unchanged.
*/
static void autoIncStep(Parse *pParse, int memId, int regRowid){
if( memId>0 ){
@@ -106180,44 +99925,31 @@ static void autoIncStep(Parse *pParse, int memId, int regRowid){
** table (either directly or through triggers) needs to call this
** routine just before the "exit" code.
*/
-static SQLITE_NOINLINE void autoIncrementEnd(Parse *pParse){
+SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse){
AutoincInfo *p;
Vdbe *v = pParse->pVdbe;
sqlite3 *db = pParse->db;
assert( v );
for(p = pParse->pAinc; p; p = p->pNext){
- static const int iLn = VDBE_OFFSET_LINENO(2);
- static const VdbeOpList autoIncEnd[] = {
- /* 0 */ {OP_NotNull, 0, 2, 0},
- /* 1 */ {OP_NewRowid, 0, 0, 0},
- /* 2 */ {OP_MakeRecord, 0, 2, 0},
- /* 3 */ {OP_Insert, 0, 0, 0},
- /* 4 */ {OP_Close, 0, 0, 0}
- };
- VdbeOp *aOp;
Db *pDb = &db->aDb[p->iDb];
+ int j1;
int iRec;
int memId = p->regCtr;
iRec = sqlite3GetTempReg(pParse);
assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
- aOp = sqlite3VdbeAddOpList(v, ArraySize(autoIncEnd), autoIncEnd, iLn);
- if( aOp==0 ) break;
- aOp[0].p1 = memId+1;
- aOp[1].p2 = memId+1;
- aOp[2].p1 = memId-1;
- aOp[2].p3 = iRec;
- aOp[3].p2 = iRec;
- aOp[3].p3 = memId+1;
- aOp[3].p5 = OPFLAG_APPEND;
+ j1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_NewRowid, 0, memId+1);
+ sqlite3VdbeJumpHere(v, j1);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, iRec);
+ sqlite3VdbeAddOp3(v, OP_Insert, 0, iRec, memId+1);
+ sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
+ sqlite3VdbeAddOp0(v, OP_Close);
sqlite3ReleaseTempReg(pParse, iRec);
}
}
-SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse){
- if( pParse->pAinc ) autoIncrementEnd(pParse);
-}
#else
/*
** If SQLITE_OMIT_AUTOINCREMENT is defined, then the three routines
@@ -106548,7 +100280,7 @@ SQLITE_PRIVATE void sqlite3Insert(
rc = sqlite3Select(pParse, pSelect, &dest);
regFromSelect = dest.iSdst;
if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup;
- sqlite3VdbeEndCoroutine(v, regYield);
+ sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
assert( pSelect->pEList );
nColumn = pSelect->pEList->nExpr;
@@ -106589,7 +100321,7 @@ SQLITE_PRIVATE void sqlite3Insert(
sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec);
sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regTempRowid);
sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regTempRowid);
- sqlite3VdbeGoto(v, addrL);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrL);
sqlite3VdbeJumpHere(v, addrL);
sqlite3ReleaseTempReg(pParse, regRec);
sqlite3ReleaseTempReg(pParse, regTempRowid);
@@ -106603,13 +100335,11 @@ SQLITE_PRIVATE void sqlite3Insert(
sNC.pParse = pParse;
srcTab = -1;
assert( useTempTable==0 );
- if( pList ){
- nColumn = pList->nExpr;
- if( sqlite3ResolveExprListNames(&sNC, pList) ){
+ nColumn = pList ? pList->nExpr : 0;
+ for(i=0; i<nColumn; i++){
+ if( sqlite3ResolveExprNames(&sNC, pList->a[i].pExpr) ){
goto insert_cleanup;
}
- }else{
- nColumn = 0;
}
}
@@ -106624,8 +100354,10 @@ SQLITE_PRIVATE void sqlite3Insert(
/* Make sure the number of columns in the source data matches the number
** of columns to be inserted into the table.
*/
- for(i=0; i<pTab->nCol; i++){
- nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0);
+ if( IsVirtual(pTab) ){
+ for(i=0; i<pTab->nCol; i++){
+ nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0);
+ }
}
if( pColumn==0 && nColumn && nColumn!=(pTab->nCol-nHidden) ){
sqlite3ErrorMsg(pParse,
@@ -106648,9 +100380,9 @@ SQLITE_PRIVATE void sqlite3Insert(
/* If this is not a view, open the table and and all indices */
if( !isView ){
int nIdx;
- nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, -1, 0,
+ nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, -1, 0,
&iDataCur, &iIdxCur);
- aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+1));
+ aRegIdx = sqlite3DbMallocRaw(db, sizeof(int)*(nIdx+1));
if( aRegIdx==0 ){
goto insert_cleanup;
}
@@ -106700,7 +100432,7 @@ SQLITE_PRIVATE void sqlite3Insert(
if( ipkColumn<0 ){
sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols);
}else{
- int addr1;
+ int j1;
assert( !withoutRowid );
if( useTempTable ){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regCols);
@@ -106708,9 +100440,9 @@ SQLITE_PRIVATE void sqlite3Insert(
assert( pSelect==0 ); /* Otherwise useTempTable is true */
sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regCols);
}
- addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); VdbeCoverage(v);
+ j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols);
- sqlite3VdbeJumpHere(v, addr1);
+ sqlite3VdbeJumpHere(v, j1);
sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); VdbeCoverage(v);
}
@@ -106721,14 +100453,15 @@ SQLITE_PRIVATE void sqlite3Insert(
/* Create the new column data
*/
- for(i=j=0; i<pTab->nCol; i++){
- if( pColumn ){
+ for(i=0; i<pTab->nCol; i++){
+ if( pColumn==0 ){
+ j = i;
+ }else{
for(j=0; j<pColumn->nId; j++){
if( pColumn->a[j].idx==i ) break;
}
}
- if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId)
- || (pColumn==0 && IsOrdinaryHiddenColumn(&pTab->aCol[i])) ){
+ if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId) ){
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1);
}else if( useTempTable ){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1);
@@ -106736,7 +100469,6 @@ SQLITE_PRIVATE void sqlite3Insert(
assert( pSelect==0 ); /* Otherwise useTempTable is true */
sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i+1);
}
- if( pColumn==0 && !IsOrdinaryHiddenColumn(&pTab->aCol[i]) ) j++;
}
/* If this is an INSERT on a view with an INSTEAD OF INSERT trigger,
@@ -106784,14 +100516,14 @@ SQLITE_PRIVATE void sqlite3Insert(
** to generate a unique primary key value.
*/
if( !appendFlag ){
- int addr1;
+ int j1;
if( !IsVirtual(pTab) ){
- addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid); VdbeCoverage(v);
+ j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc);
- sqlite3VdbeJumpHere(v, addr1);
+ sqlite3VdbeJumpHere(v, j1);
}else{
- addr1 = sqlite3VdbeCurrentAddr(v);
- sqlite3VdbeAddOp2(v, OP_IsNull, regRowid, addr1+2); VdbeCoverage(v);
+ j1 = sqlite3VdbeCurrentAddr(v);
+ sqlite3VdbeAddOp2(v, OP_IsNull, regRowid, j1+2); VdbeCoverage(v);
}
sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid); VdbeCoverage(v);
}
@@ -106820,6 +100552,7 @@ SQLITE_PRIVATE void sqlite3Insert(
}
if( pColumn==0 ){
if( IsHiddenColumn(&pTab->aCol[i]) ){
+ assert( IsVirtual(pTab) );
j = -1;
nHidden++;
}else{
@@ -106858,7 +100591,7 @@ SQLITE_PRIVATE void sqlite3Insert(
{
int isReplace; /* Set to true if constraints may cause a replace */
sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
- regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0
+ regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace
);
sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur,
@@ -106887,7 +100620,7 @@ SQLITE_PRIVATE void sqlite3Insert(
sqlite3VdbeJumpHere(v, addrInsTop);
sqlite3VdbeAddOp1(v, OP_Close, srcTab);
}else if( pSelect ){
- sqlite3VdbeGoto(v, addrCont);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrCont);
sqlite3VdbeJumpHere(v, addrInsTop);
}
@@ -106941,59 +100674,6 @@ insert_cleanup:
#endif
/*
-** Meanings of bits in of pWalker->eCode for checkConstraintUnchanged()
-*/
-#define CKCNSTRNT_COLUMN 0x01 /* CHECK constraint uses a changing column */
-#define CKCNSTRNT_ROWID 0x02 /* CHECK constraint references the ROWID */
-
-/* This is the Walker callback from checkConstraintUnchanged(). Set
-** bit 0x01 of pWalker->eCode if
-** pWalker->eCode to 0 if this expression node references any of the
-** columns that are being modifed by an UPDATE statement.
-*/
-static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){
- if( pExpr->op==TK_COLUMN ){
- assert( pExpr->iColumn>=0 || pExpr->iColumn==-1 );
- if( pExpr->iColumn>=0 ){
- if( pWalker->u.aiCol[pExpr->iColumn]>=0 ){
- pWalker->eCode |= CKCNSTRNT_COLUMN;
- }
- }else{
- pWalker->eCode |= CKCNSTRNT_ROWID;
- }
- }
- return WRC_Continue;
-}
-
-/*
-** pExpr is a CHECK constraint on a row that is being UPDATE-ed. The
-** only columns that are modified by the UPDATE are those for which
-** aiChng[i]>=0, and also the ROWID is modified if chngRowid is true.
-**
-** Return true if CHECK constraint pExpr does not use any of the
-** changing columns (or the rowid if it is changing). In other words,
-** return true if this CHECK constraint can be skipped when validating
-** the new row in the UPDATE statement.
-*/
-static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){
- Walker w;
- memset(&w, 0, sizeof(w));
- w.eCode = 0;
- w.xExprCallback = checkConstraintExprNode;
- w.u.aiCol = aiChng;
- sqlite3WalkExpr(&w, pExpr);
- if( !chngRowid ){
- testcase( (w.eCode & CKCNSTRNT_ROWID)!=0 );
- w.eCode &= ~CKCNSTRNT_ROWID;
- }
- testcase( w.eCode==0 );
- testcase( w.eCode==CKCNSTRNT_COLUMN );
- testcase( w.eCode==CKCNSTRNT_ROWID );
- testcase( w.eCode==(CKCNSTRNT_ROWID|CKCNSTRNT_COLUMN) );
- return !w.eCode;
-}
-
-/*
** Generate code to do constraint checks prior to an INSERT or an UPDATE
** on table pTab.
**
@@ -107087,8 +100767,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
u8 pkChng, /* Non-zero if the rowid or PRIMARY KEY changed */
u8 overrideError, /* Override onError to this if not OE_Default */
int ignoreDest, /* Jump to this label on an OE_Ignore resolution */
- int *pbMayReplace, /* OUT: Set to true if constraint may cause a replace */
- int *aiChng /* column i is unchanged if aiChng[i]<0 */
+ int *pbMayReplace /* OUT: Set to true if constraint may cause a replace */
){
Vdbe *v; /* VDBE under constrution */
Index *pIdx; /* Pointer to one of the indices */
@@ -107098,7 +100777,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
int ix; /* Index loop counter */
int nCol; /* Number of columns */
int onError; /* Conflict resolution strategy */
- int addr1; /* Address of jump instruction */
+ int j1; /* Address of jump instruction */
int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
int ipkTop = 0; /* Top of the rowid change constraint check */
@@ -107134,14 +100813,10 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
*/
for(i=0; i<nCol; i++){
if( i==pTab->iPKey ){
- continue; /* ROWID is never NULL */
- }
- if( aiChng && aiChng[i]<0 ){
- /* Don't bother checking for NOT NULL on columns that do not change */
continue;
}
onError = pTab->aCol[i].notNull;
- if( onError==OE_None ) continue; /* This column is allowed to be NULL */
+ if( onError==OE_None ) continue;
if( overrideError!=OE_Default ){
onError = overrideError;
}else if( onError==OE_Default ){
@@ -107173,10 +100848,9 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
}
default: {
assert( onError==OE_Replace );
- addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regNewData+1+i);
- VdbeCoverage(v);
+ j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regNewData+1+i); VdbeCoverage(v);
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i);
- sqlite3VdbeJumpHere(v, addr1);
+ sqlite3VdbeJumpHere(v, j1);
break;
}
}
@@ -107190,13 +100864,10 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
pParse->ckBase = regNewData+1;
onError = overrideError!=OE_Default ? overrideError : OE_Abort;
for(i=0; i<pCheck->nExpr; i++){
- int allOk;
- Expr *pExpr = pCheck->a[i].pExpr;
- if( aiChng && checkConstraintUnchanged(pExpr, aiChng, pkChng) ) continue;
- allOk = sqlite3VdbeMakeLabel(v);
- sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL);
+ int allOk = sqlite3VdbeMakeLabel(v);
+ sqlite3ExprIfTrue(pParse, pCheck->a[i].pExpr, allOk, SQLITE_JUMPIFNULL);
if( onError==OE_Ignore ){
- sqlite3VdbeGoto(v, ignoreDest);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
}else{
char *zName = pCheck->a[i].zName;
if( zName==0 ) zName = pTab->zName;
@@ -107294,29 +100965,17 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
sqlite3MultiWrite(pParse);
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
- regNewData, 1, 0, OE_Replace, 1, -1);
- }else{
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
- if( HasRowid(pTab) ){
- /* This OP_Delete opcode fires the pre-update-hook only. It does
- ** not modify the b-tree. It is more efficient to let the coming
- ** OP_Insert replace the existing entry than it is to delete the
- ** existing entry and then insert a new one. */
- sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, OPFLAG_ISNOOP);
- sqlite3VdbeChangeP4(v, -1, (char *)pTab, P4_TABLE);
- }
-#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
- if( pTab->pIndex ){
- sqlite3MultiWrite(pParse);
- sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,-1);
- }
+ regNewData, 1, 0, OE_Replace, 1);
+ }else if( pTab->pIndex ){
+ sqlite3MultiWrite(pParse);
+ sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, 0);
}
seenReplace = 1;
break;
}
case OE_Ignore: {
/*assert( seenReplace==0 );*/
- sqlite3VdbeGoto(v, ignoreDest);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
break;
}
}
@@ -107352,8 +101011,8 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
if( pIdx->pPartIdxWhere ){
sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]);
pParse->ckBase = regNewData+1;
- sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
- SQLITE_JUMPIFNULL);
+ sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
+ SQLITE_JUMPIFNULL);
pParse->ckBase = 0;
}
@@ -107364,22 +101023,15 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
for(i=0; i<pIdx->nColumn; i++){
int iField = pIdx->aiColumn[i];
int x;
- if( iField==XN_EXPR ){
- pParse->ckBase = regNewData+1;
- sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i);
- pParse->ckBase = 0;
- VdbeComment((v, "%s column %d", pIdx->zName, i));
+ if( iField<0 || iField==pTab->iPKey ){
+ if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */
+ x = regNewData;
+ regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i;
}else{
- if( iField==XN_ROWID || iField==pTab->iPKey ){
- if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */
- x = regNewData;
- regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i;
- }else{
- x = iField + regNewData + 1;
- }
- sqlite3VdbeAddOp2(v, iField<0 ? OP_IntCopy : OP_SCopy, x, regIdx+i);
- VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName));
+ x = iField + regNewData + 1;
}
+ sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i);
+ VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName));
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
VdbeComment((v, "for %s", pIdx->zName));
@@ -107429,7 +101081,6 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
** store it in registers regR..regR+nPk-1 */
if( pIdx!=pPk ){
for(i=0; i<pPk->nKeyCol; i++){
- assert( pPk->aiColumn[i]>=0 );
x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
VdbeComment((v, "%s.%s", pTab->zName,
@@ -107451,7 +101102,6 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
for(i=0; i<pPk->nKeyCol; i++){
char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]);
x = pPk->aiColumn[i];
- assert( x>=0 );
if( i==(pPk->nKeyCol-1) ){
addrJump = addrUniqueOk;
op = OP_Eq;
@@ -107478,7 +101128,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
break;
}
case OE_Ignore: {
- sqlite3VdbeGoto(v, ignoreDest);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
break;
}
default: {
@@ -107489,8 +101139,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
}
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
- regR, nPkField, 0, OE_Replace,
- (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), -1);
+ regR, nPkField, 0, OE_Replace, pIdx==pPk);
seenReplace = 1;
break;
}
@@ -107500,7 +101149,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
}
if( ipkTop ){
- sqlite3VdbeGoto(v, ipkTop+1);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, ipkTop+1);
sqlite3VdbeJumpHere(v, ipkBottom);
}
@@ -107553,7 +101202,7 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
assert( pParse->nested==0 );
pik_flags |= OPFLAG_NCHANGE;
}
- sqlite3VdbeChangeP5(v, pik_flags);
+ if( pik_flags ) sqlite3VdbeChangeP5(v, pik_flags);
}
if( !HasRowid(pTab) ) return;
regData = regNewData + 1;
@@ -107575,7 +101224,7 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
}
sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, regRec, regNewData);
if( !pParse->nested ){
- sqlite3VdbeChangeP4(v, -1, (char *)pTab, P4_TABLE);
+ sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
}
sqlite3VdbeChangeP5(v, pik_flags);
}
@@ -107605,7 +101254,6 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
Parse *pParse, /* Parsing context */
Table *pTab, /* Table to be opened */
int op, /* OP_OpenRead or OP_OpenWrite */
- u8 p5, /* P5 value for OP_Open* opcodes (except on WITHOUT ROWID) */
int iBase, /* Use this for the table cursor, if there is one */
u8 *aToOpen, /* If not NULL: boolean for each table and index */
int *piDataCur, /* Write the database source cursor number here */
@@ -107618,7 +101266,6 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
Vdbe *v;
assert( op==OP_OpenRead || op==OP_OpenWrite );
- assert( op==OP_OpenWrite || p5==0 );
if( IsVirtual(pTab) ){
/* This routine is a no-op for virtual tables. Leave the output
** variables *piDataCur and *piIdxCur uninitialized so that valgrind
@@ -107640,16 +101287,14 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
int iIdxCur = iBase++;
assert( pIdx->pSchema==pTab->pSchema );
+ if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) && piDataCur ){
+ *piDataCur = iIdxCur;
+ }
if( aToOpen==0 || aToOpen[i+1] ){
sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
VdbeComment((v, "%s", pIdx->zName));
}
- if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
- if( piDataCur ) *piDataCur = iIdxCur;
- }else{
- sqlite3VdbeChangeP5(v, p5);
- }
}
if( iBase>pParse->nTab ) pParse->nTab = iBase;
return i;
@@ -107669,6 +101314,20 @@ SQLITE_API int sqlite3_xferopt_count;
#ifndef SQLITE_OMIT_XFER_OPT
/*
+** Check to collation names to see if they are compatible.
+*/
+static int xferCompatibleCollation(const char *z1, const char *z2){
+ if( z1==0 ){
+ return z2==0;
+ }
+ if( z2==0 ){
+ return 0;
+ }
+ return sqlite3StrICmp(z1, z2)==0;
+}
+
+
+/*
** Check to see if index pSrc is compatible as a source of data
** for index pDest in an insert transfer optimization. The rules
** for a compatible index:
@@ -107693,17 +101352,10 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){
return 0; /* Different columns indexed */
}
- if( pSrc->aiColumn[i]==XN_EXPR ){
- assert( pSrc->aColExpr!=0 && pDest->aColExpr!=0 );
- if( sqlite3ExprCompare(pSrc->aColExpr->a[i].pExpr,
- pDest->aColExpr->a[i].pExpr, -1)!=0 ){
- return 0; /* Different expressions in the index */
- }
- }
if( pSrc->aSortOrder[i]!=pDest->aSortOrder[i] ){
return 0; /* Different sort orders */
}
- if( sqlite3_stricmp(pSrc->azColl[i],pDest->azColl[i])!=0 ){
+ if( !xferCompatibleCollation(pSrc->azColl[i],pDest->azColl[i]) ){
return 0; /* Different collating sequences */
}
}
@@ -107818,7 +101470,7 @@ static int xferOptimization(
return 0; /* The result set must have exactly one column */
}
assert( pEList->a[0].pExpr );
- if( pEList->a[0].pExpr->op!=TK_ASTERISK ){
+ if( pEList->a[0].pExpr->op!=TK_ALL ){
return 0; /* The result set must be the special operator "*" */
}
@@ -107854,32 +101506,21 @@ static int xferOptimization(
for(i=0; i<pDest->nCol; i++){
Column *pDestCol = &pDest->aCol[i];
Column *pSrcCol = &pSrc->aCol[i];
-#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS
- if( (db->flags & SQLITE_Vacuum)==0
- && (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN
- ){
- return 0; /* Neither table may have __hidden__ columns */
- }
-#endif
if( pDestCol->affinity!=pSrcCol->affinity ){
return 0; /* Affinity must be the same on all columns */
}
- if( sqlite3_stricmp(pDestCol->zColl, pSrcCol->zColl)!=0 ){
+ if( !xferCompatibleCollation(pDestCol->zColl, pSrcCol->zColl) ){
return 0; /* Collating sequence must be the same on all columns */
}
if( pDestCol->notNull && !pSrcCol->notNull ){
return 0; /* tab2 must be NOT NULL if tab1 is */
}
/* Default values for second and subsequent columns need to match. */
- if( i>0 ){
- assert( pDestCol->pDflt==0 || pDestCol->pDflt->op==TK_SPAN );
- assert( pSrcCol->pDflt==0 || pSrcCol->pDflt->op==TK_SPAN );
- if( (pDestCol->pDflt==0)!=(pSrcCol->pDflt==0)
- || (pDestCol->pDflt && strcmp(pDestCol->pDflt->u.zToken,
- pSrcCol->pDflt->u.zToken)!=0)
- ){
- return 0; /* Default values must be the same for all columns */
- }
+ if( i>0
+ && ((pDestCol->zDflt==0)!=(pSrcCol->zDflt==0)
+ || (pDestCol->zDflt && strcmp(pDestCol->zDflt, pSrcCol->zDflt)!=0))
+ ){
+ return 0; /* Default values must be the same for all columns */
}
}
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
@@ -107954,7 +101595,7 @@ static int xferOptimization(
** (3) onError is something other than OE_Abort and OE_Rollback.
*/
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iDest, 0); VdbeCoverage(v);
- emptyDestTest = sqlite3VdbeAddOp0(v, OP_Goto);
+ emptyDestTest = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
sqlite3VdbeJumpHere(v, addr1);
}
if( HasRowid(pSrc) ){
@@ -107974,9 +101615,9 @@ static int xferOptimization(
assert( (pDest->tabFlags & TF_Autoincrement)==0 );
}
sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
- sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid,
- (char*)pDest, P4_TABLE);
+ sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid);
sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
+ sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
@@ -107985,7 +101626,7 @@ static int xferOptimization(
sqlite3TableLock(pParse, iDbSrc, pSrc->tnum, 0, pSrc->zName);
}
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
- u8 idxInsFlags = 0;
+ u8 useSeekResult = 0;
for(pSrcIdx=pSrc->pIndex; ALWAYS(pSrcIdx); pSrcIdx=pSrcIdx->pNext){
if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
}
@@ -108015,21 +101656,17 @@ static int xferOptimization(
** a VACUUM command. In that case keys may not be written in strictly
** sorted order. */
for(i=0; i<pSrcIdx->nColumn; i++){
- const char *zColl = pSrcIdx->azColl[i];
- assert( sqlite3_stricmp(sqlite3StrBINARY, zColl)!=0
- || sqlite3StrBINARY==zColl );
- if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break;
+ char *zColl = pSrcIdx->azColl[i];
+ assert( zColl!=0 );
+ if( sqlite3_stricmp("BINARY", zColl) ) break;
}
if( i==pSrcIdx->nColumn ){
- idxInsFlags = OPFLAG_USESEEKRESULT;
+ useSeekResult = OPFLAG_USESEEKRESULT;
sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
}
}
- if( !HasRowid(pSrc) && pDestIdx->idxType==2 ){
- idxInsFlags |= OPFLAG_NCHANGE;
- }
sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
- sqlite3VdbeChangeP5(v, idxInsFlags);
+ sqlite3VdbeChangeP5(v, useSeekResult);
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
@@ -108068,7 +101705,6 @@ static int xferOptimization(
** accessed by users of the library.
*/
-/* #include "sqliteInt.h" */
/*
** Execute SQL code. Return one of the SQLITE_ success/failure
@@ -108143,7 +101779,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
for(i=0; i<nCol; i++){
azVals[i] = (char *)sqlite3_column_text(pStmt, i);
if( !azVals[i] && sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
goto exec_out;
}
}
@@ -108184,7 +101820,7 @@ exec_out:
if( *pzErrMsg ){
memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg);
}else{
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
sqlite3Error(db, SQLITE_NOMEM);
}
}else if( pzErrMsg ){
@@ -108237,7 +101873,6 @@ exec_out:
*/
#ifndef _SQLITE3EXT_H_
#define _SQLITE3EXT_H_
-/* #include "sqlite3.h" */
typedef struct sqlite3_api_routines sqlite3_api_routines;
@@ -108487,20 +102122,6 @@ struct sqlite3_api_routines {
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
void(*)(void*), unsigned char);
int (*strglob)(const char*,const char*);
- /* Version 3.8.11 and later */
- sqlite3_value *(*value_dup)(const sqlite3_value*);
- void (*value_free)(sqlite3_value*);
- int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
- int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
- /* Version 3.9.0 and later */
- unsigned int (*value_subtype)(sqlite3_value*);
- void (*result_subtype)(sqlite3_context*,unsigned int);
- /* Version 3.10.0 and later */
- int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
- int (*strlike)(const char*,const char*,unsigned int);
- int (*db_cacheflush)(sqlite3*);
- /* Version 3.12.0 and later */
- int (*system_errno)(sqlite3*);
};
/*
@@ -108514,7 +102135,7 @@ struct sqlite3_api_routines {
** the API. So the redefinition macros are only valid if the
** SQLITE_CORE macros is undefined.
*/
-#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
+#ifndef SQLITE_CORE
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
@@ -108641,7 +102262,6 @@ struct sqlite3_api_routines {
#define sqlite3_value_text16le sqlite3_api->value_text16le
#define sqlite3_value_type sqlite3_api->value_type
#define sqlite3_vmprintf sqlite3_api->vmprintf
-#define sqlite3_vsnprintf sqlite3_api->vsnprintf
#define sqlite3_overload_function sqlite3_api->overload_function
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
@@ -108732,23 +102352,9 @@ struct sqlite3_api_routines {
#define sqlite3_result_blob64 sqlite3_api->result_blob64
#define sqlite3_result_text64 sqlite3_api->result_text64
#define sqlite3_strglob sqlite3_api->strglob
-/* Version 3.8.11 and later */
-#define sqlite3_value_dup sqlite3_api->value_dup
-#define sqlite3_value_free sqlite3_api->value_free
-#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
-#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
-/* Version 3.9.0 and later */
-#define sqlite3_value_subtype sqlite3_api->value_subtype
-#define sqlite3_result_subtype sqlite3_api->result_subtype
-/* Version 3.10.0 and later */
-#define sqlite3_status64 sqlite3_api->status64
-#define sqlite3_strlike sqlite3_api->strlike
-#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
-/* Version 3.12.0 and later */
-#define sqlite3_system_errno sqlite3_api->system_errno
-#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
-
-#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
+#endif /* SQLITE_CORE */
+
+#ifndef SQLITE_CORE
/* This case when the file really is being compiled as a loadable
** extension */
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
@@ -108767,7 +102373,6 @@ struct sqlite3_api_routines {
/************** End of sqlite3ext.h ******************************************/
/************** Continuing where we left off in loadext.c ********************/
-/* #include "sqliteInt.h" */
/* #include <string.h> */
#ifndef SQLITE_OMIT_LOAD_EXTENSION
@@ -109152,21 +102757,7 @@ static const sqlite3_api_routines sqlite3Apis = {
sqlite3_reset_auto_extension,
sqlite3_result_blob64,
sqlite3_result_text64,
- sqlite3_strglob,
- /* Version 3.8.11 and later */
- (sqlite3_value*(*)(const sqlite3_value*))sqlite3_value_dup,
- sqlite3_value_free,
- sqlite3_result_zeroblob64,
- sqlite3_bind_zeroblob64,
- /* Version 3.9.0 and later */
- sqlite3_value_subtype,
- sqlite3_result_subtype,
- /* Version 3.10.0 and later */
- sqlite3_status64,
- sqlite3_strlike,
- sqlite3_db_cacheflush,
- /* Version 3.12.0 and later */
- sqlite3_system_errno
+ sqlite3_strglob
};
/*
@@ -109214,9 +102805,8 @@ static int sqlite3LoadExtension(
/* Ticket #1863. To avoid a creating security problems for older
** applications that relink against newer versions of SQLite, the
** ability to run load_extension is turned off by default. One
- ** must call either sqlite3_enable_load_extension(db) or
- ** sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, 0)
- ** to turn on extension loading.
+ ** must call sqlite3_enable_load_extension() to turn on extension
+ ** loading. Otherwise you get the following error.
*/
if( (db->flags & SQLITE_LoadExtension)==0 ){
if( pzErrMsg ){
@@ -109231,7 +102821,7 @@ static int sqlite3LoadExtension(
#if SQLITE_OS_UNIX || SQLITE_OS_WIN
for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
char *zAltFile = sqlite3_mprintf("%s.%s", zFile, azEndings[ii]);
- if( zAltFile==0 ) return SQLITE_NOMEM_BKPT;
+ if( zAltFile==0 ) return SQLITE_NOMEM;
handle = sqlite3OsDlOpen(pVfs, zAltFile);
sqlite3_free(zAltFile);
}
@@ -109267,7 +102857,7 @@ static int sqlite3LoadExtension(
zAltEntry = sqlite3_malloc64(ncFile+30);
if( zAltEntry==0 ){
sqlite3OsDlClose(pVfs, handle);
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
memcpy(zAltEntry, "sqlite3_", 8);
for(iFile=ncFile-1; iFile>=0 && zFile[iFile]!='/'; iFile--){}
@@ -109310,7 +102900,7 @@ static int sqlite3LoadExtension(
/* Append the new shared library handle to the db->aExtension array. */
aHandle = sqlite3DbMallocZero(db, sizeof(handle)*(db->nExtension+1));
if( aHandle==0 ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
if( db->nExtension>0 ){
memcpy(aHandle, db->aExtension, sizeof(handle)*db->nExtension);
@@ -109355,9 +102945,9 @@ SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3 *db){
SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff){
sqlite3_mutex_enter(db->mutex);
if( onoff ){
- db->flags |= SQLITE_LoadExtension|SQLITE_LoadExtFunc;
+ db->flags |= SQLITE_LoadExtension;
}else{
- db->flags &= ~(SQLITE_LoadExtension|SQLITE_LoadExtFunc);
+ db->flags &= ~SQLITE_LoadExtension;
}
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
@@ -109432,7 +103022,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xInit)(void)){
void (**aNew)(void);
aNew = sqlite3_realloc64(wsdAutoext.aExt, nByte);
if( aNew==0 ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}else{
wsdAutoext.aExt = aNew;
wsdAutoext.aExt[wsdAutoext.nExt] = xInit;
@@ -109549,7 +103139,6 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
*************************************************************************
** This file contains code used to implement the PRAGMA command.
*/
-/* #include "sqliteInt.h" */
#if !defined(SQLITE_ENABLE_LOCKING_STYLE)
# if defined(__APPLE__)
@@ -109578,44 +103167,43 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
#define PragTyp_FLAG 2
#define PragTyp_BUSY_TIMEOUT 3
#define PragTyp_CACHE_SIZE 4
-#define PragTyp_CACHE_SPILL 5
-#define PragTyp_CASE_SENSITIVE_LIKE 6
-#define PragTyp_COLLATION_LIST 7
-#define PragTyp_COMPILE_OPTIONS 8
-#define PragTyp_DATA_STORE_DIRECTORY 9
-#define PragTyp_DATABASE_LIST 10
-#define PragTyp_DEFAULT_CACHE_SIZE 11
-#define PragTyp_ENCODING 12
-#define PragTyp_FOREIGN_KEY_CHECK 13
-#define PragTyp_FOREIGN_KEY_LIST 14
-#define PragTyp_INCREMENTAL_VACUUM 15
-#define PragTyp_INDEX_INFO 16
-#define PragTyp_INDEX_LIST 17
-#define PragTyp_INTEGRITY_CHECK 18
-#define PragTyp_JOURNAL_MODE 19
-#define PragTyp_JOURNAL_SIZE_LIMIT 20
-#define PragTyp_LOCK_PROXY_FILE 21
-#define PragTyp_LOCKING_MODE 22
-#define PragTyp_PAGE_COUNT 23
-#define PragTyp_MMAP_SIZE 24
-#define PragTyp_PAGE_SIZE 25
-#define PragTyp_SECURE_DELETE 26
-#define PragTyp_SHRINK_MEMORY 27
-#define PragTyp_SOFT_HEAP_LIMIT 28
-#define PragTyp_STATS 29
-#define PragTyp_SYNCHRONOUS 30
-#define PragTyp_TABLE_INFO 31
-#define PragTyp_TEMP_STORE 32
-#define PragTyp_TEMP_STORE_DIRECTORY 33
-#define PragTyp_THREADS 34
-#define PragTyp_WAL_AUTOCHECKPOINT 35
-#define PragTyp_WAL_CHECKPOINT 36
-#define PragTyp_ACTIVATE_EXTENSIONS 37
-#define PragTyp_HEXKEY 38
-#define PragTyp_KEY 39
-#define PragTyp_REKEY 40
-#define PragTyp_LOCK_STATUS 41
-#define PragTyp_PARSER_TRACE 42
+#define PragTyp_CASE_SENSITIVE_LIKE 5
+#define PragTyp_COLLATION_LIST 6
+#define PragTyp_COMPILE_OPTIONS 7
+#define PragTyp_DATA_STORE_DIRECTORY 8
+#define PragTyp_DATABASE_LIST 9
+#define PragTyp_DEFAULT_CACHE_SIZE 10
+#define PragTyp_ENCODING 11
+#define PragTyp_FOREIGN_KEY_CHECK 12
+#define PragTyp_FOREIGN_KEY_LIST 13
+#define PragTyp_INCREMENTAL_VACUUM 14
+#define PragTyp_INDEX_INFO 15
+#define PragTyp_INDEX_LIST 16
+#define PragTyp_INTEGRITY_CHECK 17
+#define PragTyp_JOURNAL_MODE 18
+#define PragTyp_JOURNAL_SIZE_LIMIT 19
+#define PragTyp_LOCK_PROXY_FILE 20
+#define PragTyp_LOCKING_MODE 21
+#define PragTyp_PAGE_COUNT 22
+#define PragTyp_MMAP_SIZE 23
+#define PragTyp_PAGE_SIZE 24
+#define PragTyp_SECURE_DELETE 25
+#define PragTyp_SHRINK_MEMORY 26
+#define PragTyp_SOFT_HEAP_LIMIT 27
+#define PragTyp_STATS 28
+#define PragTyp_SYNCHRONOUS 29
+#define PragTyp_TABLE_INFO 30
+#define PragTyp_TEMP_STORE 31
+#define PragTyp_TEMP_STORE_DIRECTORY 32
+#define PragTyp_THREADS 33
+#define PragTyp_WAL_AUTOCHECKPOINT 34
+#define PragTyp_WAL_CHECKPOINT 35
+#define PragTyp_ACTIVATE_EXTENSIONS 36
+#define PragTyp_HEXKEY 37
+#define PragTyp_KEY 38
+#define PragTyp_REKEY 39
+#define PragTyp_LOCK_STATUS 40
+#define PragTyp_PARSER_TRACE 41
#define PragFlag_NeedSchema 0x01
#define PragFlag_ReadOnly 0x02
static const struct sPragmaNames {
@@ -109662,18 +103250,14 @@ static const struct sPragmaNames {
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
{ /* zName: */ "cache_spill",
- /* ePragTyp: */ PragTyp_CACHE_SPILL,
+ /* ePragTyp: */ PragTyp_FLAG,
/* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ /* iArg: */ SQLITE_CacheSpill },
#endif
{ /* zName: */ "case_sensitive_like",
/* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE,
/* ePragFlag: */ 0,
/* iArg: */ 0 },
- { /* zName: */ "cell_size_check",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_CellSizeCk },
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
{ /* zName: */ "checkpoint_fullfsync",
/* ePragTyp: */ PragTyp_FLAG,
@@ -109878,7 +103462,7 @@ static const struct sPragmaNames {
/* ePragFlag: */ 0,
/* iArg: */ 0 },
#endif
-#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_PARSER_TRACE)
+#if defined(SQLITE_DEBUG)
{ /* zName: */ "parser_trace",
/* ePragTyp: */ PragTyp_PARSER_TRACE,
/* ePragFlag: */ 0,
@@ -110031,15 +103615,15 @@ static const struct sPragmaNames {
/* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
#endif
};
-/* Number of pragmas: 60 on by default, 73 total. */
+/* Number of pragmas: 59 on by default, 72 total. */
/************** End of pragma.h **********************************************/
/************** Continuing where we left off in pragma.c *********************/
/*
** Interpret the given string as a safety level. Return 0 for OFF,
-** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA. Return 1 for an empty or
-** unrecognized string argument. The FULL and EXTRA option is disallowed
+** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or
+** unrecognized string argument. The FULL option is disallowed
** if the omitFull parameter it 1.
**
** Note that the values returned are one less that the values that
@@ -110048,21 +103632,18 @@ static const struct sPragmaNames {
** and older scripts may have used numbers 0 for OFF and 1 for ON.
*/
static u8 getSafetyLevel(const char *z, int omitFull, u8 dflt){
- /* 123456789 123456789 123 */
- static const char zText[] = "onoffalseyestruextrafull";
- static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 15, 20};
- static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 5, 4};
- static const u8 iValue[] = {1, 0, 0, 0, 1, 1, 3, 2};
- /* on no off false yes true extra full */
+ /* 123456789 123456789 */
+ static const char zText[] = "onoffalseyestruefull";
+ static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16};
+ static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 4};
+ static const u8 iValue[] = {1, 0, 0, 0, 1, 1, 2};
int i, n;
if( sqlite3Isdigit(*z) ){
return (u8)sqlite3Atoi(z);
}
n = sqlite3Strlen30(z);
- for(i=0; i<ArraySize(iLength); i++){
- if( iLength[i]==n && sqlite3StrNICmp(&zText[iOffset[i]],z,n)==0
- && (!omitFull || iValue[i]<=1)
- ){
+ for(i=0; i<ArraySize(iLength)-omitFull; i++){
+ if( iLength[i]==n && sqlite3StrNICmp(&zText[iOffset[i]],z,n)==0 ){
return iValue[i];
}
}
@@ -110169,45 +103750,19 @@ static int changeTempStorage(Parse *pParse, const char *zStorageType){
#endif /* SQLITE_PAGER_PRAGMAS */
/*
-** Set the names of the first N columns to the values in azCol[]
-*/
-static void setAllColumnNames(
- Vdbe *v, /* The query under construction */
- int N, /* Number of columns */
- const char **azCol /* Names of columns */
-){
- int i;
- sqlite3VdbeSetNumCols(v, N);
- for(i=0; i<N; i++){
- sqlite3VdbeSetColName(v, i, COLNAME_NAME, azCol[i], SQLITE_STATIC);
- }
-}
-static void setOneColumnName(Vdbe *v, const char *z){
- setAllColumnNames(v, 1, &z);
-}
-
-/*
** Generate code to return a single integer value.
*/
-static void returnSingleInt(Vdbe *v, const char *zLabel, i64 value){
- sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, 1, 0, (const u8*)&value, P4_INT64);
- setOneColumnName(v, zLabel);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
-}
-
-/*
-** Generate code to return a single text value.
-*/
-static void returnSingleText(
- Vdbe *v, /* Prepared statement under construction */
- const char *zLabel, /* Name of the result column */
- const char *zValue /* Value to be returned */
-){
- if( zValue ){
- sqlite3VdbeLoadString(v, 1, (const char*)zValue);
- setOneColumnName(v, zLabel);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
+static void returnSingleInt(Parse *pParse, const char *zLabel, i64 value){
+ Vdbe *v = sqlite3GetVdbe(pParse);
+ int nMem = ++pParse->nMem;
+ i64 *pI64 = sqlite3DbMallocRaw(pParse->db, sizeof(value));
+ if( pI64 ){
+ memcpy(pI64, &value, sizeof(value));
}
+ sqlite3VdbeAddOp4(v, OP_Int64, 0, nMem, 0, (char*)pI64, P4_INT64);
+ sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, SQLITE_STATIC);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, nMem, 1);
}
@@ -110288,7 +103843,7 @@ SQLITE_PRIVATE const char *sqlite3JournalModename(int eMode){
**
** Pragmas are of this form:
**
-** PRAGMA [schema.]id [= value]
+** PRAGMA [database.]id [= value]
**
** The identifier might also be a string. The value is a string, and
** identifier, or a number. If minusFlag is true, then the value is
@@ -110300,8 +103855,8 @@ SQLITE_PRIVATE const char *sqlite3JournalModename(int eMode){
*/
SQLITE_PRIVATE void sqlite3Pragma(
Parse *pParse,
- Token *pId1, /* First part of [schema.]id field */
- Token *pId2, /* Second part of [schema.]id field, or NULL */
+ Token *pId1, /* First part of [database.]id field */
+ Token *pId2, /* Second part of [database.]id field, or NULL */
Token *pValue, /* Token for <value>, or NULL */
int minusFlag /* True if a '-' sign preceded <value> */
){
@@ -110322,7 +103877,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3VdbeRunOnlyOnce(v);
pParse->nMem = 2;
- /* Interpret the [schema.] part of the pragma statement. iDb is the
+ /* Interpret the [database.] part of the pragma statement. iDb is the
** index of the database this pragma is being applied to in db.aDb[]. */
iDb = sqlite3TwoPartName(pParse, pId1, pId2, &pId);
if( iDb<0 ) return;
@@ -110371,8 +103926,14 @@ SQLITE_PRIVATE void sqlite3Pragma(
db->busyHandler.nBusy = 0;
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl);
if( rc==SQLITE_OK ){
- returnSingleText(v, "result", aFcntl[0]);
- sqlite3_free(aFcntl[0]);
+ if( aFcntl[0] ){
+ int nMem = ++pParse->nMem;
+ sqlite3VdbeAddOp4(v, OP_String8, 0, nMem, 0, aFcntl[0], 0);
+ sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "result", SQLITE_STATIC);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, nMem, 1);
+ sqlite3_free(aFcntl[0]);
+ }
goto pragma_out;
}
if( rc!=SQLITE_NOTFOUND ){
@@ -110411,8 +103972,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
/*
- ** PRAGMA [schema.]default_cache_size
- ** PRAGMA [schema.]default_cache_size=N
+ ** PRAGMA [database.]default_cache_size
+ ** PRAGMA [database.]default_cache_size=N
**
** The first form reports the current persistent setting for the
** page cache size. The value returned is the maximum number of
@@ -110439,21 +104000,21 @@ SQLITE_PRIVATE void sqlite3Pragma(
{ OP_Noop, 0, 0, 0},
{ OP_ResultRow, 1, 1, 0},
};
- VdbeOp *aOp;
+ int addr;
sqlite3VdbeUsesBtree(v, iDb);
if( !zRight ){
- setOneColumnName(v, "cache_size");
+ sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", SQLITE_STATIC);
pParse->nMem += 2;
- sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(getCacheSize));
- aOp = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize, iLn);
- if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
- aOp[0].p1 = iDb;
- aOp[1].p1 = iDb;
- aOp[6].p1 = SQLITE_DEFAULT_CACHE_SIZE;
+ addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize,iLn);
+ sqlite3VdbeChangeP1(v, addr, iDb);
+ sqlite3VdbeChangeP1(v, addr+1, iDb);
+ sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE);
}else{
int size = sqlite3AbsInt32(sqlite3Atoi(zRight));
sqlite3BeginWriteOperation(pParse, 0, iDb);
- sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, size);
+ sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
+ sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
pDb->pSchema->cache_size = size;
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
@@ -110464,8 +104025,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
/*
- ** PRAGMA [schema.]page_size
- ** PRAGMA [schema.]page_size=N
+ ** PRAGMA [database.]page_size
+ ** PRAGMA [database.]page_size=N
**
** The first form reports the current setting for the
** database page size in bytes. The second form sets the
@@ -110477,22 +104038,22 @@ SQLITE_PRIVATE void sqlite3Pragma(
assert( pBt!=0 );
if( !zRight ){
int size = ALWAYS(pBt) ? sqlite3BtreeGetPageSize(pBt) : 0;
- returnSingleInt(v, "page_size", size);
+ returnSingleInt(pParse, "page_size", size);
}else{
/* Malloc may fail when setting the page-size, as there is an internal
** buffer that the pager module resizes using sqlite3_realloc().
*/
db->nextPagesize = sqlite3Atoi(zRight);
if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,-1,0) ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
}
}
break;
}
/*
- ** PRAGMA [schema.]secure_delete
- ** PRAGMA [schema.]secure_delete=ON/OFF
+ ** PRAGMA [database.]secure_delete
+ ** PRAGMA [database.]secure_delete=ON/OFF
**
** The first form reports the current setting for the
** secure_delete flag. The second form changes the secure_delete
@@ -110512,13 +104073,13 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
}
b = sqlite3BtreeSecureDelete(pBt, b);
- returnSingleInt(v, "secure_delete", b);
+ returnSingleInt(pParse, "secure_delete", b);
break;
}
/*
- ** PRAGMA [schema.]max_page_count
- ** PRAGMA [schema.]max_page_count=N
+ ** 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
@@ -110529,7 +104090,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
** change. The only purpose is to provide an easy way to test
** the sqlite3AbsInt32() function.
**
- ** PRAGMA [schema.]page_count
+ ** PRAGMA [database.]page_count
**
** Return the number of pages in the specified database.
*/
@@ -110550,8 +104111,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
/*
- ** PRAGMA [schema.]locking_mode
- ** PRAGMA [schema.]locking_mode = (normal|exclusive)
+ ** PRAGMA [database.]locking_mode
+ ** PRAGMA [database.]locking_mode = (normal|exclusive)
*/
case PragTyp_LOCKING_MODE: {
const char *zRet = "normal";
@@ -110591,20 +104152,25 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( eMode==PAGER_LOCKINGMODE_EXCLUSIVE ){
zRet = "exclusive";
}
- returnSingleText(v, "locking_mode", zRet);
+ sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "locking_mode", SQLITE_STATIC);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, zRet, 0);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
break;
}
/*
- ** PRAGMA [schema.]journal_mode
- ** PRAGMA [schema.]journal_mode =
+ ** PRAGMA [database.]journal_mode
+ ** PRAGMA [database.]journal_mode =
** (delete|persist|off|truncate|memory|wal|off)
*/
case PragTyp_JOURNAL_MODE: {
int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */
int ii; /* Loop counter */
- setOneColumnName(v, "journal_mode");
+ sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
+
if( zRight==0 ){
/* If there is no "=MODE" part of the pragma, do a query for the
** current mode */
@@ -110637,8 +104203,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
/*
- ** PRAGMA [schema.]journal_size_limit
- ** PRAGMA [schema.]journal_size_limit=N
+ ** PRAGMA [database.]journal_size_limit
+ ** PRAGMA [database.]journal_size_limit=N
**
** Get or set the size limit on rollback journal files.
*/
@@ -110650,15 +104216,15 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( iLimit<-1 ) iLimit = -1;
}
iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
- returnSingleInt(v, "journal_size_limit", iLimit);
+ returnSingleInt(pParse, "journal_size_limit", iLimit);
break;
}
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
/*
- ** PRAGMA [schema.]auto_vacuum
- ** PRAGMA [schema.]auto_vacuum=N
+ ** PRAGMA [database.]auto_vacuum
+ ** PRAGMA [database.]auto_vacuum=N
**
** Get or set the value of the database 'auto-vacuum' parameter.
** The value is one of: 0 NONE 1 FULL 2 INCREMENTAL
@@ -110668,7 +104234,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
Btree *pBt = pDb->pBt;
assert( pBt!=0 );
if( !zRight ){
- returnSingleInt(v, "auto_vacuum", sqlite3BtreeGetAutoVacuum(pBt));
+ returnSingleInt(pParse, "auto_vacuum", sqlite3BtreeGetAutoVacuum(pBt));
}else{
int eAuto = getAutoVacuum(zRight);
assert( eAuto>=0 && eAuto<=2 );
@@ -110691,18 +104257,16 @@ SQLITE_PRIVATE void sqlite3Pragma(
{ OP_ReadCookie, 0, 1, BTREE_LARGEST_ROOT_PAGE},
{ OP_If, 1, 0, 0}, /* 2 */
{ OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */
- { OP_SetCookie, 0, BTREE_INCR_VACUUM, 0}, /* 4 */
+ { OP_Integer, 0, 1, 0}, /* 4 */
+ { OP_SetCookie, 0, BTREE_INCR_VACUUM, 1}, /* 5 */
};
- VdbeOp *aOp;
- int iAddr = sqlite3VdbeCurrentAddr(v);
- sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setMeta6));
- aOp = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn);
- if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
- aOp[0].p1 = iDb;
- aOp[1].p1 = iDb;
- aOp[2].p2 = iAddr+4;
- aOp[4].p1 = iDb;
- aOp[4].p3 = eAuto - 1;
+ int iAddr;
+ iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6, iLn);
+ sqlite3VdbeChangeP1(v, iAddr, iDb);
+ sqlite3VdbeChangeP1(v, iAddr+1, iDb);
+ sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4);
+ sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1);
+ sqlite3VdbeChangeP1(v, iAddr+5, iDb);
sqlite3VdbeUsesBtree(v, iDb);
}
}
@@ -110711,7 +104275,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
#endif
/*
- ** PRAGMA [schema.]incremental_vacuum(N)
+ ** PRAGMA [database.]incremental_vacuum(N)
**
** Do N steps of incremental vacuuming on a database.
*/
@@ -110734,8 +104298,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
/*
- ** PRAGMA [schema.]cache_size
- ** PRAGMA [schema.]cache_size=N
+ ** PRAGMA [database.]cache_size
+ ** PRAGMA [database.]cache_size=N
**
** The first form reports the current local setting for the
** page cache size. The second form sets the local
@@ -110747,7 +104311,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
case PragTyp_CACHE_SIZE: {
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( !zRight ){
- returnSingleInt(v, "cache_size", pDb->pSchema->cache_size);
+ returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
}else{
int size = sqlite3Atoi(zRight);
pDb->pSchema->cache_size = size;
@@ -110757,50 +104321,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
/*
- ** PRAGMA [schema.]cache_spill
- ** PRAGMA cache_spill=BOOLEAN
- ** PRAGMA [schema.]cache_spill=N
- **
- ** The first form reports the current local setting for the
- ** page cache spill size. The second form turns cache spill on
- ** or off. When turnning cache spill on, the size is set to the
- ** current cache_size. The third form sets a spill size that
- ** may be different form the cache size.
- ** If N is positive then that is the
- ** number of pages in the cache. If N is negative, then the
- ** number of pages is adjusted so that the cache uses -N kibibytes
- ** of memory.
- **
- ** If the number of cache_spill pages is less then the number of
- ** cache_size pages, no spilling occurs until the page count exceeds
- ** the number of cache_size pages.
- **
- ** The cache_spill=BOOLEAN setting applies to all attached schemas,
- ** not just the schema specified.
- */
- case PragTyp_CACHE_SPILL: {
- assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
- if( !zRight ){
- returnSingleInt(v, "cache_spill",
- (db->flags & SQLITE_CacheSpill)==0 ? 0 :
- sqlite3BtreeSetSpillSize(pDb->pBt,0));
- }else{
- int size = 1;
- if( sqlite3GetInt32(zRight, &size) ){
- sqlite3BtreeSetSpillSize(pDb->pBt, size);
- }
- if( sqlite3GetBoolean(zRight, size!=0) ){
- db->flags |= SQLITE_CacheSpill;
- }else{
- db->flags &= ~SQLITE_CacheSpill;
- }
- setAllPagerFlags(db);
- }
- break;
- }
-
- /*
- ** PRAGMA [schema.]mmap_size(N)
+ ** PRAGMA [database.]mmap_size(N)
**
** Used to set mapping size limit. The mapping size limit is
** used to limit the aggregate size of all memory mapped regions of the
@@ -110835,7 +104356,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
rc = SQLITE_OK;
#endif
if( rc==SQLITE_OK ){
- returnSingleInt(v, "mmap_size", sz);
+ returnSingleInt(pParse, "mmap_size", sz);
}else if( rc!=SQLITE_NOTFOUND ){
pParse->nErr++;
pParse->rc = rc;
@@ -110856,7 +104377,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
*/
case PragTyp_TEMP_STORE: {
if( !zRight ){
- returnSingleInt(v, "temp_store", db->temp_store);
+ returnSingleInt(pParse, "temp_store", db->temp_store);
}else{
changeTempStorage(pParse, zRight);
}
@@ -110875,7 +104396,13 @@ SQLITE_PRIVATE void sqlite3Pragma(
*/
case PragTyp_TEMP_STORE_DIRECTORY: {
if( !zRight ){
- returnSingleText(v, "temp_store_directory", sqlite3_temp_directory);
+ if( sqlite3_temp_directory ){
+ sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME,
+ "temp_store_directory", SQLITE_STATIC);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, sqlite3_temp_directory, 0);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
+ }
}else{
#ifndef SQLITE_OMIT_WSD
if( zRight[0] ){
@@ -110919,7 +104446,13 @@ SQLITE_PRIVATE void sqlite3Pragma(
*/
case PragTyp_DATA_STORE_DIRECTORY: {
if( !zRight ){
- returnSingleText(v, "data_store_directory", sqlite3_data_directory);
+ if( sqlite3_data_directory ){
+ sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME,
+ "data_store_directory", SQLITE_STATIC);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, sqlite3_data_directory, 0);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
+ }
}else{
#ifndef SQLITE_OMIT_WSD
if( zRight[0] ){
@@ -110944,8 +104477,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
#if SQLITE_ENABLE_LOCKING_STYLE
/*
- ** PRAGMA [schema.]lock_proxy_file
- ** PRAGMA [schema.]lock_proxy_file = ":auto:"|"lock_file_path"
+ ** PRAGMA [database.]lock_proxy_file
+ ** PRAGMA [database.]lock_proxy_file = ":auto:"|"lock_file_path"
**
** Return or set the value of the lock_proxy_file flag. Changing
** the value sets a specific file to be used for database access locks.
@@ -110958,7 +104491,14 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3_file *pFile = sqlite3PagerFile(pPager);
sqlite3OsFileControlHint(pFile, SQLITE_GET_LOCKPROXYFILE,
&proxy_file_path);
- returnSingleText(v, "lock_proxy_file", proxy_file_path);
+
+ if( proxy_file_path ){
+ sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME,
+ "lock_proxy_file", SQLITE_STATIC);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, proxy_file_path, 0);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
+ }
}else{
Pager *pPager = sqlite3BtreePager(pDb->pBt);
sqlite3_file *pFile = sqlite3PagerFile(pPager);
@@ -110980,8 +104520,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
#endif /* SQLITE_ENABLE_LOCKING_STYLE */
/*
- ** PRAGMA [schema.]synchronous
- ** PRAGMA [schema.]synchronous=OFF|ON|NORMAL|FULL|EXTRA
+ ** PRAGMA [database.]synchronous
+ ** PRAGMA [database.]synchronous=OFF|ON|NORMAL|FULL
**
** Return or set the local value of the synchronous flag. Changing
** the local value does not make changes to the disk file and the
@@ -110990,7 +104530,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
*/
case PragTyp_SYNCHRONOUS: {
if( !zRight ){
- returnSingleInt(v, "synchronous", pDb->safety_level-1);
+ returnSingleInt(pParse, "synchronous", pDb->safety_level-1);
}else{
if( !db->autoCommit ){
sqlite3ErrorMsg(pParse,
@@ -110999,7 +104539,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK;
if( iLevel==0 ) iLevel = 1;
pDb->safety_level = iLevel;
- pDb->bSyncSet = 1;
setAllPagerFlags(db);
}
}
@@ -111010,7 +104549,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
#ifndef SQLITE_OMIT_FLAG_PRAGMAS
case PragTyp_FLAG: {
if( zRight==0 ){
- returnSingleInt(v, pPragma->zName, (db->flags & pPragma->iArg)!=0 );
+ returnSingleInt(pParse, pPragma->zName, (db->flags & pPragma->iArg)!=0 );
}else{
int mask = pPragma->iArg; /* Mask of bits to set or clear. */
if( db->autoCommit==0 ){
@@ -111060,22 +104599,35 @@ SQLITE_PRIVATE void sqlite3Pragma(
Table *pTab;
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
- static const char *azCol[] = {
- "cid", "name", "type", "notnull", "dflt_value", "pk"
- };
int i, k;
int nHidden = 0;
Column *pCol;
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
+ sqlite3VdbeSetNumCols(v, 6);
pParse->nMem = 6;
sqlite3CodeVerifySchema(pParse, iDb);
- setAllColumnNames(v, 6, azCol); assert( 6==ArraySize(azCol) );
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "notnull", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "dflt_value", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", SQLITE_STATIC);
sqlite3ViewGetColumnNames(pParse, pTab);
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
if( IsHiddenColumn(pCol) ){
nHidden++;
continue;
}
+ sqlite3VdbeAddOp2(v, OP_Integer, i-nHidden, 1);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pCol->zName, 0);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
+ pCol->zType ? pCol->zType : "", 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, (pCol->notNull ? 1 : 0), 4);
+ if( pCol->zDflt ){
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pCol->zDflt, 0);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
+ }
if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){
k = 0;
}else if( pPk==0 ){
@@ -111083,14 +104635,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
}else{
for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){}
}
- assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN );
- sqlite3VdbeMultiLoad(v, 1, "issisi",
- i-nHidden,
- pCol->zName,
- sqlite3ColumnType(pCol,""),
- pCol->notNull ? 1 : 0,
- pCol->pDflt ? pCol->pDflt->u.zToken : 0,
- k);
+ sqlite3VdbeAddOp2(v, OP_Integer, k, 6);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
}
}
@@ -111098,26 +104643,31 @@ SQLITE_PRIVATE void sqlite3Pragma(
break;
case PragTyp_STATS: {
- static const char *azCol[] = { "table", "index", "width", "height" };
Index *pIdx;
HashElem *i;
v = sqlite3GetVdbe(pParse);
+ sqlite3VdbeSetNumCols(v, 4);
pParse->nMem = 4;
sqlite3CodeVerifySchema(pParse, iDb);
- setAllColumnNames(v, 4, azCol); assert( 4==ArraySize(azCol) );
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "table", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "index", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "width", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "height", SQLITE_STATIC);
for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){
Table *pTab = sqliteHashData(i);
- sqlite3VdbeMultiLoad(v, 1, "ssii",
- pTab->zName,
- 0,
- pTab->szTabRow,
- pTab->nRowLogEst);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, pTab->zName, 0);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, 2);
+ sqlite3VdbeAddOp2(v, OP_Integer,
+ (int)sqlite3LogEstToInt(pTab->szTabRow), 3);
+ sqlite3VdbeAddOp2(v, OP_Integer,
+ (int)sqlite3LogEstToInt(pTab->nRowLogEst), 4);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- sqlite3VdbeMultiLoad(v, 2, "sii",
- pIdx->zName,
- pIdx->szIdxRow,
- pIdx->aiRowLogEst[0]);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
+ sqlite3VdbeAddOp2(v, OP_Integer,
+ (int)sqlite3LogEstToInt(pIdx->szIdxRow), 3);
+ sqlite3VdbeAddOp2(v, OP_Integer,
+ (int)sqlite3LogEstToInt(pIdx->aiRowLogEst[0]), 4);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
}
}
@@ -111129,9 +104679,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
Table *pTab;
pIdx = sqlite3FindIndex(db, zRight, zDb);
if( pIdx ){
- static const char *azCol[] = {
- "seqno", "cid", "name", "desc", "coll", "key"
- };
int i;
int mx;
if( pPragma->iArg ){
@@ -111144,18 +104691,29 @@ SQLITE_PRIVATE void sqlite3Pragma(
pParse->nMem = 3;
}
pTab = pIdx->pTable;
+ sqlite3VdbeSetNumCols(v, pParse->nMem);
sqlite3CodeVerifySchema(pParse, iDb);
- assert( pParse->nMem<=ArraySize(azCol) );
- setAllColumnNames(v, pParse->nMem, azCol);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", SQLITE_STATIC);
+ if( pPragma->iArg ){
+ sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "desc", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "coll", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "key", SQLITE_STATIC);
+ }
for(i=0; i<mx; i++){
i16 cnum = pIdx->aiColumn[i];
- sqlite3VdbeMultiLoad(v, 1, "iis", i, cnum,
- cnum<0 ? 0 : pTab->aCol[cnum].zName);
+ sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
+ sqlite3VdbeAddOp2(v, OP_Integer, cnum, 2);
+ if( cnum<0 ){
+ sqlite3VdbeAddOp2(v, OP_Null, 0, 3);
+ }else{
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0);
+ }
if( pPragma->iArg ){
- sqlite3VdbeMultiLoad(v, 4, "isi",
- pIdx->aSortOrder[i],
- pIdx->azColl[i],
- i<pIdx->nKeyCol);
+ sqlite3VdbeAddOp2(v, OP_Integer, pIdx->aSortOrder[i], 4);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, pIdx->azColl[i], 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, i<pIdx->nKeyCol, 6);
}
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, pParse->nMem);
}
@@ -111169,21 +104727,22 @@ SQLITE_PRIVATE void sqlite3Pragma(
int i;
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
- static const char *azCol[] = {
- "seq", "name", "unique", "origin", "partial"
- };
v = sqlite3GetVdbe(pParse);
+ sqlite3VdbeSetNumCols(v, 5);
pParse->nMem = 5;
sqlite3CodeVerifySchema(pParse, iDb);
- setAllColumnNames(v, 5, azCol); assert( 5==ArraySize(azCol) );
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "origin", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "partial", SQLITE_STATIC);
for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){
const char *azOrigin[] = { "c", "u", "pk" };
- sqlite3VdbeMultiLoad(v, 1, "isisi",
- i,
- pIdx->zName,
- IsUniqueIndex(pIdx),
- azOrigin[pIdx->idxType],
- pIdx->pPartIdxWhere!=0);
+ sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, IsUniqueIndex(pIdx), 3);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, azOrigin[pIdx->idxType], 0);
+ sqlite3VdbeAddOp2(v, OP_Integer, pIdx->pPartIdxWhere!=0, 5);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
}
}
@@ -111191,31 +104750,35 @@ SQLITE_PRIVATE void sqlite3Pragma(
break;
case PragTyp_DATABASE_LIST: {
- static const char *azCol[] = { "seq", "name", "file" };
int i;
+ sqlite3VdbeSetNumCols(v, 3);
pParse->nMem = 3;
- setAllColumnNames(v, 3, azCol); assert( 3==ArraySize(azCol) );
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "file", SQLITE_STATIC);
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt==0 ) continue;
assert( db->aDb[i].zName!=0 );
- sqlite3VdbeMultiLoad(v, 1, "iss",
- i,
- db->aDb[i].zName,
- sqlite3BtreeGetFilename(db->aDb[i].pBt));
+ sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, db->aDb[i].zName, 0);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
+ sqlite3BtreeGetFilename(db->aDb[i].pBt), 0);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
}
}
break;
case PragTyp_COLLATION_LIST: {
- static const char *azCol[] = { "seq", "name" };
int i = 0;
HashElem *p;
+ sqlite3VdbeSetNumCols(v, 2);
pParse->nMem = 2;
- setAllColumnNames(v, 2, azCol); assert( 2==ArraySize(azCol) );
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){
CollSeq *pColl = (CollSeq *)sqliteHashData(p);
- sqlite3VdbeMultiLoad(v, 1, "is", i++, pColl->zName);
+ sqlite3VdbeAddOp2(v, OP_Integer, i++, 1);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pColl->zName, 0);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
}
}
@@ -111231,26 +104794,33 @@ SQLITE_PRIVATE void sqlite3Pragma(
v = sqlite3GetVdbe(pParse);
pFK = pTab->pFKey;
if( pFK ){
- static const char *azCol[] = {
- "id", "seq", "table", "from", "to", "on_update", "on_delete",
- "match"
- };
int i = 0;
+ sqlite3VdbeSetNumCols(v, 8);
pParse->nMem = 8;
sqlite3CodeVerifySchema(pParse, iDb);
- setAllColumnNames(v, 8, azCol); assert( 8==ArraySize(azCol) );
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "on_update", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 6, COLNAME_NAME, "on_delete", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 7, COLNAME_NAME, "match", SQLITE_STATIC);
while(pFK){
int j;
for(j=0; j<pFK->nCol; j++){
- sqlite3VdbeMultiLoad(v, 1, "iissssss",
- i,
- j,
- pFK->zTo,
- pTab->aCol[pFK->aCol[j].iFrom].zName,
- pFK->aCol[j].zCol,
- actionName(pFK->aAction[1]), /* ON UPDATE */
- actionName(pFK->aAction[0]), /* ON DELETE */
- "NONE");
+ char *zCol = pFK->aCol[j].zCol;
+ char *zOnDelete = (char *)actionName(pFK->aAction[0]);
+ char *zOnUpdate = (char *)actionName(pFK->aAction[1]);
+ sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
+ sqlite3VdbeAddOp2(v, OP_Integer, j, 2);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pFK->zTo, 0);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0,
+ pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
+ sqlite3VdbeAddOp4(v, zCol ? OP_String8 : OP_Null, 0, 5, 0, zCol, 0);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 6, 0, zOnUpdate, 0);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 7, 0, zOnDelete, 0);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 8, 0, "NONE", 0);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 8);
}
++i;
@@ -111279,14 +104849,17 @@ SQLITE_PRIVATE void sqlite3Pragma(
int addrTop; /* Top of a loop checking foreign keys */
int addrOk; /* Jump here if the key is OK */
int *aiCols; /* child to parent column mapping */
- static const char *azCol[] = { "table", "rowid", "parent", "fkid" };
regResult = pParse->nMem+1;
pParse->nMem += 4;
regKey = ++pParse->nMem;
regRow = ++pParse->nMem;
v = sqlite3GetVdbe(pParse);
- setAllColumnNames(v, 4, azCol); assert( 4==ArraySize(azCol) );
+ sqlite3VdbeSetNumCols(v, 4);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "table", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "rowid", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "parent", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "fkid", SQLITE_STATIC);
sqlite3CodeVerifySchema(pParse, iDb);
k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash);
while( k ){
@@ -111301,7 +104874,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow;
sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead);
- sqlite3VdbeLoadString(v, regResult, pTab->zName);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, regResult, 0, pTab->zName,
+ P4_TRANSIENT);
for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){
pParent = sqlite3FindTable(db, pFK->zTo, zDb);
if( pParent==0 ) continue;
@@ -111346,7 +104920,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow);
}
sqlite3VdbeAddOp3(v, OP_NotExists, i, 0, regRow); VdbeCoverage(v);
- sqlite3VdbeGoto(v, addrOk);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrOk);
sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
}else{
for(j=0; j<pFK->nCol; j++){
@@ -111356,13 +104930,15 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
if( pParent ){
sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
- sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
+ sqlite3IndexAffinityStr(v,pIdx), pFK->nCol);
sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
VdbeCoverage(v);
}
}
sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
- sqlite3VdbeMultiLoad(v, regResult+2, "si", pFK->zTo, i-1);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, regResult+2, 0,
+ pFK->zTo, P4_TRANSIENT);
+ sqlite3VdbeAddOp2(v, OP_Integer, i-1, regResult+3);
sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4);
sqlite3VdbeResolveLabel(v, addrOk);
sqlite3DbFree(db, aiCols);
@@ -111379,7 +104955,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
case PragTyp_PARSER_TRACE: {
if( zRight ){
if( sqlite3GetBoolean(zRight, 0) ){
- sqlite3ParserTrace(stdout, "parser: ");
+ sqlite3ParserTrace(stderr, "parser: ");
}else{
sqlite3ParserTrace(0, 0);
}
@@ -111410,6 +104986,17 @@ SQLITE_PRIVATE void sqlite3Pragma(
case PragTyp_INTEGRITY_CHECK: {
int i, j, addr, mxErr;
+ /* Code that appears at the end of the integrity check. If no error
+ ** messages have been generated, output OK. Otherwise output the
+ ** error message
+ */
+ static const int iLn = VDBE_OFFSET_LINENO(2);
+ static const VdbeOpList endCode[] = {
+ { OP_IfNeg, 1, 0, 0}, /* 0 */
+ { OP_String8, 0, 3, 0}, /* 1 */
+ { OP_ResultRow, 3, 1, 0},
+ };
+
int isQuick = (sqlite3Tolower(zLeft[0])=='q');
/* If the PRAGMA command was of the form "PRAGMA <db>.integrity_check",
@@ -111427,7 +105014,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
/* Initialize the VDBE program */
pParse->nMem = 6;
- setOneColumnName(v, "integrity_check");
+ sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", SQLITE_STATIC);
/* Set the maximum error count */
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
@@ -111443,10 +105031,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
for(i=0; i<db->nDb; i++){
HashElem *x;
Hash *pTbls;
- int *aRoot;
int cnt = 0;
- int mxIdx = 0;
- int nIdx;
if( OMIT_TEMPDB && i==1 ) continue;
if( iDb>=0 && i!=iDb ) continue;
@@ -111459,35 +105044,31 @@ SQLITE_PRIVATE void sqlite3Pragma(
/* Do an integrity check of the B-Tree
**
- ** Begin by finding the root pages numbers
+ ** Begin by filling registers 2, 3, ... with the root pages numbers
** for all tables and indices in the database.
*/
assert( sqlite3SchemaMutexHeld(db, i, 0) );
pTbls = &db->aDb[i].pSchema->tblHash;
- for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
+ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx;
- if( HasRowid(pTab) ) cnt++;
- for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
- if( nIdx>mxIdx ) mxIdx = nIdx;
- }
- aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1));
- if( aRoot==0 ) break;
- for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
- Table *pTab = sqliteHashData(x);
- Index *pIdx;
- if( HasRowid(pTab) ) aRoot[cnt++] = pTab->tnum;
+ if( HasRowid(pTab) ){
+ sqlite3VdbeAddOp2(v, OP_Integer, pTab->tnum, 2+cnt);
+ VdbeComment((v, "%s", pTab->zName));
+ cnt++;
+ }
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- aRoot[cnt++] = pIdx->tnum;
+ sqlite3VdbeAddOp2(v, OP_Integer, pIdx->tnum, 2+cnt);
+ VdbeComment((v, "%s", pIdx->zName));
+ cnt++;
}
}
- aRoot[cnt] = 0;
/* Make sure sufficient number of registers have been allocated */
- pParse->nMem = MAX( pParse->nMem, 8+mxIdx );
+ pParse->nMem = MAX( pParse->nMem, cnt+8 );
/* Do the b-tree integrity checks */
- sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY);
+ sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1);
sqlite3VdbeChangeP5(v, (u8)i);
addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
@@ -111515,14 +105096,13 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
sqlite3VdbeJumpHere(v, addr);
sqlite3ExprCacheClear(pParse);
- sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
+ sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead,
1, 0, &iDataCur, &iIdxCur);
sqlite3VdbeAddOp2(v, OP_Integer, 0, 7);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
}
- assert( pParse->nMem>=8+j );
- assert( sqlite3NoTempsInRange(pParse,1,7+j) );
+ pParse->nMem = MAX(pParse->nMem, 8+j);
sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
/* Verify that all NOT NULL columns really are NOT NULL */
@@ -111557,11 +105137,13 @@ SQLITE_PRIVATE void sqlite3Pragma(
jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
pIdx->nColumn); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
- sqlite3VdbeLoadString(v, 3, "row ");
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, "row ", P4_STATIC);
sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
- sqlite3VdbeLoadString(v, 4, " missing from index ");
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0,
+ " missing from index ", P4_STATIC);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
- jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName);
+ jmp5 = sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0,
+ pIdx->zName, P4_TRANSIENT);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
@@ -111576,19 +105158,20 @@ SQLITE_PRIVATE void sqlite3Pragma(
int kk;
for(kk=0; kk<pIdx->nKeyCol; kk++){
int iCol = pIdx->aiColumn[kk];
- assert( iCol!=XN_ROWID && iCol<pTab->nCol );
- if( iCol>=0 && pTab->aCol[iCol].notNull ) continue;
+ assert( iCol>=0 && iCol<pTab->nCol );
+ if( pTab->aCol[iCol].notNull ) continue;
sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk);
VdbeCoverage(v);
}
jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v);
- sqlite3VdbeGoto(v, uniqOk);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, uniqOk);
sqlite3VdbeJumpHere(v, jmp6);
sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1,
pIdx->nKeyCol); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
- sqlite3VdbeLoadString(v, 3, "non-unique entry in index ");
- sqlite3VdbeGoto(v, jmp5);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
+ "non-unique entry in index ", P4_STATIC);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, jmp5);
sqlite3VdbeResolveLabel(v, uniqOk);
}
sqlite3VdbeJumpHere(v, jmp4);
@@ -111597,7 +105180,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, loopTop-1);
#ifndef SQLITE_OMIT_BTREECOUNT
- sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0,
+ "wrong # of entries in index ", P4_STATIC);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
if( pPk==pIdx ) continue;
addr = sqlite3VdbeCurrentAddr(v);
@@ -111607,30 +105191,17 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3VdbeAddOp3(v, OP_Eq, 8+j, addr+8, 3); VdbeCoverage(v);
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
- sqlite3VdbeLoadString(v, 3, pIdx->zName);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pIdx->zName, P4_TRANSIENT);
sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1);
}
#endif /* SQLITE_OMIT_BTREECOUNT */
}
}
- {
- static const int iLn = VDBE_OFFSET_LINENO(2);
- static const VdbeOpList endCode[] = {
- { OP_AddImm, 1, 0, 0}, /* 0 */
- { OP_If, 1, 4, 0}, /* 1 */
- { OP_String8, 0, 3, 0}, /* 2 */
- { OP_ResultRow, 3, 1, 0}, /* 3 */
- };
- VdbeOp *aOp;
-
- aOp = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
- if( aOp ){
- aOp[0].p2 = -mxErr;
- aOp[2].p4type = P4_STATIC;
- aOp[2].p4.z = "ok";
- }
- }
+ addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
+ sqlite3VdbeChangeP3(v, addr, -mxErr);
+ sqlite3VdbeJumpHere(v, addr);
+ sqlite3VdbeChangeP4(v, addr+1, "ok", P4_STATIC);
}
break;
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -111676,10 +105247,14 @@ SQLITE_PRIVATE void sqlite3Pragma(
const struct EncName *pEnc;
if( !zRight ){ /* "PRAGMA encoding" */
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
+ sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "encoding", SQLITE_STATIC);
+ sqlite3VdbeAddOp2(v, OP_String8, 0, 1);
assert( encnames[SQLITE_UTF8].enc==SQLITE_UTF8 );
assert( encnames[SQLITE_UTF16LE].enc==SQLITE_UTF16LE );
assert( encnames[SQLITE_UTF16BE].enc==SQLITE_UTF16BE );
- returnSingleText(v, "encoding", encnames[ENC(pParse->db)].zName);
+ sqlite3VdbeChangeP4(v, -1, encnames[ENC(pParse->db)].zName, P4_STATIC);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}else{ /* "PRAGMA encoding = XXX" */
/* Only change the value of sqlite.enc if the database handle is not
** initialized. If the main database exists, the new sqlite.enc value
@@ -111708,18 +105283,16 @@ SQLITE_PRIVATE void sqlite3Pragma(
#ifndef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
/*
- ** PRAGMA [schema.]schema_version
- ** PRAGMA [schema.]schema_version = <integer>
- **
- ** PRAGMA [schema.]user_version
- ** PRAGMA [schema.]user_version = <integer>
+ ** PRAGMA [database.]schema_version
+ ** PRAGMA [database.]schema_version = <integer>
**
- ** PRAGMA [schema.]freelist_count
+ ** PRAGMA [database.]user_version
+ ** PRAGMA [database.]user_version = <integer>
**
- ** PRAGMA [schema.]data_version
+ ** PRAGMA [database.]freelist_count = <integer>
**
- ** PRAGMA [schema.]application_id
- ** PRAGMA [schema.]application_id = <integer>
+ ** PRAGMA [database.]application_id
+ ** PRAGMA [database.]application_id = <integer>
**
** The pragma's schema_version and user_version are used to set or get
** the value of the schema-version and user-version, respectively. Both
@@ -111746,16 +105319,14 @@ SQLITE_PRIVATE void sqlite3Pragma(
/* Write the specified cookie value */
static const VdbeOpList setCookie[] = {
{ OP_Transaction, 0, 1, 0}, /* 0 */
- { OP_SetCookie, 0, 0, 0}, /* 1 */
+ { OP_Integer, 0, 1, 0}, /* 1 */
+ { OP_SetCookie, 0, 0, 1}, /* 2 */
};
- VdbeOp *aOp;
- sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(setCookie));
- aOp = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0);
- if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
- aOp[0].p1 = iDb;
- aOp[1].p1 = iDb;
- aOp[1].p2 = iCookie;
- aOp[1].p3 = sqlite3Atoi(zRight);
+ int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie, 0);
+ sqlite3VdbeChangeP1(v, addr, iDb);
+ sqlite3VdbeChangeP1(v, addr+1, sqlite3Atoi(zRight));
+ sqlite3VdbeChangeP1(v, addr+2, iDb);
+ sqlite3VdbeChangeP2(v, addr+2, iCookie);
}else{
/* Read the specified cookie value */
static const VdbeOpList readCookie[] = {
@@ -111763,16 +105334,12 @@ SQLITE_PRIVATE void sqlite3Pragma(
{ OP_ReadCookie, 0, 1, 0}, /* 1 */
{ OP_ResultRow, 1, 1, 0}
};
- VdbeOp *aOp;
- sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(readCookie));
- aOp = sqlite3VdbeAddOpList(v, ArraySize(readCookie),readCookie,0);
- if( ONLY_IF_REALLOC_STRESS(aOp==0) ) break;
- aOp[0].p1 = iDb;
- aOp[1].p1 = iDb;
- aOp[1].p3 = iCookie;
+ int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie, 0);
+ sqlite3VdbeChangeP1(v, addr, iDb);
+ sqlite3VdbeChangeP1(v, addr+1, iDb);
+ sqlite3VdbeChangeP3(v, addr+1, iCookie);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
- sqlite3VdbeReusable(v);
}
}
break;
@@ -111788,25 +105355,24 @@ SQLITE_PRIVATE void sqlite3Pragma(
case PragTyp_COMPILE_OPTIONS: {
int i = 0;
const char *zOpt;
+ sqlite3VdbeSetNumCols(v, 1);
pParse->nMem = 1;
- setOneColumnName(v, "compile_option");
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "compile_option", SQLITE_STATIC);
while( (zOpt = sqlite3_compileoption_get(i++))!=0 ){
- sqlite3VdbeLoadString(v, 1, zOpt);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, zOpt, 0);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}
- sqlite3VdbeReusable(v);
}
break;
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
#ifndef SQLITE_OMIT_WAL
/*
- ** PRAGMA [schema.]wal_checkpoint = passive|full|restart|truncate
+ ** PRAGMA [database.]wal_checkpoint = passive|full|restart|truncate
**
** Checkpoint the database.
*/
case PragTyp_WAL_CHECKPOINT: {
- static const char *azCol[] = { "busy", "log", "checkpointed" };
int iBt = (pId2->z?iDb:SQLITE_MAX_ATTACHED);
int eMode = SQLITE_CHECKPOINT_PASSIVE;
if( zRight ){
@@ -111818,8 +105384,12 @@ SQLITE_PRIVATE void sqlite3Pragma(
eMode = SQLITE_CHECKPOINT_TRUNCATE;
}
}
- setAllColumnNames(v, 3, azCol); assert( 3==ArraySize(azCol) );
+ sqlite3VdbeSetNumCols(v, 3);
pParse->nMem = 3;
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "busy", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "log", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "checkpointed", SQLITE_STATIC);
+
sqlite3VdbeAddOp3(v, OP_Checkpoint, iBt, eMode, 1);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
}
@@ -111837,7 +105407,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( zRight ){
sqlite3_wal_autocheckpoint(db, sqlite3Atoi(zRight));
}
- returnSingleInt(v, "wal_autocheckpoint",
+ returnSingleInt(pParse, "wal_autocheckpoint",
db->xWalCallback==sqlite3WalDefaultHook ?
SQLITE_PTR_TO_INT(db->pWalArg) : 0);
}
@@ -111870,7 +105440,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( zRight ){
sqlite3_busy_timeout(db, sqlite3Atoi(zRight));
}
- returnSingleInt(v, "timeout", db->busyTimeout);
+ returnSingleInt(pParse, "timeout", db->busyTimeout);
break;
}
@@ -111890,7 +105460,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){
sqlite3_soft_heap_limit64(N);
}
- returnSingleInt(v, "soft_heap_limit", sqlite3_soft_heap_limit64(-1));
+ returnSingleInt(pParse, "soft_heap_limit", sqlite3_soft_heap_limit64(-1));
break;
}
@@ -111909,7 +105479,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
){
sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, (int)(N&0x7fffffff));
}
- returnSingleInt(v, "threads",
+ returnSingleInt(pParse, "threads",
sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1));
break;
}
@@ -111922,15 +105492,17 @@ SQLITE_PRIVATE void sqlite3Pragma(
static const char *const azLockName[] = {
"unlocked", "shared", "reserved", "pending", "exclusive"
};
- static const char *azCol[] = { "database", "status" };
int i;
- setAllColumnNames(v, 2, azCol); assert( 2==ArraySize(azCol) );
+ sqlite3VdbeSetNumCols(v, 2);
pParse->nMem = 2;
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "database", SQLITE_STATIC);
+ sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "status", SQLITE_STATIC);
for(i=0; i<db->nDb; i++){
Btree *pBt;
const char *zState = "unknown";
int j;
if( db->aDb[i].zName==0 ) continue;
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, db->aDb[i].zName, P4_STATIC);
pBt = db->aDb[i].pBt;
if( pBt==0 || sqlite3BtreePager(pBt)==0 ){
zState = "closed";
@@ -111938,7 +105510,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){
zState = azLockName[j];
}
- sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zName, zState);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, zState, P4_STATIC);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
}
break;
@@ -112014,7 +105586,6 @@ pragma_out:
** interface, and routines that contribute to loading the database schema
** from disk.
*/
-/* #include "sqliteInt.h" */
/*
** Fill the InitData structure with an error message that indicates
@@ -112027,14 +105598,15 @@ static void corruptSchema(
){
sqlite3 *db = pData->db;
if( !db->mallocFailed && (db->flags & SQLITE_RecoveryMode)==0 ){
- char *z;
if( zObj==0 ) zObj = "?";
- z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj);
- if( zExtra ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra);
- sqlite3DbFree(db, *pData->pzErrMsg);
- *pData->pzErrMsg = z;
+ sqlite3SetString(pData->pzErrMsg, db,
+ "malformed database schema (%s)", zObj);
+ if( zExtra ){
+ *pData->pzErrMsg = sqlite3MAppendf(db, *pData->pzErrMsg,
+ "%s - %s", *pData->pzErrMsg, zExtra);
+ }
}
- pData->rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_CORRUPT_BKPT;
+ pData->rc = db->mallocFailed ? SQLITE_NOMEM : SQLITE_CORRUPT_BKPT;
}
/*
@@ -112091,7 +105663,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
}else{
pData->rc = rc;
if( rc==SQLITE_NOMEM ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
}else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
corruptSchema(pData, argv[0], sqlite3_errmsg(db));
}
@@ -112137,27 +105709,61 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
#ifndef SQLITE_OMIT_DEPRECATED
int size;
#endif
+ Table *pTab;
Db *pDb;
char const *azArg[4];
int meta[5];
InitData initData;
- const char *zMasterName;
+ char const *zMasterSchema;
+ char const *zMasterName;
int openedTransaction = 0;
+ /*
+ ** The master database table has a structure like this
+ */
+ static const char master_schema[] =
+ "CREATE TABLE sqlite_master(\n"
+ " type text,\n"
+ " name text,\n"
+ " tbl_name text,\n"
+ " rootpage integer,\n"
+ " sql text\n"
+ ")"
+ ;
+#ifndef SQLITE_OMIT_TEMPDB
+ static const char temp_master_schema[] =
+ "CREATE TEMP TABLE sqlite_temp_master(\n"
+ " type text,\n"
+ " name text,\n"
+ " tbl_name text,\n"
+ " rootpage integer,\n"
+ " sql text\n"
+ ")"
+ ;
+#else
+ #define temp_master_schema 0
+#endif
+
assert( iDb>=0 && iDb<db->nDb );
assert( db->aDb[iDb].pSchema );
assert( sqlite3_mutex_held(db->mutex) );
assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
- /* Construct the in-memory representation schema tables (sqlite_master or
- ** sqlite_temp_master) by invoking the parser directly. The appropriate
- ** table name will be inserted automatically by the parser so we can just
- ** use the abbreviation "x" here. The parser will also automatically tag
- ** the schema table as read-only. */
- azArg[0] = zMasterName = SCHEMA_TABLE(iDb);
+ /* zMasterSchema and zInitScript are set to point at the master schema
+ ** and initialisation script appropriate for the database being
+ ** initialized. zMasterName is the name of the master table.
+ */
+ if( !OMIT_TEMPDB && iDb==1 ){
+ zMasterSchema = temp_master_schema;
+ }else{
+ zMasterSchema = master_schema;
+ }
+ zMasterName = SCHEMA_TABLE(iDb);
+
+ /* Construct the schema tables. */
+ azArg[0] = zMasterName;
azArg[1] = "1";
- azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text,"
- "rootpage integer,sql text)";
+ azArg[2] = zMasterSchema;
azArg[3] = 0;
initData.db = db;
initData.iDb = iDb;
@@ -112168,6 +105774,10 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
rc = initData.rc;
goto error_out;
}
+ pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName);
+ if( ALWAYS(pTab) ){
+ pTab->tabFlags |= TF_Readonly;
+ }
/* Create a cursor to hold the database open
*/
@@ -112186,7 +105796,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
if( !sqlite3BtreeIsInReadTrans(pDb->pBt) ){
rc = sqlite3BtreeBeginTrans(pDb->pBt, 0);
if( rc!=SQLITE_OK ){
- sqlite3SetString(pzErrMsg, db, sqlite3ErrStr(rc));
+ sqlite3SetString(pzErrMsg, db, "%s", sqlite3ErrStr(rc));
goto initone_error_out;
}
openedTransaction = 1;
@@ -112286,7 +105896,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
{
char *zSql;
zSql = sqlite3MPrintf(db,
- "SELECT name, rootpage, sql FROM \"%w\".%s ORDER BY rowid",
+ "SELECT name, rootpage, sql FROM '%q'.%s ORDER BY rowid",
db->aDb[iDb].zName, zMasterName);
#ifndef SQLITE_OMIT_AUTHORIZATION
{
@@ -112308,7 +105918,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
#endif
}
if( db->mallocFailed ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
sqlite3ResetAllSchemasOfConnection(db);
}
if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){
@@ -112336,7 +105946,7 @@ initone_error_out:
error_out:
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
}
return rc;
}
@@ -112434,7 +106044,7 @@ static void schemaIsValid(Parse *pParse){
if( !sqlite3BtreeIsInReadTrans(pBt) ){
rc = sqlite3BtreeBeginTrans(pBt, 0);
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
}
if( rc!=SQLITE_OK ) return;
openedTransaction = 1;
@@ -112497,11 +106107,6 @@ SQLITE_PRIVATE void sqlite3ParserReset(Parse *pParse){
sqlite3 *db = pParse->db;
sqlite3DbFree(db, pParse->aLabel);
sqlite3ExprListDelete(db, pParse->pConstExpr);
- if( db ){
- assert( db->lookaside.bDisable >= pParse->disableLookaside );
- db->lookaside.bDisable -= pParse->disableLookaside;
- }
- pParse->disableLookaside = 0;
}
}
@@ -112525,12 +106130,12 @@ static int sqlite3Prepare(
/* Allocate the parsing context */
pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
if( pParse==0 ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
goto end_prepare;
}
pParse->pReprepare = pReprepare;
assert( ppStmt && *ppStmt==0 );
- /* assert( !db->mallocFailed ); // not true with SQLITE_USE_ALLOCA */
+ assert( !db->mallocFailed );
assert( sqlite3_mutex_held(db->mutex) );
/* Check to verify that it is possible to get a read lock on all
@@ -112587,8 +106192,8 @@ static int sqlite3Prepare(
zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes);
if( zSqlCopy ){
sqlite3RunParser(pParse, zSqlCopy, &zErrMsg);
- pParse->zTail = &zSql[pParse->zTail-zSqlCopy];
sqlite3DbFree(db, zSqlCopy);
+ pParse->zTail = &zSql[pParse->zTail-zSqlCopy];
}else{
pParse->zTail = &zSql[nBytes];
}
@@ -112597,12 +106202,15 @@ static int sqlite3Prepare(
}
assert( 0==pParse->nQueryLoop );
+ if( db->mallocFailed ){
+ pParse->rc = SQLITE_NOMEM;
+ }
if( pParse->rc==SQLITE_DONE ) pParse->rc = SQLITE_OK;
if( pParse->checkSchema ){
schemaIsValid(pParse);
}
if( db->mallocFailed ){
- pParse->rc = SQLITE_NOMEM_BKPT;
+ pParse->rc = SQLITE_NOMEM;
}
if( pzTail ){
*pzTail = pParse->zTail;
@@ -112718,7 +106326,7 @@ SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){
rc = sqlite3LockAndPrepare(db, zSql, -1, 0, p, &pNew, 0);
if( rc ){
if( rc==SQLITE_NOMEM ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
}
assert( pNew==0 );
return rc;
@@ -112872,7 +106480,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
*/
-/* #include "sqliteInt.h" */
/*
** Trace output macros
@@ -112881,8 +106488,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
/***/ int sqlite3SelectTrace = 0;
# define SELECTTRACE(K,P,S,X) \
if(sqlite3SelectTrace&(K)) \
- sqlite3DebugPrintf("%*s%s.%p: ",(P)->nSelectIndent*2-2,"",\
- (S)->zSelName,(S)),\
+ sqlite3DebugPrintf("%*s%s.%p: ",(P)->nSelectIndent*2-2,"",(S)->zSelName,(S)),\
sqlite3DebugPrintf X
#else
# define SELECTTRACE(K,P,S,X)
@@ -112914,7 +106520,6 @@ struct SortCtx {
int regReturn; /* Register holding block-output return address */
int labelBkOut; /* Start label for the block-output subroutine */
int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */
- int labelDone; /* Jump here when done, ex: LIMIT reached */
u8 sortFlags; /* Zero or more SORTFLAG_* bits */
};
#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
@@ -112934,7 +106539,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
sqlite3ExprListDelete(db, p->pOrderBy);
sqlite3ExprDelete(db, p->pLimit);
sqlite3ExprDelete(db, p->pOffset);
- if( p->pWith ) sqlite3WithDelete(db, p->pWith);
+ sqlite3WithDelete(db, p->pWith);
if( bFree ) sqlite3DbFree(db, p);
p = pPrior;
bFree = 1;
@@ -112965,44 +106570,36 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
ExprList *pGroupBy, /* the GROUP BY clause */
Expr *pHaving, /* the HAVING clause */
ExprList *pOrderBy, /* the ORDER BY clause */
- u32 selFlags, /* Flag parameters, such as SF_Distinct */
+ u16 selFlags, /* Flag parameters, such as SF_Distinct */
Expr *pLimit, /* LIMIT value. NULL means not used */
Expr *pOffset /* OFFSET value. NULL means no offset */
){
Select *pNew;
Select standin;
sqlite3 *db = pParse->db;
- pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
+ pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
if( pNew==0 ){
assert( db->mallocFailed );
pNew = &standin;
+ memset(pNew, 0, sizeof(*pNew));
}
if( pEList==0 ){
- pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ASTERISK,0));
+ pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ALL,0));
}
pNew->pEList = pEList;
- pNew->op = TK_SELECT;
- pNew->selFlags = selFlags;
- pNew->iLimit = 0;
- pNew->iOffset = 0;
-#if SELECTTRACE_ENABLED
- pNew->zSelName[0] = 0;
-#endif
- pNew->addrOpenEphm[0] = -1;
- pNew->addrOpenEphm[1] = -1;
- pNew->nSelectRow = 0;
if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc));
pNew->pSrc = pSrc;
pNew->pWhere = pWhere;
pNew->pGroupBy = pGroupBy;
pNew->pHaving = pHaving;
pNew->pOrderBy = pOrderBy;
- pNew->pPrior = 0;
- pNew->pNext = 0;
+ pNew->selFlags = selFlags;
+ pNew->op = TK_SELECT;
pNew->pLimit = pLimit;
pNew->pOffset = pOffset;
- pNew->pWith = 0;
assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 );
+ pNew->addrOpenEphm[0] = -1;
+ pNew->addrOpenEphm[1] = -1;
if( db->mallocFailed ) {
clearSelect(db, pNew, pNew!=&standin);
pNew = 0;
@@ -113029,7 +106626,7 @@ SQLITE_PRIVATE void sqlite3SelectSetName(Select *p, const char *zName){
** Delete the given Select structure and all of its substructures.
*/
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){
- if( p ) clearSelect(db, p, 1);
+ clearSelect(db, p, 1);
}
/*
@@ -113235,12 +106832,6 @@ static void setJoinExpr(Expr *p, int iTable){
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
ExprSetVVAProperty(p, EP_NoReduce);
p->iRightJoinTable = (i16)iTable;
- if( p->op==TK_FUNCTION && p->x.pList ){
- int i;
- for(i=0; i<p->x.pList->nExpr; i++){
- setJoinExpr(p->x.pList->a[i].pExpr, iTable);
- }
- }
setJoinExpr(p->pLeft, iTable);
p = p->pRight;
}
@@ -113275,12 +106866,12 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
int isOuter;
if( NEVER(pLeftTab==0 || pRightTab==0) ) continue;
- isOuter = (pRight->fg.jointype & JT_OUTER)!=0;
+ isOuter = (pRight->jointype & JT_OUTER)!=0;
/* When the NATURAL keyword is present, add WHERE clause terms for
** every column that the two tables have in common.
*/
- if( pRight->fg.jointype & JT_NATURAL ){
+ if( pRight->jointype & JT_NATURAL ){
if( pRight->pOn || pRight->pUsing ){
sqlite3ErrorMsg(pParse, "a NATURAL join may not have "
"an ON or USING clause", 0);
@@ -113365,7 +106956,6 @@ static void pushOntoSorter(
SortCtx *pSort, /* Information about the ORDER BY clause */
Select *pSelect, /* The whole SELECT statement */
int regData, /* First register holding data to be sorted */
- int regOrigData, /* First register holding data before packing */
int nData, /* Number of elements in the data array */
int nPrefixReg /* No. of reg prior to regData available for use */
){
@@ -113377,10 +106967,8 @@ static void pushOntoSorter(
int regRecord = ++pParse->nMem; /* Assembled sorter record */
int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */
int op; /* Opcode to add sorter record to sorter */
- int iLimit; /* LIMIT counter */
assert( bSeq==0 || bSeq==1 );
- assert( nData==1 || regData==regOrigData );
if( nPrefixReg ){
assert( nPrefixReg==nExpr+bSeq );
regBase = regData - nExpr - bSeq;
@@ -113388,17 +106976,14 @@ static void pushOntoSorter(
regBase = pParse->nMem + 1;
pParse->nMem += nBase;
}
- assert( pSelect->iOffset==0 || pSelect->iLimit!=0 );
- iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit;
- pSort->labelDone = sqlite3VdbeMakeLabel(v);
- sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData,
- SQLITE_ECEL_DUP|SQLITE_ECEL_REF);
+ sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, SQLITE_ECEL_DUP);
if( bSeq ){
sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
}
if( nPrefixReg==0 ){
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData);
}
+
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord);
if( nOBSat>0 ){
int regPrevKey; /* The first nOBSat columns of the previous row */
@@ -113433,10 +107018,6 @@ static void pushOntoSorter(
pSort->regReturn = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor);
- if( iLimit ){
- sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, pSort->labelDone);
- VdbeCoverage(v);
- }
sqlite3VdbeJumpHere(v, addrFirst);
sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat);
sqlite3VdbeJumpHere(v, addrJmp);
@@ -113447,9 +107028,15 @@ static void pushOntoSorter(
op = OP_IdxInsert;
}
sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
- if( iLimit ){
+ if( pSelect->iLimit ){
int addr;
- addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v);
+ int iLimit;
+ if( pSelect->iOffset ){
+ iLimit = pSelect->iOffset+1;
+ }else{
+ iLimit = pSelect->iLimit;
+ }
+ addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, -1); VdbeCoverage(v);
sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
sqlite3VdbeJumpHere(v, addr);
@@ -113465,8 +107052,11 @@ static void codeOffset(
int iContinue /* Jump here to skip the current record */
){
if( iOffset>0 ){
- sqlite3VdbeAddOp3(v, OP_IfPos, iOffset, iContinue, 1); VdbeCoverage(v);
- VdbeComment((v, "OFFSET"));
+ int addr;
+ addr = sqlite3VdbeAddOp3(v, OP_IfNeg, iOffset, 0, -1); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, iContinue);
+ VdbeComment((v, "skip OFFSET records"));
+ sqlite3VdbeJumpHere(v, addr);
}
}
@@ -113590,13 +107180,8 @@ static void selectInnerLoop(
/* If the destination is an EXISTS(...) expression, the actual
** values returned by the SELECT are not required.
*/
- u8 ecelFlags;
- if( eDest==SRT_Mem || eDest==SRT_Output || eDest==SRT_Coroutine ){
- ecelFlags = SQLITE_ECEL_DUP;
- }else{
- ecelFlags = 0;
- }
- sqlite3ExprCodeExprList(pParse, pEList, regResult, 0, ecelFlags);
+ sqlite3ExprCodeExprList(pParse, pEList, regResult,
+ (eDest==SRT_Output||eDest==SRT_Coroutine)?SQLITE_ECEL_DUP:0);
}
/* If the DISTINCT keyword was present on the SELECT statement
@@ -113651,8 +107236,7 @@ static void selectInnerLoop(
default: {
assert( pDistinct->eTnctType==WHERE_DISTINCT_UNORDERED );
- codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol,
- regResult);
+ codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol, regResult);
break;
}
}
@@ -113694,8 +107278,6 @@ static void selectInnerLoop(
int r1 = sqlite3GetTempRange(pParse, nPrefixReg+1);
testcase( eDest==SRT_Table );
testcase( eDest==SRT_EphemTab );
- testcase( eDest==SRT_Fifo );
- testcase( eDest==SRT_DistFifo );
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1+nPrefixReg);
#ifndef SQLITE_OMIT_CTE
if( eDest==SRT_DistFifo ){
@@ -113705,14 +107287,13 @@ static void selectInnerLoop(
** current row to the index and proceed with writing it to the
** output table as well. */
int addr = sqlite3VdbeCurrentAddr(v) + 4;
- sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0);
- VdbeCoverage(v);
+ sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1);
assert( pSort==0 );
}
#endif
if( pSort ){
- pushOntoSorter(pParse, pSort, p, r1+nPrefixReg,regResult,1,nPrefixReg);
+ pushOntoSorter(pParse, pSort, p, r1+nPrefixReg, 1, nPrefixReg);
}else{
int r2 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
@@ -113738,7 +107319,7 @@ static void selectInnerLoop(
** ORDER BY in this case since the order of entries in the set
** does not matter. But there might be a LIMIT clause, in which
** case the order does matter */
- pushOntoSorter(pParse, pSort, p, regResult, regResult, 1, nPrefixReg);
+ pushOntoSorter(pParse, pSort, p, regResult, 1, nPrefixReg);
}else{
int r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
@@ -113764,7 +107345,7 @@ static void selectInnerLoop(
case SRT_Mem: {
assert( nResultCol==1 );
if( pSort ){
- pushOntoSorter(pParse, pSort, p, regResult, regResult, 1, nPrefixReg);
+ pushOntoSorter(pParse, pSort, p, regResult, 1, nPrefixReg);
}else{
assert( regResult==iParm );
/* The LIMIT clause will jump out of the loop for us */
@@ -113778,8 +107359,7 @@ static void selectInnerLoop(
testcase( eDest==SRT_Coroutine );
testcase( eDest==SRT_Output );
if( pSort ){
- pushOntoSorter(pParse, pSort, p, regResult, regResult, nResultCol,
- nPrefixReg);
+ pushOntoSorter(pParse, pSort, p, regResult, nResultCol, nPrefixReg);
}else if( eDest==SRT_Coroutine ){
sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
}else{
@@ -113865,8 +107445,8 @@ static void selectInnerLoop(
** X extra columns.
*/
SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
- int nExtra = (N+X)*(sizeof(CollSeq*)+1);
- KeyInfo *p = sqlite3Malloc(sizeof(KeyInfo) + nExtra);
+ KeyInfo *p = sqlite3DbMallocZero(0,
+ sizeof(KeyInfo) + (N+X)*(sizeof(CollSeq*)+1));
if( p ){
p->aSortOrder = (u8*)&p->aColl[N+X];
p->nField = (u16)N;
@@ -113874,9 +107454,8 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
p->enc = ENC(db);
p->db = db;
p->nRef = 1;
- memset(&p[1], 0, nExtra);
}else{
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
}
return p;
}
@@ -113954,6 +107533,7 @@ static KeyInfo *keyInfoFromExprList(
return pInfo;
}
+#ifndef SQLITE_OMIT_COMPOUND_SELECT
/*
** Name of the connection operator, used for error messages.
*/
@@ -113967,6 +107547,7 @@ static const char *selectOpName(int id){
}
return z;
}
+#endif /* SQLITE_OMIT_COMPOUND_SELECT */
#ifndef SQLITE_OMIT_EXPLAIN
/*
@@ -114053,7 +107634,7 @@ static void generateSortTail(
SelectDest *pDest /* Write the sorted results here */
){
Vdbe *v = pParse->pVdbe; /* The prepared statement */
- int addrBreak = pSort->labelDone; /* Jump here to exit loop */
+ int addrBreak = sqlite3VdbeMakeLabel(v); /* Jump here to exit loop */
int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */
int addr;
int addrOnce = 0;
@@ -114072,10 +107653,9 @@ static void generateSortTail(
struct ExprList_item *aOutEx = p->pEList->a;
#endif
- assert( addrBreak<0 );
if( pSort->labelBkOut ){
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
- sqlite3VdbeGoto(v, addrBreak);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrBreak);
sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
}
iTab = pSort->iECursor;
@@ -114113,7 +107693,10 @@ static void generateSortTail(
VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan));
}
switch( eDest ){
+ case SRT_Table:
case SRT_EphemTab: {
+ testcase( eDest==SRT_Table );
+ testcase( eDest==SRT_EphemTab );
sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid);
sqlite3VdbeAddOp3(v, OP_Insert, iParm, regRow, regRowid);
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
@@ -114190,30 +107773,30 @@ static void generateSortTail(
*/
#ifdef SQLITE_ENABLE_COLUMN_METADATA
# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,C,D,E,F)
-#else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */
-# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,F)
-#endif
static const char *columnTypeImpl(
NameContext *pNC,
Expr *pExpr,
-#ifdef SQLITE_ENABLE_COLUMN_METADATA
const char **pzOrigDb,
const char **pzOrigTab,
const char **pzOrigCol,
-#endif
u8 *pEstWidth
){
- char const *zType = 0;
- int j;
- u8 estWidth = 1;
-#ifdef SQLITE_ENABLE_COLUMN_METADATA
char const *zOrigDb = 0;
char const *zOrigTab = 0;
char const *zOrigCol = 0;
-#endif
+#else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */
+# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,F)
+static const char *columnTypeImpl(
+ NameContext *pNC,
+ Expr *pExpr,
+ u8 *pEstWidth
+){
+#endif /* !defined(SQLITE_ENABLE_COLUMN_METADATA) */
+ char const *zType = 0;
+ int j;
+ u8 estWidth = 1;
- assert( pExpr!=0 );
- assert( pNC->pSrcList!=0 );
+ if( NEVER(pExpr==0) || pNC->pSrcList==0 ) return 0;
switch( pExpr->op ){
case TK_AGG_COLUMN:
case TK_COLUMN: {
@@ -114264,13 +107847,10 @@ static const char *columnTypeImpl(
** of the SELECT statement. Return the declaration type and origin
** data for the result-set column of the sub-select.
*/
- if( iCol>=0 && ALWAYS(iCol<pS->pEList->nExpr) ){
+ if( iCol>=0 && iCol<pS->pEList->nExpr ){
/* If iCol is less than zero, then the expression requests the
** rowid of the sub-select or view. This expression is legal (see
** test case misc2.2.2) - it always evaluates to NULL.
- **
- ** The ALWAYS() is because iCol>=pS->pEList->nExpr will have been
- ** caught already by name resolution.
*/
NameContext sNC;
Expr *p = pS->pEList->a[iCol].pExpr;
@@ -114289,8 +107869,8 @@ static const char *columnTypeImpl(
zType = "INTEGER";
zOrigCol = "rowid";
}else{
+ zType = pTab->aCol[iCol].zType;
zOrigCol = pTab->aCol[iCol].zName;
- zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
estWidth = pTab->aCol[iCol].szEst;
}
zOrigTab = pTab->zName;
@@ -114302,7 +107882,7 @@ static const char *columnTypeImpl(
if( iCol<0 ){
zType = "INTEGER";
}else{
- zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
+ zType = pTab->aCol[iCol].zType;
estWidth = pTab->aCol[iCol].szEst;
}
#endif
@@ -114401,9 +107981,7 @@ static void generateColumnNames(
}
#endif
- if( pParse->colNamesSet || db->mallocFailed ) return;
- assert( v!=0 );
- assert( pTabList!=0 );
+ if( pParse->colNamesSet || NEVER(v==0) || db->mallocFailed ) return;
pParse->colNamesSet = 1;
fullNames = (db->flags & SQLITE_FullColNames)!=0;
shortNames = (db->flags & SQLITE_ShortColNames)!=0;
@@ -114415,7 +107993,7 @@ static void generateColumnNames(
if( pEList->a[i].zName ){
char *zName = pEList->a[i].zName;
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT);
- }else if( p->op==TK_COLUMN || p->op==TK_AGG_COLUMN ){
+ }else if( (p->op==TK_COLUMN || p->op==TK_AGG_COLUMN) && pTabList ){
Table *pTab;
char *zCol;
int iCol = p->iColumn;
@@ -114463,7 +108041,7 @@ static void generateColumnNames(
** Return SQLITE_OK on success. If a memory allocation error occurs,
** store NULL in *paCol and 0 in *pnCol and return SQLITE_NOMEM.
*/
-SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
+static int selectColumnsFromExprList(
Parse *pParse, /* Parsing context */
ExprList *pEList, /* Expr list from which to derive column names */
i16 *pnCol, /* Write the number of columns here */
@@ -114471,15 +108049,13 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
){
sqlite3 *db = pParse->db; /* Database connection */
int i, j; /* Loop counters */
- u32 cnt; /* Index added to make the name unique */
+ int cnt; /* Index added to make the name unique */
Column *aCol, *pCol; /* For looping over result columns */
int nCol; /* Number of columns in the result set */
Expr *p; /* Expression for a single result column */
char *zName; /* Column name */
int nName; /* Size of name in zName[] */
- Hash ht; /* Hash table of column names */
- sqlite3HashInit(&ht);
if( pEList ){
nCol = pEList->nExpr;
aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
@@ -114488,16 +108064,16 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
nCol = 0;
aCol = 0;
}
- assert( nCol==(i16)nCol );
*pnCol = nCol;
*paCol = aCol;
- for(i=0, pCol=aCol; i<nCol && !db->mallocFailed; i++, pCol++){
+ for(i=0, pCol=aCol; i<nCol; i++, pCol++){
/* Get an appropriate name for the column
*/
p = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
if( (zName = pEList->a[i].zName)!=0 ){
/* If the column contains an "AS <name>" phrase, use <name> as the name */
+ zName = sqlite3DbStrDup(db, zName);
}else{
Expr *pColExpr = p; /* The expression that is the result column name */
Table *pTab; /* Table associated with this expression */
@@ -114510,37 +108086,41 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
int iCol = pColExpr->iColumn;
pTab = pColExpr->pTab;
if( iCol<0 ) iCol = pTab->iPKey;
- zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid";
+ zName = sqlite3MPrintf(db, "%s",
+ iCol>=0 ? pTab->aCol[iCol].zName : "rowid");
}else if( pColExpr->op==TK_ID ){
assert( !ExprHasProperty(pColExpr, EP_IntValue) );
- zName = pColExpr->u.zToken;
+ zName = sqlite3MPrintf(db, "%s", pColExpr->u.zToken);
}else{
/* Use the original text of the column expression as its name */
- zName = pEList->a[i].zSpan;
+ zName = sqlite3MPrintf(db, "%s", pEList->a[i].zSpan);
}
}
- zName = sqlite3MPrintf(db, "%s", zName);
+ if( db->mallocFailed ){
+ sqlite3DbFree(db, zName);
+ break;
+ }
/* Make sure the column name is unique. If the name is not unique,
** append an integer to the name so that it becomes unique.
*/
- cnt = 0;
- while( zName && sqlite3HashFind(&ht, zName)!=0 ){
- nName = sqlite3Strlen30(zName);
- if( nName>0 ){
- for(j=nName-1; j>0 && sqlite3Isdigit(zName[j]); j--){}
- if( zName[j]==':' ) nName = j;
+ nName = sqlite3Strlen30(zName);
+ for(j=cnt=0; j<i; j++){
+ if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){
+ char *zNewName;
+ int k;
+ for(k=nName-1; k>1 && sqlite3Isdigit(zName[k]); k--){}
+ if( k>=0 && zName[k]==':' ) nName = k;
+ zName[nName] = 0;
+ zNewName = sqlite3MPrintf(db, "%s:%d", zName, ++cnt);
+ sqlite3DbFree(db, zName);
+ zName = zNewName;
+ j = -1;
+ if( zName==0 ) break;
}
- zName = sqlite3MPrintf(db, "%.*z:%u", nName, zName, ++cnt);
- if( cnt>3 ) sqlite3_randomness(sizeof(cnt), &cnt);
}
pCol->zName = zName;
- sqlite3ColumnPropertiesFromName(0, pCol);
- if( zName && sqlite3HashInsert(&ht, zName, pCol)==pCol ){
- sqlite3OomFault(db);
- }
}
- sqlite3HashClear(&ht);
if( db->mallocFailed ){
for(j=0; j<i; j++){
sqlite3DbFree(db, aCol[j].zName);
@@ -114548,7 +108128,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
sqlite3DbFree(db, aCol);
*paCol = 0;
*pnCol = 0;
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
return SQLITE_OK;
}
@@ -114564,7 +108144,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
** This routine requires that all identifiers in the SELECT
** statement be resolved.
*/
-SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(
+static void selectAddColumnTypeAndCollation(
Parse *pParse, /* Parsing contexts */
Table *pTab, /* Add column type information to this table */
Select *pSelect /* SELECT used to determine types and collations */
@@ -114586,21 +108166,13 @@ SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(
sNC.pSrcList = pSelect->pSrc;
a = pSelect->pEList->a;
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
- const char *zType;
- int n, m;
p = a[i].pExpr;
- zType = columnType(&sNC, p, 0, 0, 0, &pCol->szEst);
+ if( pCol->zType==0 ){
+ pCol->zType = sqlite3DbStrDup(db, columnType(&sNC, p,0,0,0, &pCol->szEst));
+ }
szAll += pCol->szEst;
pCol->affinity = sqlite3ExprAffinity(p);
- if( zType && (m = sqlite3Strlen30(zType))>0 ){
- n = sqlite3Strlen30(pCol->zName);
- pCol->zName = sqlite3DbReallocOrFree(db, pCol->zName, n+m+2);
- if( pCol->zName ){
- memcpy(&pCol->zName[n+1], zType, m+1);
- pCol->colFlags |= COLFLAG_HASTYPE;
- }
- }
- if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_BLOB;
+ if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_NONE;
pColl = sqlite3ExprCollSeq(pParse, p);
if( pColl && pCol->zColl==0 ){
pCol->zColl = sqlite3DbStrDup(db, pColl->zName);
@@ -114631,12 +108203,12 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
}
/* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside
** is disabled */
- assert( db->lookaside.bDisable );
+ assert( db->lookaside.bEnabled==0 );
pTab->nRef = 1;
pTab->zName = 0;
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
- sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
- sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect);
+ selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
+ selectAddColumnTypeAndCollation(pParse, pTab, pSelect);
pTab->iPKey = -1;
if( db->mallocFailed ){
sqlite3DeleteTable(db, pTab);
@@ -114649,19 +108221,19 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
** Get a VDBE for the given parser context. Create a new one if necessary.
** If an error occurs, return NULL and leave a message in pParse.
*/
-static SQLITE_NOINLINE Vdbe *allocVdbe(Parse *pParse){
- Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
- if( v ) sqlite3VdbeAddOp0(v, OP_Init);
- if( pParse->pToplevel==0
- && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
- ){
- pParse->okConstFactor = 1;
- }
- return v;
-}
SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
Vdbe *v = pParse->pVdbe;
- return v ? v : allocVdbe(pParse);
+ if( v==0 ){
+ v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
+ if( v ) sqlite3VdbeAddOp0(v, OP_Init);
+ if( pParse->pToplevel==0
+ && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
+ ){
+ pParse->okConstFactor = 1;
+ }
+
+ }
+ return v;
}
@@ -114692,7 +108264,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
Vdbe *v = 0;
int iLimit = 0;
int iOffset;
- int n;
+ int addr1, n;
if( p->iLimit ) return;
/*
@@ -114711,10 +108283,9 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
sqlite3VdbeAddOp2(v, OP_Integer, n, iLimit);
VdbeComment((v, "LIMIT counter"));
if( n==0 ){
- sqlite3VdbeGoto(v, iBreak);
- }else if( n>=0 && p->nSelectRow>sqlite3LogEst((u64)n) ){
- p->nSelectRow = sqlite3LogEst((u64)n);
- p->selFlags |= SF_FixedLimit;
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak);
+ }else if( n>=0 && p->nSelectRow>(u64)n ){
+ p->nSelectRow = n;
}
}else{
sqlite3ExprCode(pParse, p->pLimit, iLimit);
@@ -114728,8 +108299,14 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
sqlite3ExprCode(pParse, p->pOffset, iOffset);
sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset); VdbeCoverage(v);
VdbeComment((v, "OFFSET counter"));
- sqlite3VdbeAddOp3(v, OP_OffsetLimit, iLimit, iOffset+1, iOffset);
+ addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iOffset); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, iOffset);
+ sqlite3VdbeJumpHere(v, addr1);
+ sqlite3VdbeAddOp3(v, OP_Add, iLimit, iOffset, iOffset+1);
VdbeComment((v, "LIMIT+OFFSET"));
+ addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iLimit); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_Integer, -1, iOffset+1);
+ sqlite3VdbeJumpHere(v, addr1);
}
}
}
@@ -114751,10 +108328,7 @@ static CollSeq *multiSelectCollSeq(Parse *pParse, Select *p, int iCol){
pRet = 0;
}
assert( iCol>=0 );
- /* iCol must be less than p->pEList->nExpr. Otherwise an error would
- ** have been thrown during name resolution and we would not have gotten
- ** this far */
- if( pRet==0 && ALWAYS(iCol<p->pEList->nExpr) ){
+ if( pRet==0 && iCol<p->pEList->nExpr ){
pRet = sqlite3ExprCollSeq(pParse, p->pEList->a[iCol].pExpr);
}
return pRet;
@@ -114809,7 +108383,7 @@ static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){
**
**
** There is exactly one reference to the recursive-table in the FROM clause
-** of recursive-query, marked with the SrcList->a[].fg.isRecursive flag.
+** of recursive-query, marked with the SrcList->a[].isRecursive flag.
**
** The setup-query runs once to generate an initial set of rows that go
** into a Queue table. Rows are extracted from the Queue table one by
@@ -114874,7 +108448,7 @@ static void generateWithRecursiveQuery(
/* Locate the cursor number of the Current table */
for(i=0; ALWAYS(i<pSrc->nSrc); i++){
- if( pSrc->a[i].fg.isRecursive ){
+ if( pSrc->a[i].isRecursive ){
iCurrent = pSrc->a[i].iCursor;
break;
}
@@ -114944,17 +108518,13 @@ static void generateWithRecursiveQuery(
/* Execute the recursive SELECT taking the single row in Current as
** the value for the recursive-table. Store the results in the Queue.
*/
- if( p->selFlags & SF_Aggregate ){
- sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported");
- }else{
- p->pPrior = 0;
- sqlite3Select(pParse, p, &destQueue);
- assert( p->pPrior==0 );
- p->pPrior = pSetup;
- }
+ p->pPrior = 0;
+ sqlite3Select(pParse, p, &destQueue);
+ assert( p->pPrior==0 );
+ p->pPrior = pSetup;
/* Keep running the loop until the Queue is empty */
- sqlite3VdbeGoto(v, addrTop);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
sqlite3VdbeResolveLabel(v, addrBreak);
end_of_recursive_query:
@@ -114974,6 +108544,19 @@ static int multiSelectOrderBy(
);
/*
+** Error message for when two or more terms of a compound select have different
+** size result sets.
+*/
+static void selectWrongNumTermsError(Parse *pParse, Select *p){
+ if( p->selFlags & SF_Values ){
+ sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms");
+ }else{
+ sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
+ " do not have the same number of result columns", selectOpName(p->op));
+ }
+}
+
+/*
** Handle the special case of a compound-select that originates from a
** VALUES clause. By handling this as a special case, we avoid deep
** recursion, and thus do not need to enforce the SQLITE_LIMIT_COMPOUND_SELECT
@@ -114990,6 +108573,7 @@ static int multiSelectValues(
SelectDest *pDest /* What to do with query results */
){
Select *pPrior;
+ int nExpr = p->pEList->nExpr;
int nRow = 1;
int rc = 0;
assert( p->selFlags & SF_MultiValue );
@@ -114998,7 +108582,10 @@ static int multiSelectValues(
assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) );
assert( p->pLimit==0 );
assert( p->pOffset==0 );
- assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr );
+ if( p->pEList->nExpr!=nExpr ){
+ selectWrongNumTermsError(pParse, p);
+ return 1;
+ }
if( p->pPrior==0 ) break;
assert( p->pPrior->pNext==p );
p = p->pPrior;
@@ -115092,6 +108679,7 @@ static int multiSelect(
if( dest.eDest==SRT_EphemTab ){
assert( p->pEList );
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iSDParm, p->pEList->nExpr);
+ sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
dest.eDest = SRT_Table;
}
@@ -115106,7 +108694,11 @@ static int multiSelect(
** in their result sets.
*/
assert( p->pEList && pPrior->pEList );
- assert( p->pEList->nExpr==pPrior->pEList->nExpr );
+ if( p->pEList->nExpr!=pPrior->pEList->nExpr ){
+ selectWrongNumTermsError(pParse, p);
+ rc = 1;
+ goto multi_select_end;
+ }
#ifndef SQLITE_OMIT_CTE
if( p->selFlags & SF_Recursive ){
@@ -115144,22 +108736,18 @@ static int multiSelect(
if( p->iLimit ){
addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v);
VdbeComment((v, "Jump ahead if LIMIT reached"));
- if( p->iOffset ){
- sqlite3VdbeAddOp3(v, OP_OffsetLimit,
- p->iLimit, p->iOffset+1, p->iOffset);
- }
}
explainSetInteger(iSub2, pParse->iNextSelectId);
rc = sqlite3Select(pParse, p, &dest);
testcase( rc!=SQLITE_OK );
pDelete = p->pPrior;
p->pPrior = pPrior;
- p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
+ p->nSelectRow += pPrior->nSelectRow;
if( pPrior->pLimit
&& sqlite3ExprIsInteger(pPrior->pLimit, &nLimit)
- && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit)
+ && nLimit>0 && p->nSelectRow > (u64)nLimit
){
- p->nSelectRow = sqlite3LogEst((u64)nLimit);
+ p->nSelectRow = nLimit;
}
if( addr ){
sqlite3VdbeJumpHere(v, addr);
@@ -115231,9 +108819,7 @@ static int multiSelect(
pDelete = p->pPrior;
p->pPrior = pPrior;
p->pOrderBy = 0;
- if( p->op==TK_UNION ){
- p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
- }
+ if( p->op==TK_UNION ) p->nSelectRow += pPrior->nSelectRow;
sqlite3ExprDelete(db, p->pLimit);
p->pLimit = pLimit;
p->pOffset = pOffset;
@@ -115250,7 +108836,7 @@ static int multiSelect(
if( dest.eDest==SRT_Output ){
Select *pFirst = p;
while( pFirst->pPrior ) pFirst = pFirst->pPrior;
- generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList);
+ generateColumnNames(pParse, 0, pFirst->pEList);
}
iBreak = sqlite3VdbeMakeLabel(v);
iCont = sqlite3VdbeMakeLabel(v);
@@ -115325,7 +108911,7 @@ static int multiSelect(
if( dest.eDest==SRT_Output ){
Select *pFirst = p;
while( pFirst->pPrior ) pFirst = pFirst->pPrior;
- generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList);
+ generateColumnNames(pParse, 0, pFirst->pEList);
}
iBreak = sqlite3VdbeMakeLabel(v);
iCont = sqlite3VdbeMakeLabel(v);
@@ -115368,7 +108954,7 @@ static int multiSelect(
nCol = p->pEList->nExpr;
pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1);
if( !pKeyInfo ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
goto multi_select_end;
}
for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){
@@ -115405,19 +108991,6 @@ multi_select_end:
#endif /* SQLITE_OMIT_COMPOUND_SELECT */
/*
-** Error message for when two or more terms of a compound select have different
-** size result sets.
-*/
-SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p){
- if( p->selFlags & SF_Values ){
- sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms");
- }else{
- sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
- " do not have the same number of result columns", selectOpName(p->op));
- }
-}
-
-/*
** Code an output subroutine for a coroutine implementation of a
** SELECT statment.
**
@@ -115457,12 +109030,12 @@ static int generateOutputSubroutine(
/* Suppress duplicates for UNION, EXCEPT, and INTERSECT
*/
if( regPrev ){
- int addr1, addr2;
- addr1 = sqlite3VdbeAddOp1(v, OP_IfNot, regPrev); VdbeCoverage(v);
- addr2 = sqlite3VdbeAddOp4(v, OP_Compare, pIn->iSdst, regPrev+1, pIn->nSdst,
+ int j1, j2;
+ j1 = sqlite3VdbeAddOp1(v, OP_IfNot, regPrev); VdbeCoverage(v);
+ j2 = sqlite3VdbeAddOp4(v, OP_Compare, pIn->iSdst, regPrev+1, pIn->nSdst,
(char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO);
- sqlite3VdbeAddOp3(v, OP_Jump, addr2+2, iContinue, addr2+2); VdbeCoverage(v);
- sqlite3VdbeJumpHere(v, addr1);
+ sqlite3VdbeAddOp3(v, OP_Jump, j2+2, iContinue, j2+2); VdbeCoverage(v);
+ sqlite3VdbeJumpHere(v, j1);
sqlite3VdbeAddOp3(v, OP_Copy, pIn->iSdst, regPrev+1, pIn->nSdst-1);
sqlite3VdbeAddOp2(v, OP_Integer, 1, regPrev);
}
@@ -115472,14 +109045,15 @@ static int generateOutputSubroutine(
*/
codeOffset(v, p->iOffset, iContinue);
- assert( pDest->eDest!=SRT_Exists );
- assert( pDest->eDest!=SRT_Table );
switch( pDest->eDest ){
/* Store the result as data using a unique key.
*/
+ case SRT_Table:
case SRT_EphemTab: {
int r1 = sqlite3GetTempReg(pParse);
int r2 = sqlite3GetTempReg(pParse);
+ testcase( pDest->eDest==SRT_Table );
+ testcase( pDest->eDest==SRT_EphemTab );
sqlite3VdbeAddOp3(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, r1);
sqlite3VdbeAddOp2(v, OP_NewRowid, pDest->iSDParm, r2);
sqlite3VdbeAddOp3(v, OP_Insert, pDest->iSDParm, r1, r2);
@@ -115507,6 +109081,16 @@ static int generateOutputSubroutine(
break;
}
+#if 0 /* Never occurs on an ORDER BY query */
+ /* If any row exist in the result set, record that fact and abort.
+ */
+ case SRT_Exists: {
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, pDest->iSDParm);
+ /* The LIMIT clause will terminate the loop for us */
+ break;
+ }
+#endif
+
/* If this is a scalar select that is part of an expression, then
** store the results in the appropriate memory cell and break out
** of the scan loop.
@@ -115679,7 +109263,7 @@ static int multiSelectOrderBy(
int savedOffset; /* Saved value of p->iOffset */
int labelCmpr; /* Label for the start of the merge algorithm */
int labelEnd; /* Label for the end of the overall SELECT stmt */
- int addr1; /* Jump instructions that get retargetted */
+ int j1; /* Jump instructions that get retargetted */
int op; /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */
KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */
KeyInfo *pKeyMerge; /* Comparison information for merging rows */
@@ -115723,7 +109307,7 @@ static int multiSelectOrderBy(
}
if( j==nOrderBy ){
Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
- if( pNew==0 ) return SQLITE_NOMEM_BKPT;
+ if( pNew==0 ) return SQLITE_NOMEM;
pNew->flags |= EP_IntValue;
pNew->u.iValue = i;
pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
@@ -115739,13 +109323,14 @@ static int multiSelectOrderBy(
** to the right and the left are evaluated, they use the correct
** collation.
*/
- aPermute = sqlite3DbMallocRawNN(db, sizeof(int)*(nOrderBy + 1));
+ aPermute = sqlite3DbMallocRaw(db, sizeof(int)*nOrderBy);
if( aPermute ){
struct ExprList_item *pItem;
- aPermute[0] = nOrderBy;
- for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){
+ for(i=0, pItem=pOrderBy->a; i<nOrderBy; i++, pItem++){
assert( pItem->u.x.iOrderByCol>0 );
- assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr );
+ /* assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr ) is also true
+ ** but only for well-formed SELECT statements. */
+ testcase( pItem->u.x.iOrderByCol > p->pEList->nExpr );
aPermute[i] = pItem->u.x.iOrderByCol - 1;
}
pKeyMerge = multiSelectOrderByKeyInfo(pParse, p, 1);
@@ -115816,19 +109401,19 @@ static int multiSelectOrderBy(
** left of the compound operator - the "A" select.
*/
addrSelectA = sqlite3VdbeCurrentAddr(v) + 1;
- addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA);
+ j1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA);
VdbeComment((v, "left SELECT"));
pPrior->iLimit = regLimitA;
explainSetInteger(iSub1, pParse->iNextSelectId);
sqlite3Select(pParse, pPrior, &destA);
- sqlite3VdbeEndCoroutine(v, regAddrA);
- sqlite3VdbeJumpHere(v, addr1);
+ sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrA);
+ sqlite3VdbeJumpHere(v, j1);
/* Generate a coroutine to evaluate the SELECT statement on
** the right - the "B" select
*/
addrSelectB = sqlite3VdbeCurrentAddr(v) + 1;
- addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB);
+ j1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB);
VdbeComment((v, "right SELECT"));
savedLimit = p->iLimit;
savedOffset = p->iOffset;
@@ -115838,7 +109423,7 @@ static int multiSelectOrderBy(
sqlite3Select(pParse, p, &destB);
p->iLimit = savedLimit;
p->iOffset = savedOffset;
- sqlite3VdbeEndCoroutine(v, regAddrB);
+ sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrB);
/* Generate a subroutine that outputs the current row of the A
** select as the next output row of the compound select.
@@ -115869,8 +109454,8 @@ static int multiSelectOrderBy(
addrEofA = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd);
VdbeCoverage(v);
- sqlite3VdbeGoto(v, addrEofA);
- p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofA);
+ p->nSelectRow += pPrior->nSelectRow;
}
/* Generate a subroutine to run when the results from select B
@@ -115883,7 +109468,7 @@ static int multiSelectOrderBy(
VdbeNoopComment((v, "eof-B subroutine"));
addrEofB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, labelEnd); VdbeCoverage(v);
- sqlite3VdbeGoto(v, addrEofB);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofB);
}
/* Generate code to handle the case of A<B
@@ -115891,7 +109476,7 @@ static int multiSelectOrderBy(
VdbeNoopComment((v, "A-lt-B subroutine"));
addrAltB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA); VdbeCoverage(v);
- sqlite3VdbeGoto(v, labelCmpr);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
/* Generate code to handle the case of A==B
*/
@@ -115904,7 +109489,7 @@ static int multiSelectOrderBy(
VdbeNoopComment((v, "A-eq-B subroutine"));
addrAeqB =
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA); VdbeCoverage(v);
- sqlite3VdbeGoto(v, labelCmpr);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
}
/* Generate code to handle the case of A>B
@@ -115915,11 +109500,11 @@ static int multiSelectOrderBy(
sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
}
sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v);
- sqlite3VdbeGoto(v, labelCmpr);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
/* This code runs once to initialize everything.
*/
- sqlite3VdbeJumpHere(v, addr1);
+ sqlite3VdbeJumpHere(v, j1);
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA_noB); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v);
@@ -115941,7 +109526,7 @@ static int multiSelectOrderBy(
if( pDest->eDest==SRT_Output ){
Select *pFirst = pPrior;
while( pFirst->pPrior ) pFirst = pFirst->pPrior;
- generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList);
+ generateColumnNames(pParse, 0, pFirst->pEList);
}
/* Reassembly the compound query so that it will be freed correctly
@@ -115962,7 +109547,7 @@ static int multiSelectOrderBy(
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
/* Forward Declarations */
static void substExprList(sqlite3*, ExprList*, int, ExprList*);
-static void substSelect(sqlite3*, Select *, int, ExprList*, int);
+static void substSelect(sqlite3*, Select *, int, ExprList *);
/*
** Scan through the expression pExpr. Replace every reference to
@@ -115999,7 +109584,7 @@ static Expr *substExpr(
pExpr->pLeft = substExpr(db, pExpr->pLeft, iTable, pEList);
pExpr->pRight = substExpr(db, pExpr->pRight, iTable, pEList);
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
- substSelect(db, pExpr->x.pSelect, iTable, pEList, 1);
+ substSelect(db, pExpr->x.pSelect, iTable, pEList);
}else{
substExprList(db, pExpr->x.pList, iTable, pEList);
}
@@ -116022,28 +109607,25 @@ static void substSelect(
sqlite3 *db, /* Report malloc errors here */
Select *p, /* SELECT statement in which to make substitutions */
int iTable, /* Table to be replaced */
- ExprList *pEList, /* Substitute values */
- int doPrior /* Do substitutes on p->pPrior too */
+ ExprList *pEList /* Substitute values */
){
SrcList *pSrc;
struct SrcList_item *pItem;
int i;
if( !p ) return;
- do{
- substExprList(db, p->pEList, iTable, pEList);
- substExprList(db, p->pGroupBy, iTable, pEList);
- substExprList(db, p->pOrderBy, iTable, pEList);
- p->pHaving = substExpr(db, p->pHaving, iTable, pEList);
- p->pWhere = substExpr(db, p->pWhere, iTable, pEList);
- pSrc = p->pSrc;
- assert( pSrc!=0 );
+ substExprList(db, p->pEList, iTable, pEList);
+ substExprList(db, p->pGroupBy, iTable, pEList);
+ substExprList(db, p->pOrderBy, iTable, pEList);
+ p->pHaving = substExpr(db, p->pHaving, iTable, pEList);
+ p->pWhere = substExpr(db, p->pWhere, iTable, pEList);
+ substSelect(db, p->pPrior, iTable, pEList);
+ pSrc = p->pSrc;
+ assert( pSrc ); /* Even for (SELECT 1) we have: pSrc!=0 but pSrc->nSrc==0 */
+ if( ALWAYS(pSrc) ){
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
- substSelect(db, pItem->pSelect, iTable, pEList, 1);
- if( pItem->fg.isTabFunc ){
- substExprList(db, pItem->u1.pFuncArg, iTable, pEList);
- }
+ substSelect(db, pItem->pSelect, iTable, pEList);
}
- }while( doPrior && (p = p->pPrior)!=0 );
+ }
}
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
@@ -116107,8 +109689,8 @@ static void substSelect(
**
** (**) Restriction (10) was removed from the code on 2005-02-05 but we
** accidently carried the comment forward until 2014-09-15. Original
-** text: "The subquery does not use aggregates or the outer query
-** does not use LIMIT."
+** text: "The subquery does not use aggregates or the outer query does not
+** use LIMIT."
**
** (11) The subquery and the outer query do not both have ORDER BY clauses.
**
@@ -116195,7 +109777,7 @@ static int flattenSubquery(
int subqueryIsAgg /* True if the subquery uses aggregate functions */
){
const char *zSavedAuthContext = pParse->zAuthContext;
- Select *pParent; /* Current UNION ALL term of the other query */
+ Select *pParent;
Select *pSub; /* The inner query or "subquery" */
Select *pSub1; /* Pointer to the rightmost select in sub-query */
SrcList *pSrc; /* The FROM clause of the outer query */
@@ -116298,7 +109880,7 @@ static int flattenSubquery(
** is fraught with danger. Best to avoid the whole thing. If the
** subquery is the right term of a LEFT JOIN, then do not flatten.
*/
- if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){
+ if( (pSubitem->jointype & JT_OUTER)!=0 ){
return 0;
}
@@ -116318,10 +109900,10 @@ static int flattenSubquery(
testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate );
assert( pSub->pSrc!=0 );
- assert( pSub->pEList->nExpr==pSub1->pEList->nExpr );
if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0
|| (pSub1->pPrior && pSub1->op!=TK_ALL)
|| pSub1->pSrc->nSrc<1
+ || pSub->pEList->nExpr!=pSub1->pEList->nExpr
){
return 0;
}
@@ -116469,7 +110051,7 @@ static int flattenSubquery(
if( pSrc ){
assert( pParent==p ); /* First time through the loop */
- jointype = pSubitem->fg.jointype;
+ jointype = pSubitem->jointype;
}else{
assert( pParent!=p ); /* 2nd and subsequent times through the loop */
pSrc = pParent->pSrc = sqlite3SrcListAppend(db, 0, 0, 0);
@@ -116490,9 +110072,9 @@ static int flattenSubquery(
**
** The outer query has 3 slots in its FROM clause. One slot of the
** outer query (the middle slot) is used by the subquery. The next
- ** block of code will expand the outer query FROM clause to 4 slots.
- ** The middle slot is expanded to two slots in order to make space
- ** for the two elements in the FROM clause of the subquery.
+ ** block of code will expand the out query to 4 slots. The middle
+ ** slot is expanded to two slots in order to make space for the
+ ** two elements in the FROM clause of the subquery.
*/
if( nSubSrc>1 ){
pParent->pSrc = pSrc = sqlite3SrcListEnlarge(db, pSrc, nSubSrc-1,iFrom+1);
@@ -116506,11 +110088,10 @@ static int flattenSubquery(
*/
for(i=0; i<nSubSrc; i++){
sqlite3IdListDelete(db, pSrc->a[i+iFrom].pUsing);
- assert( pSrc->a[i+iFrom].fg.isTabFunc==0 );
pSrc->a[i+iFrom] = pSubSrc->a[i];
memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
}
- pSrc->a[iFrom].fg.jointype = jointype;
+ pSrc->a[iFrom].jointype = jointype;
/* Now begin substituting subquery result set expressions for
** references to the iParent in the outer query.
@@ -116532,12 +110113,17 @@ static int flattenSubquery(
pList->a[i].zName = zName;
}
}
+ substExprList(db, pParent->pEList, iParent, pSub->pEList);
+ if( isAgg ){
+ substExprList(db, pParent->pGroupBy, iParent, pSub->pEList);
+ pParent->pHaving = substExpr(db, pParent->pHaving, iParent, pSub->pEList);
+ }
if( pSub->pOrderBy ){
/* At this point, any non-zero iOrderByCol values indicate that the
** ORDER BY column expression is identical to the iOrderByCol'th
** expression returned by SELECT statement pSub. Since these values
** do not necessarily correspond to columns in SELECT statement pParent,
- ** zero them before transfering the ORDER BY clause.
+ ** zero them before transferring the ORDER BY clause.
**
** Not doing this may cause an error if a subsequent call to this
** function attempts to flatten a compound sub-query into pParent
@@ -116551,20 +110137,27 @@ static int flattenSubquery(
assert( pSub->pPrior==0 );
pParent->pOrderBy = pOrderBy;
pSub->pOrderBy = 0;
+ }else if( pParent->pOrderBy ){
+ substExprList(db, pParent->pOrderBy, iParent, pSub->pEList);
+ }
+ if( pSub->pWhere ){
+ pWhere = sqlite3ExprDup(db, pSub->pWhere, 0);
+ }else{
+ pWhere = 0;
}
- pWhere = sqlite3ExprDup(db, pSub->pWhere, 0);
if( subqueryIsAgg ){
assert( pParent->pHaving==0 );
pParent->pHaving = pParent->pWhere;
pParent->pWhere = pWhere;
+ pParent->pHaving = substExpr(db, pParent->pHaving, iParent, pSub->pEList);
pParent->pHaving = sqlite3ExprAnd(db, pParent->pHaving,
sqlite3ExprDup(db, pSub->pHaving, 0));
assert( pParent->pGroupBy==0 );
pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0);
}else{
+ pParent->pWhere = substExpr(db, pParent->pWhere, iParent, pSub->pEList);
pParent->pWhere = sqlite3ExprAnd(db, pParent->pWhere, pWhere);
}
- substSelect(db, pParent, iParent, pSub->pEList, 0);
/* The flattened query is distinct if either the inner or the
** outer query is distinct.
@@ -116590,7 +110183,7 @@ static int flattenSubquery(
#if SELECTTRACE_ENABLED
if( sqlite3SelectTrace & 0x100 ){
- SELECTTRACE(0x100,pParse,p,("After flattening:\n"));
+ sqlite3DebugPrintf("After flattening:\n");
sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -116599,83 +110192,6 @@ static int flattenSubquery(
}
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
-
-
-#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
-/*
-** Make copies of relevant WHERE clause terms of the outer query into
-** the WHERE clause of subquery. Example:
-**
-** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1) WHERE x=5 AND y=10;
-**
-** Transformed into:
-**
-** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1 WHERE a=5 AND c-d=10)
-** WHERE x=5 AND y=10;
-**
-** The hope is that the terms added to the inner query will make it more
-** efficient.
-**
-** Do not attempt this optimization if:
-**
-** (1) The inner query is an aggregate. (In that case, we'd really want
-** to copy the outer WHERE-clause terms onto the HAVING clause of the
-** inner query. But they probably won't help there so do not bother.)
-**
-** (2) The inner query is the recursive part of a common table expression.
-**
-** (3) The inner query has a LIMIT clause (since the changes to the WHERE
-** close would change the meaning of the LIMIT).
-**
-** (4) The inner query is the right operand of a LEFT JOIN. (The caller
-** enforces this restriction since this routine does not have enough
-** information to know.)
-**
-** (5) The WHERE clause expression originates in the ON or USING clause
-** of a LEFT JOIN.
-**
-** Return 0 if no changes are made and non-zero if one or more WHERE clause
-** terms are duplicated into the subquery.
-*/
-static int pushDownWhereTerms(
- sqlite3 *db, /* The database connection (for malloc()) */
- Select *pSubq, /* The subquery whose WHERE clause is to be augmented */
- Expr *pWhere, /* The WHERE clause of the outer query */
- int iCursor /* Cursor number of the subquery */
-){
- Expr *pNew;
- int nChng = 0;
- Select *pX; /* For looping over compound SELECTs in pSubq */
- if( pWhere==0 ) return 0;
- for(pX=pSubq; pX; pX=pX->pPrior){
- if( (pX->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){
- testcase( pX->selFlags & SF_Aggregate );
- testcase( pX->selFlags & SF_Recursive );
- testcase( pX!=pSubq );
- return 0; /* restrictions (1) and (2) */
- }
- }
- if( pSubq->pLimit!=0 ){
- return 0; /* restriction (3) */
- }
- while( pWhere->op==TK_AND ){
- nChng += pushDownWhereTerms(db, pSubq, pWhere->pRight, iCursor);
- pWhere = pWhere->pLeft;
- }
- if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction 5 */
- if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
- nChng++;
- while( pSubq ){
- pNew = sqlite3ExprDup(db, pWhere, 0);
- pNew = substExpr(db, pNew, iCursor, pSubq->pEList);
- pSubq->pWhere = sqlite3ExprAnd(db, pSubq->pWhere, pNew);
- pSubq = pSubq->pPrior;
- }
- }
- return nChng;
-}
-#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
-
/*
** Based on the contents of the AggInfo structure indicated by the first
** argument, this function checks if the following are true:
@@ -116759,20 +110275,20 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
** pFrom->pIndex and return SQLITE_OK.
*/
SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pFrom){
- if( pFrom->pTab && pFrom->fg.isIndexedBy ){
+ if( pFrom->pTab && pFrom->zIndex ){
Table *pTab = pFrom->pTab;
- char *zIndexedBy = pFrom->u1.zIndexedBy;
+ char *zIndex = pFrom->zIndex;
Index *pIdx;
for(pIdx=pTab->pIndex;
- pIdx && sqlite3StrICmp(pIdx->zName, zIndexedBy);
+ pIdx && sqlite3StrICmp(pIdx->zName, zIndex);
pIdx=pIdx->pNext
);
if( !pIdx ){
- sqlite3ErrorMsg(pParse, "no such index: %s", zIndexedBy, 0);
+ sqlite3ErrorMsg(pParse, "no such index: %s", zIndex, 0);
pParse->checkSchema = 1;
return SQLITE_ERROR;
}
- pFrom->pIBIndex = pIdx;
+ pFrom->pIndex = pIdx;
}
return SQLITE_OK;
}
@@ -116828,7 +110344,7 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
if( pNewSrc==0 ) return WRC_Abort;
*pNew = *p;
p->pSrc = pNewSrc;
- p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0));
+ p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ALL, 0));
p->op = TK_SELECT;
p->pWhere = 0;
pNew->pGroupBy = 0;
@@ -116847,19 +110363,6 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
return WRC_Continue;
}
-/*
-** Check to see if the FROM clause term pFrom has table-valued function
-** arguments. If it does, leave an error message in pParse and return
-** non-zero, since pFrom is not allowed to be a table-valued function.
-*/
-static int cannotBeFunction(Parse *pParse, struct SrcList_item *pFrom){
- if( pFrom->fg.isTabFunc ){
- sqlite3ErrorMsg(pParse, "'%s' is not a function", pFrom->zName);
- return 1;
- }
- return 0;
-}
-
#ifndef SQLITE_OMIT_CTE
/*
** Argument pWith (which may be NULL) points to a linked list of nested
@@ -116872,7 +110375,7 @@ static int cannotBeFunction(Parse *pParse, struct SrcList_item *pFrom){
** object that the returned CTE belongs to.
*/
static struct Cte *searchWith(
- With *pWith, /* Current innermost WITH clause */
+ With *pWith, /* Current outermost WITH clause */
struct SrcList_item *pItem, /* FROM clause element to resolve */
With **ppContext /* OUT: WITH clause return value belongs to */
){
@@ -116903,12 +110406,11 @@ static struct Cte *searchWith(
** statement with which it is associated.
*/
SQLITE_PRIVATE void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
- assert( bFree==0 || (pParse->pWith==0 && pParse->pWithToFree==0) );
+ assert( bFree==0 || pParse->pWith==0 );
if( pWith ){
- assert( pParse->pWith!=pWith );
pWith->pOuter = pParse->pWith;
pParse->pWith = pWith;
- if( bFree ) pParse->pWithToFree = pWith;
+ pParse->bFreeWith = bFree;
}
}
@@ -116947,15 +110449,14 @@ static int withExpand(
int bMayRecursive; /* True if compound joined by UNION [ALL] */
With *pSavedWith; /* Initial value of pParse->pWith */
- /* If pCte->zCteErr is non-NULL at this point, then this is an illegal
+ /* If pCte->zErr is non-NULL at this point, then this is an illegal
** recursive reference to CTE pCte. Leave an error in pParse and return
- ** early. If pCte->zCteErr is NULL, then this is not a recursive reference.
+ ** early. If pCte->zErr is NULL, then this is not a recursive reference.
** In this case, proceed. */
- if( pCte->zCteErr ){
- sqlite3ErrorMsg(pParse, pCte->zCteErr, pCte->zName);
+ if( pCte->zErr ){
+ sqlite3ErrorMsg(pParse, pCte->zErr, pCte->zName);
return SQLITE_ERROR;
}
- if( cannotBeFunction(pParse, pFrom) ) return SQLITE_ERROR;
assert( pFrom->pTab==0 );
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
@@ -116964,9 +110465,9 @@ static int withExpand(
pTab->zName = sqlite3DbStrDup(db, pCte->zName);
pTab->iPKey = -1;
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
- pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
+ pTab->tabFlags |= TF_Ephemeral;
pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
- if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
+ if( db->mallocFailed ) return SQLITE_NOMEM;
assert( pFrom->pSelect );
/* Check if this is a recursive CTE. */
@@ -116982,7 +110483,7 @@ static int withExpand(
&& 0==sqlite3StrICmp(pItem->zName, pCte->zName)
){
pItem->pTab = pTab;
- pItem->fg.isRecursive = 1;
+ pItem->isRecursive = 1;
pTab->nRef++;
pSel->selFlags |= SF_Recursive;
}
@@ -116998,11 +110499,10 @@ static int withExpand(
}
assert( pTab->nRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nRef==2 ));
- pCte->zCteErr = "circular reference: %s";
+ pCte->zErr = "circular reference: %s";
pSavedWith = pParse->pWith;
pParse->pWith = pWith;
sqlite3WalkSelect(pWalker, bMayRecursive ? pSel->pPrior : pSel);
- pParse->pWith = pWith;
for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior);
pEList = pLeft->pEList;
@@ -117017,16 +110517,16 @@ static int withExpand(
pEList = pCte->pCols;
}
- sqlite3ColumnsFromExprList(pParse, pEList, &pTab->nCol, &pTab->aCol);
+ selectColumnsFromExprList(pParse, pEList, &pTab->nCol, &pTab->aCol);
if( bMayRecursive ){
if( pSel->selFlags & SF_Recursive ){
- pCte->zCteErr = "multiple recursive references: %s";
+ pCte->zErr = "multiple recursive references: %s";
}else{
- pCte->zCteErr = "recursive reference in a subquery: %s";
+ pCte->zErr = "recursive reference in a subquery: %s";
}
sqlite3WalkSelect(pWalker, pSel);
}
- pCte->zCteErr = 0;
+ pCte->zErr = 0;
pParse->pWith = pSavedWith;
}
@@ -117113,9 +110613,17 @@ static int selectExpander(Walker *pWalker, Select *p){
*/
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
Table *pTab;
- assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 );
- if( pFrom->fg.isRecursive ) continue;
- assert( pFrom->pTab==0 );
+ assert( pFrom->isRecursive==0 || pFrom->pTab );
+ if( pFrom->isRecursive ) continue;
+ if( pFrom->pTab!=0 ){
+ /* This statement has already been prepared. There is no need
+ ** to go further. */
+ assert( i==0 );
+#ifndef SQLITE_OMIT_CTE
+ selectPopWith(pWalker, p);
+#endif
+ return WRC_Prune;
+ }
#ifndef SQLITE_OMIT_CTE
if( withExpand(pWalker, pFrom) ) return WRC_Abort;
if( pFrom->pTab ) {} else
@@ -117132,7 +110640,7 @@ static int selectExpander(Walker *pWalker, Select *p){
pTab->nRef = 1;
pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab);
while( pSel->pPrior ){ pSel = pSel->pPrior; }
- sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
+ selectColumnsFromExprList(pParse, pSel->pEList, &pTab->nCol, &pTab->aCol);
pTab->iPKey = -1;
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
pTab->tabFlags |= TF_Ephemeral;
@@ -117149,20 +110657,14 @@ static int selectExpander(Walker *pWalker, Select *p){
return WRC_Abort;
}
pTab->nRef++;
- if( !IsVirtual(pTab) && cannotBeFunction(pParse, pFrom) ){
- return WRC_Abort;
- }
#if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
- if( IsVirtual(pTab) || pTab->pSelect ){
- i16 nCol;
+ if( pTab->pSelect || IsVirtual(pTab) ){
+ /* We reach here if the named table is a really a view */
if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
assert( pFrom->pSelect==0 );
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
sqlite3SelectSetName(pFrom->pSelect, pTab->zName);
- nCol = pTab->nCol;
- pTab->nCol = -1;
sqlite3WalkSelect(pWalker, pFrom->pSelect);
- pTab->nCol = nCol;
}
#endif
}
@@ -117182,20 +110684,19 @@ static int selectExpander(Walker *pWalker, Select *p){
/* For every "*" that occurs in the column list, insert the names of
** all columns in all tables. And for every TABLE.* insert the names
** of all columns in TABLE. The parser inserted a special expression
- ** with the TK_ASTERISK operator for each "*" that it found in the column
- ** list. The following code just has to locate the TK_ASTERISK
- ** expressions and expand each one to the list of all columns in
- ** all tables.
+ ** with the TK_ALL operator for each "*" that it found in the column list.
+ ** The following code just has to locate the TK_ALL expressions and expand
+ ** each one to the list of all columns in all tables.
**
** The first loop just checks to see if there are any "*" operators
** that need expanding.
*/
for(k=0; k<pEList->nExpr; k++){
pE = pEList->a[k].pExpr;
- if( pE->op==TK_ASTERISK ) break;
+ if( pE->op==TK_ALL ) break;
assert( pE->op!=TK_DOT || pE->pRight!=0 );
assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) );
- if( pE->op==TK_DOT && pE->pRight->op==TK_ASTERISK ) break;
+ if( pE->op==TK_DOT && pE->pRight->op==TK_ALL ) break;
}
if( k<pEList->nExpr ){
/*
@@ -117209,13 +110710,18 @@ static int selectExpander(Walker *pWalker, Select *p){
int longNames = (flags & SQLITE_FullColNames)!=0
&& (flags & SQLITE_ShortColNames)==0;
+ /* When processing FROM-clause subqueries, it is always the case
+ ** that full_column_names=OFF and short_column_names=ON. The
+ ** sqlite3ResultSetOfSelect() routine makes it so. */
+ assert( (p->selFlags & SF_NestedFrom)==0
+ || ((flags & SQLITE_FullColNames)==0 &&
+ (flags & SQLITE_ShortColNames)!=0) );
+
for(k=0; k<pEList->nExpr; k++){
pE = a[k].pExpr;
pRight = pE->pRight;
assert( pE->op!=TK_DOT || pRight!=0 );
- if( pE->op!=TK_ASTERISK
- && (pE->op!=TK_DOT || pRight->op!=TK_ASTERISK)
- ){
+ if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pRight->op!=TK_ALL) ){
/* This particular expression does not need to be expanded.
*/
pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
@@ -117267,19 +110773,18 @@ static int selectExpander(Walker *pWalker, Select *p){
continue;
}
- /* If a column is marked as 'hidden', omit it from the expanded
- ** result-set list unless the SELECT has the SF_IncludeHidden
- ** bit set.
+ /* If a column is marked as 'hidden' (currently only possible
+ ** for virtual tables), do not include it in the expanded
+ ** result-set list.
*/
- if( (p->selFlags & SF_IncludeHidden)==0
- && IsHiddenColumn(&pTab->aCol[j])
- ){
+ if( IsHiddenColumn(&pTab->aCol[j]) ){
+ assert(IsVirtual(pTab));
continue;
}
tableSeen = 1;
if( i>0 && zTName==0 ){
- if( (pFrom->fg.jointype & JT_NATURAL)!=0
+ if( (pFrom->jointype & JT_NATURAL)!=0
&& tableAndColumnIndex(pTabList, i, zName, 0, 0)
){
/* In a NATURAL join, omit the join columns from the
@@ -117311,7 +110816,8 @@ static int selectExpander(Walker *pWalker, Select *p){
pExpr = pRight;
}
pNew = sqlite3ExprListAppend(pParse, pNew, pExpr);
- sqlite3TokenInit(&sColname, zColname);
+ sColname.z = zColname;
+ sColname.n = sqlite3Strlen30(zColname);
sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){
struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
@@ -117343,7 +110849,6 @@ static int selectExpander(Walker *pWalker, Select *p){
#if SQLITE_MAX_COLUMN
if( p->pEList && p->pEList->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
sqlite3ErrorMsg(pParse, "too many columns in result set");
- return WRC_Abort;
}
#endif
return WRC_Continue;
@@ -117358,7 +110863,7 @@ static int selectExpander(Walker *pWalker, Select *p){
** Walker.xSelectCallback is set to do something useful for every
** subquery in the parser tree.
*/
-SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
+static int exprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
UNUSED_PARAMETER2(NotUsed, NotUsed2);
return WRC_Continue;
}
@@ -117379,7 +110884,7 @@ SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
Walker w;
memset(&w, 0, sizeof(w));
- w.xExprCallback = sqlite3ExprWalkNoop;
+ w.xExprCallback = exprWalkNoop;
w.pParse = pParse;
if( pParse->hasCompound ){
w.xSelectCallback = convertCompoundSelectToSubquery;
@@ -117414,19 +110919,19 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
struct SrcList_item *pFrom;
assert( p->selFlags & SF_Resolved );
- assert( (p->selFlags & SF_HasTypeInfo)==0 );
- p->selFlags |= SF_HasTypeInfo;
- pParse = pWalker->pParse;
- pTabList = p->pSrc;
- for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
- Table *pTab = pFrom->pTab;
- assert( pTab!=0 );
- if( (pTab->tabFlags & TF_Ephemeral)!=0 ){
- /* A sub-query in the FROM clause of a SELECT */
- Select *pSel = pFrom->pSelect;
- if( pSel ){
- while( pSel->pPrior ) pSel = pSel->pPrior;
- sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel);
+ if( (p->selFlags & SF_HasTypeInfo)==0 ){
+ p->selFlags |= SF_HasTypeInfo;
+ pParse = pWalker->pParse;
+ pTabList = p->pSrc;
+ for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
+ Table *pTab = pFrom->pTab;
+ if( ALWAYS(pTab!=0) && (pTab->tabFlags & TF_Ephemeral)!=0 ){
+ /* A sub-query in the FROM clause of a SELECT */
+ Select *pSel = pFrom->pSelect;
+ if( pSel ){
+ while( pSel->pPrior ) pSel = pSel->pPrior;
+ selectAddColumnTypeAndCollation(pParse, pTab, pSel);
+ }
}
}
}
@@ -117446,7 +110951,7 @@ static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){
Walker w;
memset(&w, 0, sizeof(w));
w.xSelectCallback2 = selectAddSubqueryTypeInfo;
- w.xExprCallback = sqlite3ExprWalkNoop;
+ w.xExprCallback = exprWalkNoop;
w.pParse = pParse;
sqlite3WalkSelect(&w, pSelect);
#endif
@@ -117565,7 +111070,7 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
if( pList ){
nArg = pList->nExpr;
regAgg = sqlite3GetTempRange(pParse, nArg);
- sqlite3ExprCodeExprList(pParse, pList, regAgg, 0, SQLITE_ECEL_DUP);
+ sqlite3ExprCodeExprList(pParse, pList, regAgg, SQLITE_ECEL_DUP);
}else{
nArg = 0;
regAgg = 0;
@@ -117590,7 +111095,7 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ);
}
- sqlite3VdbeAddOp4(v, OP_AggStep0, 0, regAgg, pF->iMem,
+ sqlite3VdbeAddOp4(v, OP_AggStep, 0, regAgg, pF->iMem,
(void*)pF->pFunc, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, (u8)nArg);
sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg);
@@ -117673,7 +111178,7 @@ SQLITE_PRIVATE int sqlite3Select(
WhereInfo *pWInfo; /* Return from sqlite3WhereBegin() */
Vdbe *v; /* The virtual machine under construction */
int isAgg; /* True for select lists like "count(*)" */
- ExprList *pEList = 0; /* List of columns to extract. */
+ ExprList *pEList; /* List of columns to extract. */
SrcList *pTabList; /* List of tables to select from */
Expr *pWhere; /* The WHERE clause. May be NULL */
ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
@@ -117723,11 +111228,12 @@ SQLITE_PRIVATE int sqlite3Select(
memset(&sSort, 0, sizeof(sSort));
sSort.pOrderBy = p->pOrderBy;
pTabList = p->pSrc;
+ pEList = p->pEList;
if( pParse->nErr || db->mallocFailed ){
goto select_end;
}
- assert( p->pEList!=0 );
isAgg = (p->selFlags & SF_Aggregate)!=0;
+ assert( pEList!=0 );
#if SELECTTRACE_ENABLED
if( sqlite3SelectTrace & 0x100 ){
SELECTTRACE(0x100,pParse,p, ("after name resolution:\n"));
@@ -117736,77 +111242,29 @@ SQLITE_PRIVATE int sqlite3Select(
#endif
+ /* Begin generating code.
+ */
+ 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, p->pEList->nExpr) ){
+ if( checkForMultiColumnSelectError(pParse, pDest, pEList->nExpr) ){
goto select_end;
}
#endif
- /* Try to flatten subqueries in the FROM clause up into the main query
+ /* Generate code for all sub-queries in the FROM clause
*/
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
struct SrcList_item *pItem = &pTabList->a[i];
+ SelectDest dest;
Select *pSub = pItem->pSelect;
int isAggSub;
- Table *pTab = pItem->pTab;
- if( pSub==0 ) continue;
-
- /* Catch mismatch in the declared columns of a view and the number of
- ** columns in the SELECT on the RHS */
- if( pTab->nCol!=pSub->pEList->nExpr ){
- sqlite3ErrorMsg(pParse, "expected %d columns for '%s' but got %d",
- pTab->nCol, pTab->zName, pSub->pEList->nExpr);
- goto select_end;
- }
-
- isAggSub = (pSub->selFlags & SF_Aggregate)!=0;
- if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){
- /* This subquery can be absorbed into its parent. */
- if( isAggSub ){
- isAgg = 1;
- p->selFlags |= SF_Aggregate;
- }
- i = -1;
- }
- pTabList = p->pSrc;
- if( db->mallocFailed ) goto select_end;
- if( !IgnorableOrderby(pDest) ){
- sSort.pOrderBy = p->pOrderBy;
- }
- }
-#endif
-
- /* Get a pointer the VDBE under construction, allocating a new VDBE if one
- ** does not already exist */
- v = sqlite3GetVdbe(pParse);
- if( v==0 ) goto select_end;
-#ifndef SQLITE_OMIT_COMPOUND_SELECT
- /* Handle compound SELECT statements using the separate multiSelect()
- ** procedure.
- */
- if( p->pPrior ){
- rc = multiSelect(pParse, p, pDest);
- explainSetInteger(pParse->iSelectId, iRestoreSelectId);
-#if SELECTTRACE_ENABLED
- SELECTTRACE(1,pParse,p,("end compound-select processing\n"));
- pParse->nSelectIndent--;
-#endif
- return rc;
- }
-#endif
-
- /* Generate code for all sub-queries in the FROM clause
- */
-#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
- for(i=0; i<pTabList->nSrc; i++){
- struct SrcList_item *pItem = &pTabList->a[i];
- SelectDest dest;
- Select *pSub = pItem->pSelect;
if( pSub==0 ) continue;
/* Sometimes the code for a subquery will be generated more than
@@ -117816,7 +111274,7 @@ SQLITE_PRIVATE int sqlite3Select(
** is sufficient, though the subroutine to manifest the view does need
** to be invoked again. */
if( pItem->addrFillSub ){
- if( pItem->fg.viaCoroutine==0 ){
+ if( pItem->viaCoroutine==0 ){
sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub);
}
continue;
@@ -117831,39 +111289,16 @@ SQLITE_PRIVATE int sqlite3Select(
*/
pParse->nHeight += sqlite3SelectExprHeight(p);
- /* Make copies of constant WHERE-clause terms in the outer query down
- ** inside the subquery. This can help the subquery to run more efficiently.
- */
- if( (pItem->fg.jointype & JT_OUTER)==0
- && pushDownWhereTerms(db, pSub, p->pWhere, pItem->iCursor)
- ){
-#if SELECTTRACE_ENABLED
- if( sqlite3SelectTrace & 0x100 ){
- SELECTTRACE(0x100,pParse,p,("After WHERE-clause push-down:\n"));
- sqlite3TreeViewSelect(0, p, 0);
+ isAggSub = (pSub->selFlags & SF_Aggregate)!=0;
+ if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){
+ /* This subquery can be absorbed into its parent. */
+ if( isAggSub ){
+ isAgg = 1;
+ p->selFlags |= SF_Aggregate;
}
-#endif
- }
-
- /* Generate code to implement the subquery
- **
- ** The subquery is implemented as a co-routine if all of these are true:
- ** (1) The subquery is guaranteed to be the outer loop (so that it
- ** does not need to be computed more than once)
- ** (2) The ALL keyword after SELECT is omitted. (Applications are
- ** allowed to say "SELECT ALL" instead of just "SELECT" to disable
- ** the use of co-routines.)
- ** (3) Co-routines are not disabled using sqlite3_test_control()
- ** with SQLITE_TESTCTRL_OPTIMIZATIONS.
- **
- ** TODO: Are there other reasons beside (1) to use a co-routine
- ** implementation?
- */
- if( i==0
- && (pTabList->nSrc==1
- || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */
- && (p->selFlags & SF_All)==0 /* (2) */
- && OptimizationEnabled(db, SQLITE_SubqCoroutine) /* (3) */
+ i = -1;
+ }else if( pTabList->nSrc==1
+ && OptimizationEnabled(db, SQLITE_SubqCoroutine)
){
/* Implement a co-routine that will return a single row of the result
** set on each invocation.
@@ -117876,10 +111311,10 @@ SQLITE_PRIVATE int sqlite3Select(
sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
sqlite3Select(pParse, pSub, &dest);
- pItem->pTab->nRowLogEst = pSub->nSelectRow;
- pItem->fg.viaCoroutine = 1;
+ pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
+ pItem->viaCoroutine = 1;
pItem->regResult = dest.iSdst;
- sqlite3VdbeEndCoroutine(v, pItem->regReturn);
+ sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
sqlite3VdbeJumpHere(v, addrTop-1);
sqlite3ClearTempRegCache(pParse);
}else{
@@ -117895,7 +111330,7 @@ SQLITE_PRIVATE int sqlite3Select(
pItem->regReturn = ++pParse->nMem;
topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
pItem->addrFillSub = topAddr+1;
- if( pItem->fg.isCorrelated==0 ){
+ if( pItem->isCorrelated==0 ){
/* If the subquery is not correlated and if we are not inside of
** a trigger, then we only need to compute the value of the subquery
** once. */
@@ -117907,30 +111342,40 @@ SQLITE_PRIVATE int sqlite3Select(
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
sqlite3Select(pParse, pSub, &dest);
- pItem->pTab->nRowLogEst = pSub->nSelectRow;
+ pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
VdbeComment((v, "end %s", pItem->pTab->zName));
sqlite3VdbeChangeP1(v, topAddr, retAddr);
sqlite3ClearTempRegCache(pParse);
}
- if( db->mallocFailed ) goto select_end;
+ if( /*pParse->nErr ||*/ db->mallocFailed ){
+ goto select_end;
+ }
pParse->nHeight -= sqlite3SelectExprHeight(p);
+ pTabList = p->pSrc;
+ if( !IgnorableOrderby(pDest) ){
+ sSort.pOrderBy = p->pOrderBy;
+ }
}
-#endif
-
- /* Various elements of the SELECT copied into local variables for
- ** convenience */
pEList = p->pEList;
+#endif
pWhere = p->pWhere;
pGroupBy = p->pGroupBy;
pHaving = p->pHaving;
sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0;
+#ifndef SQLITE_OMIT_COMPOUND_SELECT
+ /* If there is are a sequence of queries, do the earlier ones first.
+ */
+ if( p->pPrior ){
+ rc = multiSelect(pParse, p, pDest);
+ explainSetInteger(pParse->iSelectId, iRestoreSelectId);
#if SELECTTRACE_ENABLED
- if( sqlite3SelectTrace & 0x400 ){
- SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n"));
- sqlite3TreeViewSelect(0, p, 0);
+ SELECTTRACE(1,pParse,p,("end compound-select processing\n"));
+ pParse->nSelectIndent--;
+#endif
+ return rc;
}
#endif
@@ -117950,30 +111395,23 @@ SQLITE_PRIVATE int sqlite3Select(
** BY and DISTINCT, and an index or separate temp-table for the other.
*/
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
- && sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0
+ && sqlite3ExprListCompare(sSort.pOrderBy, p->pEList, -1)==0
){
p->selFlags &= ~SF_Distinct;
- pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0);
+ p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
+ pGroupBy = p->pGroupBy;
/* Notice that even thought SF_Distinct has been cleared from p->selFlags,
** the sDistinct.isTnct is still set. Hence, isTnct represents the
** original setting of the SF_Distinct flag, not the current setting */
assert( sDistinct.isTnct );
-
-#if SELECTTRACE_ENABLED
- if( sqlite3SelectTrace & 0x400 ){
- SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n"));
- sqlite3TreeViewSelect(0, p, 0);
- }
-#endif
}
- /* If there is an ORDER BY clause, then create an ephemeral index to
- ** do the sorting. But this sorting ephemeral index might end up
- ** being unused if the data can be extracted in pre-sorted order.
- ** If that is the case, then the OP_OpenEphemeral instruction will be
- ** changed to an OP_Noop once we figure out that the sorting index is
- ** not needed. The sSort.addrSortIndex variable is used to facilitate
- ** that change.
+ /* If there is an ORDER BY clause, then this sorting
+ ** index might end up being unused if the data can be
+ ** extracted in pre-sorted order. If that is the case, then the
+ ** OP_OpenEphemeral instruction will be changed to an OP_Noop once
+ ** we figure out that the sorting index is not needed. The addrSortIndex
+ ** variable is used to facilitate that change.
*/
if( sSort.pOrderBy ){
KeyInfo *pKeyInfo;
@@ -117997,21 +111435,21 @@ SQLITE_PRIVATE int sqlite3Select(
/* Set the limiter.
*/
iEnd = sqlite3VdbeMakeLabel(v);
- p->nSelectRow = 320; /* 4 billion rows */
+ p->nSelectRow = LARGEST_INT64;
computeLimitRegisters(pParse, p, iEnd);
if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
- sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen);
+ sqlite3VdbeGetOp(v, sSort.addrSortIndex)->opcode = OP_SorterOpen;
sSort.sortFlags |= SORTFLAG_UseSorter;
}
- /* Open an ephemeral index to use for the distinct set.
+ /* Open a virtual index to use for the distinct set.
*/
if( p->selFlags & SF_Distinct ){
sDistinct.tabTnct = pParse->nTab++;
sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
- sDistinct.tabTnct, 0, 0,
- (char*)keyInfoFromExprList(pParse, p->pEList,0,0),
- P4_KEYINFO);
+ sDistinct.tabTnct, 0, 0,
+ (char*)keyInfoFromExprList(pParse, p->pEList,0,0),
+ P4_KEYINFO);
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
}else{
@@ -118021,12 +111459,10 @@ SQLITE_PRIVATE int sqlite3Select(
if( !isAgg && pGroupBy==0 ){
/* No aggregate functions and no GROUP BY clause */
u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0);
- assert( WHERE_USE_LIMIT==SF_FixedLimit );
- wctrlFlags |= p->selFlags & SF_FixedLimit;
/* Begin the database scan. */
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
- p->pEList, wctrlFlags, p->nSelectRow);
+ p->pEList, wctrlFlags, 0);
if( pWInfo==0 ) goto select_end;
if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
@@ -118086,17 +111522,16 @@ SQLITE_PRIVATE int sqlite3Select(
for(k=pGroupBy->nExpr, pItem=pGroupBy->a; k>0; k--, pItem++){
pItem->u.x.iAlias = 0;
}
- assert( 66==sqlite3LogEst(100) );
- if( p->nSelectRow>66 ) p->nSelectRow = 66;
+ if( p->nSelectRow>100 ) p->nSelectRow = 100;
}else{
- assert( 0==sqlite3LogEst(1) );
- p->nSelectRow = 0;
+ p->nSelectRow = 1;
}
+
/* If there is both a GROUP BY and an ORDER BY clause and they are
** identical, then it may be possible to disable the ORDER BY clause
** on the grounds that the GROUP BY will cause elements to come out
- ** in the correct order. It also may not - the GROUP BY might use a
+ ** in the correct order. It also may not - the GROUP BY may use a
** database index that causes rows to be grouped together as required
** but not actually sorted. Either way, record the fact that the
** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp
@@ -118139,7 +111574,7 @@ SQLITE_PRIVATE int sqlite3Select(
*/
if( pGroupBy ){
KeyInfo *pKeyInfo; /* Keying information for the group by clause */
- int addr1; /* A-vs-B comparision jump */
+ int j1; /* A-vs-B comparision jump */
int addrOutputRow; /* Start of subroutine that outputs a result row */
int regOutputRow; /* Return address register for output subroutine */
int addrSetAbort; /* Set the abort flag and return */
@@ -118220,14 +111655,19 @@ SQLITE_PRIVATE int sqlite3Select(
}
regBase = sqlite3GetTempRange(pParse, nCol);
sqlite3ExprCacheClear(pParse);
- sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0);
+ sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0);
j = nGroupBy;
for(i=0; i<sAggInfo.nColumn; i++){
struct AggInfo_col *pCol = &sAggInfo.aCol[i];
if( pCol->iSorterColumn>=j ){
int r1 = j + regBase;
- sqlite3ExprCodeGetColumnToReg(pParse,
- pCol->pTab, pCol->iColumn, pCol->iTable, r1);
+ int r2;
+
+ r2 = sqlite3ExprCodeGetColumn(pParse,
+ pCol->pTab, pCol->iColumn, pCol->iTable, r1, 0);
+ if( r1!=r2 ){
+ sqlite3VdbeAddOp2(v, OP_SCopy, r2, r1);
+ }
j++;
}
}
@@ -118269,8 +111709,7 @@ SQLITE_PRIVATE int sqlite3Select(
addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
sqlite3ExprCacheClear(pParse);
if( groupBySort ){
- sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx,
- sortOut, sortPTab);
+ sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx, sortOut,sortPTab);
}
for(j=0; j<pGroupBy->nExpr; j++){
if( groupBySort ){
@@ -118282,8 +111721,8 @@ SQLITE_PRIVATE int sqlite3Select(
}
sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr,
(char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO);
- addr1 = sqlite3VdbeCurrentAddr(v);
- sqlite3VdbeAddOp3(v, OP_Jump, addr1+1, 0, addr1+1); VdbeCoverage(v);
+ j1 = sqlite3VdbeCurrentAddr(v);
+ sqlite3VdbeAddOp3(v, OP_Jump, j1+1, 0, j1+1); VdbeCoverage(v);
/* Generate code that runs whenever the GROUP BY changes.
** Changes in the GROUP BY are detected by the previous code
@@ -118305,7 +111744,7 @@ SQLITE_PRIVATE int sqlite3Select(
/* Update the aggregate accumulators based on the content of
** the current row
*/
- sqlite3VdbeJumpHere(v, addr1);
+ sqlite3VdbeJumpHere(v, j1);
updateAccumulator(pParse, &sAggInfo);
sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag);
VdbeComment((v, "indicate data in accumulator"));
@@ -118327,7 +111766,7 @@ SQLITE_PRIVATE int sqlite3Select(
/* Jump over the subroutines
*/
- sqlite3VdbeGoto(v, addrEnd);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEnd);
/* Generate a subroutine that outputs a single row of the result
** set. This subroutine first looks at the iUseFlag. If iUseFlag
@@ -118342,8 +111781,7 @@ SQLITE_PRIVATE int sqlite3Select(
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
sqlite3VdbeResolveLabel(v, addrOutputRow);
addrOutputRow = sqlite3VdbeCurrentAddr(v);
- sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2);
- VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); VdbeCoverage(v);
VdbeComment((v, "Groupby result generator entry point"));
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
finalizeAggFunctions(pParse, &sAggInfo);
@@ -118462,8 +111900,7 @@ SQLITE_PRIVATE int sqlite3Select(
if( flag ){
pMinMax = sqlite3ExprListDup(db, pMinMax, 0);
pDel = pMinMax;
- assert( db->mallocFailed || pMinMax!=0 );
- if( !db->mallocFailed ){
+ if( pMinMax && !db->mallocFailed ){
pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0;
pMinMax->a[0].pExpr->op = TK_COLUMN;
}
@@ -118482,7 +111919,7 @@ SQLITE_PRIVATE int sqlite3Select(
updateAccumulator(pParse, &sAggInfo);
assert( pMinMax==0 || pMinMax->nExpr==1 );
if( sqlite3WhereIsOrdered(pWInfo)>0 ){
- sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo));
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3WhereBreakLabel(pWInfo));
VdbeComment((v, "%s() by index",
(flag==WHERE_ORDERBY_MIN?"min":"max")));
}
@@ -118508,8 +111945,7 @@ SQLITE_PRIVATE int sqlite3Select(
** and send them to the callback one by one.
*/
if( sSort.pOrderBy ){
- explainTempTable(pParse,
- sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY");
+ explainTempTable(pParse, sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY");
generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest);
}
@@ -118542,6 +111978,100 @@ select_end:
return rc;
}
+#ifdef SQLITE_DEBUG
+/*
+** Generate a human-readable description of a the Select object.
+*/
+SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
+ int n = 0;
+ pView = sqlite3TreeViewPush(pView, moreToFollow);
+ sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p)",
+ ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
+ ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p
+ );
+ if( p->pSrc && p->pSrc->nSrc ) n++;
+ if( p->pWhere ) n++;
+ if( p->pGroupBy ) n++;
+ if( p->pHaving ) n++;
+ if( p->pOrderBy ) n++;
+ if( p->pLimit ) n++;
+ if( p->pOffset ) n++;
+ if( p->pPrior ) n++;
+ sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set");
+ if( p->pSrc && p->pSrc->nSrc ){
+ int i;
+ pView = sqlite3TreeViewPush(pView, (n--)>0);
+ sqlite3TreeViewLine(pView, "FROM");
+ for(i=0; i<p->pSrc->nSrc; i++){
+ struct SrcList_item *pItem = &p->pSrc->a[i];
+ StrAccum x;
+ char zLine[100];
+ sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
+ sqlite3XPrintf(&x, 0, "{%d,*}", pItem->iCursor);
+ if( pItem->zDatabase ){
+ sqlite3XPrintf(&x, 0, " %s.%s", pItem->zDatabase, pItem->zName);
+ }else if( pItem->zName ){
+ sqlite3XPrintf(&x, 0, " %s", pItem->zName);
+ }
+ if( pItem->pTab ){
+ sqlite3XPrintf(&x, 0, " tabname=%Q", pItem->pTab->zName);
+ }
+ if( pItem->zAlias ){
+ sqlite3XPrintf(&x, 0, " (AS %s)", pItem->zAlias);
+ }
+ if( pItem->jointype & JT_LEFT ){
+ sqlite3XPrintf(&x, 0, " LEFT-JOIN");
+ }
+ sqlite3StrAccumFinish(&x);
+ sqlite3TreeViewItem(pView, zLine, i<p->pSrc->nSrc-1);
+ if( pItem->pSelect ){
+ sqlite3TreeViewSelect(pView, pItem->pSelect, 0);
+ }
+ sqlite3TreeViewPop(pView);
+ }
+ sqlite3TreeViewPop(pView);
+ }
+ if( p->pWhere ){
+ sqlite3TreeViewItem(pView, "WHERE", (n--)>0);
+ sqlite3TreeViewExpr(pView, p->pWhere, 0);
+ sqlite3TreeViewPop(pView);
+ }
+ if( p->pGroupBy ){
+ sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY");
+ }
+ if( p->pHaving ){
+ sqlite3TreeViewItem(pView, "HAVING", (n--)>0);
+ sqlite3TreeViewExpr(pView, p->pHaving, 0);
+ sqlite3TreeViewPop(pView);
+ }
+ if( p->pOrderBy ){
+ sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY");
+ }
+ if( p->pLimit ){
+ sqlite3TreeViewItem(pView, "LIMIT", (n--)>0);
+ sqlite3TreeViewExpr(pView, p->pLimit, 0);
+ sqlite3TreeViewPop(pView);
+ }
+ if( p->pOffset ){
+ sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
+ sqlite3TreeViewExpr(pView, p->pOffset, 0);
+ sqlite3TreeViewPop(pView);
+ }
+ if( p->pPrior ){
+ const char *zOp = "UNION";
+ switch( p->op ){
+ case TK_ALL: zOp = "UNION ALL"; break;
+ case TK_INTERSECT: zOp = "INTERSECT"; break;
+ case TK_EXCEPT: zOp = "EXCEPT"; break;
+ }
+ sqlite3TreeViewItem(pView, zOp, (n--)>0);
+ sqlite3TreeViewSelect(pView, p->pPrior, 0);
+ sqlite3TreeViewPop(pView);
+ }
+ sqlite3TreeViewPop(pView);
+}
+#endif /* SQLITE_DEBUG */
+
/************** End of select.c **********************************************/
/************** Begin file table.c *******************************************/
/*
@@ -118562,7 +112092,6 @@ select_end:
** These routines are in a separate files so that they will not be linked
** if they are not used.
*/
-/* #include "sqliteInt.h" */
/* #include <stdlib.h> */
/* #include <string.h> */
@@ -118647,7 +112176,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
return 0;
malloc_failed:
- p->rc = SQLITE_NOMEM_BKPT;
+ p->rc = SQLITE_NOMEM;
return 1;
}
@@ -118688,7 +112217,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
res.azResult = sqlite3_malloc64(sizeof(char*)*res.nAlloc );
if( res.azResult==0 ){
db->errCode = SQLITE_NOMEM;
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
res.azResult[0] = 0;
rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg);
@@ -118717,7 +112246,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
if( azNew==0 ){
sqlite3_free_table(&res.azResult[1]);
db->errCode = SQLITE_NOMEM;
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
res.azResult = azNew;
}
@@ -118759,7 +112288,6 @@ SQLITE_API void SQLITE_STDCALL sqlite3_free_table(
*************************************************************************
** This file contains the implementation for TRIGGERs
*/
-/* #include "sqliteInt.h" */
#ifndef SQLITE_OMIT_TRIGGER
/*
@@ -119036,7 +112564,8 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
pStepList->pTrig = pTrig;
pStepList = pStepList->pNext;
}
- sqlite3TokenInit(&nameToken, pTrig->zName);
+ nameToken.z = pTrig->zName;
+ nameToken.n = sqlite3Strlen30(nameToken.z);
sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken);
if( sqlite3FixTriggerStep(&sFix, pTrig->step_list)
|| sqlite3FixExpr(&sFix, pTrig->pWhen)
@@ -119072,7 +112601,7 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
pTrig = sqlite3HashInsert(pHash, zName, pTrig);
if( pTrig ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
}else if( pLink->pSchema==pLink->pTabSchema ){
Table *pTab;
pTab = sqlite3HashFind(&pLink->pTabSchema->tblHash, pLink->table);
@@ -119307,12 +112836,31 @@ SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
*/
assert( pTable!=0 );
if( (v = sqlite3GetVdbe(pParse))!=0 ){
- sqlite3NestedParse(pParse,
- "DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'",
- db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pTrigger->zName
- );
+ int base;
+ static const int iLn = VDBE_OFFSET_LINENO(2);
+ static const VdbeOpList dropTrigger[] = {
+ { OP_Rewind, 0, ADDR(9), 0},
+ { OP_String8, 0, 1, 0}, /* 1 */
+ { OP_Column, 0, 1, 2},
+ { OP_Ne, 2, ADDR(8), 1},
+ { OP_String8, 0, 1, 0}, /* 4: "trigger" */
+ { OP_Column, 0, 0, 2},
+ { OP_Ne, 2, ADDR(8), 1},
+ { OP_Delete, 0, 0, 0},
+ { OP_Next, 0, ADDR(1), 0}, /* 8 */
+ };
+
+ sqlite3BeginWriteOperation(pParse, 0, iDb);
+ sqlite3OpenMasterTable(pParse, iDb);
+ base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger, iLn);
+ sqlite3VdbeChangeP4(v, base+1, pTrigger->zName, P4_TRANSIENT);
+ sqlite3VdbeChangeP4(v, base+4, "trigger", P4_STATIC);
sqlite3ChangeCookie(pParse, iDb);
+ sqlite3VdbeAddOp2(v, OP_Close, 0, 0);
sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0);
+ if( pParse->nMem<3 ){
+ pParse->nMem = 3;
+ }
}
}
@@ -119700,8 +113248,8 @@ SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect(
if( pPrg ){
int bRecursive = (p->zName && 0==(pParse->db->flags&SQLITE_RecTriggers));
- sqlite3VdbeAddOp4(v, OP_Program, reg, ignoreJump, ++pParse->nMem,
- (const char *)pPrg->pProgram, P4_SUBPROGRAM);
+ sqlite3VdbeAddOp3(v, OP_Program, reg, ignoreJump, ++pParse->nMem);
+ sqlite3VdbeChangeP4(v, -1, (const char *)pPrg->pProgram, P4_SUBPROGRAM);
VdbeComment(
(v, "Call: %s.%s", (p->zName?p->zName:"fkey"), onErrorText(orconf)));
@@ -119863,7 +113411,6 @@ SQLITE_PRIVATE u32 sqlite3TriggerColmask(
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
*/
-/* #include "sqliteInt.h" */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Forward declaration */
@@ -119985,9 +113532,9 @@ SQLITE_PRIVATE void sqlite3Update(
/* Register Allocations */
int regRowCount = 0; /* A count of rows changed */
- int regOldRowid = 0; /* The old rowid */
- int regNewRowid = 0; /* The new rowid */
- int regNew = 0; /* Content of the NEW.* table in triggers */
+ int regOldRowid; /* The old rowid */
+ int regNewRowid; /* The new rowid */
+ int regNew; /* Content of the NEW.* table in triggers */
int regOld = 0; /* Content of OLD.* table in triggers */
int regRowSet = 0; /* Rowset of rows to be updated */
int regKey = 0; /* composite PRIMARY KEY value */
@@ -120048,7 +113595,7 @@ SQLITE_PRIVATE void sqlite3Update(
/* Allocate space for aXRef[], aRegIdx[], and aToOpen[].
** Initialize aXRef[] and aToOpen[] to their default values.
*/
- aXRef = sqlite3DbMallocRawNN(db, sizeof(int) * (pTab->nCol+nIdx) + nIdx+2 );
+ aXRef = sqlite3DbMallocRaw(db, sizeof(int) * (pTab->nCol+nIdx) + nIdx+2 );
if( aXRef==0 ) goto update_cleanup;
aRegIdx = aXRef+pTab->nCol;
aToOpen = (u8*)(aRegIdx+nIdx);
@@ -120114,20 +113661,16 @@ SQLITE_PRIVATE void sqlite3Update(
assert( chngPk==0 || chngPk==1 );
chngKey = chngRowid + chngPk;
- /* The SET expressions are not actually used inside the WHERE loop.
- ** So reset the colUsed mask. Unless this is a virtual table. In that
- ** case, set all bits of the colUsed mask (to ensure that the virtual
- ** table implementation makes all columns available).
+ /* The SET expressions are not actually used inside the WHERE loop.
+ ** So reset the colUsed mask
*/
- pTabList->a[0].colUsed = IsVirtual(pTab) ? ALLBITS : 0;
+ pTabList->a[0].colUsed = 0;
hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngKey);
/* There is one entry in the aRegIdx[] array for each index on the table
** being updated. Fill in aRegIdx[] with a register number that will hold
- ** the key for accessing each index.
- **
- ** FIXME: Be smarter about omitting indexes that use expressions.
+ ** the key for accessing each index.
*/
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
int reg;
@@ -120136,8 +113679,7 @@ SQLITE_PRIVATE void sqlite3Update(
}else{
reg = 0;
for(i=0; i<pIdx->nKeyCol; i++){
- i16 iIdxCol = pIdx->aiColumn[i];
- if( iIdxCol<0 || aXRef[iIdxCol]>=0 ){
+ if( aXRef[pIdx->aiColumn[i]]>=0 ){
reg = ++pParse->nMem;
break;
}
@@ -120153,20 +113695,29 @@ SQLITE_PRIVATE void sqlite3Update(
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, 1, iDb);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ /* Virtual tables must be handled separately */
+ if( IsVirtual(pTab) ){
+ updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef,
+ pWhere, onError);
+ pWhere = 0;
+ pTabList = 0;
+ goto update_cleanup;
+ }
+#endif
+
/* Allocate required registers. */
- if( !IsVirtual(pTab) ){
- regRowSet = ++pParse->nMem;
- regOldRowid = regNewRowid = ++pParse->nMem;
- if( chngPk || pTrigger || hasFK ){
- regOld = pParse->nMem + 1;
- pParse->nMem += pTab->nCol;
- }
- if( chngKey || pTrigger || hasFK ){
- regNewRowid = ++pParse->nMem;
- }
- regNew = pParse->nMem + 1;
+ regRowSet = ++pParse->nMem;
+ regOldRowid = regNewRowid = ++pParse->nMem;
+ if( chngPk || pTrigger || hasFK ){
+ regOld = pParse->nMem + 1;
pParse->nMem += pTab->nCol;
}
+ if( chngKey || pTrigger || hasFK ){
+ regNewRowid = ++pParse->nMem;
+ }
+ regNew = pParse->nMem + 1;
+ pParse->nMem += pTab->nCol;
/* Start the view context. */
if( isView ){
@@ -120189,22 +113740,12 @@ SQLITE_PRIVATE void sqlite3Update(
goto update_cleanup;
}
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- /* Virtual tables must be handled separately */
- if( IsVirtual(pTab) ){
- updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef,
- pWhere, onError);
- goto update_cleanup;
- }
-#endif
-
/* Begin the database scan
*/
if( HasRowid(pTab) ){
sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
pWInfo = sqlite3WhereBegin(
- pParse, pTabList, pWhere, 0, 0,
- WHERE_ONEPASS_DESIRED | WHERE_SEEK_TABLE, iIdxCur
+ pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED, iIdxCur
);
if( pWInfo==0 ) goto update_cleanup;
okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
@@ -120238,7 +113779,6 @@ SQLITE_PRIVATE void sqlite3Update(
if( pWInfo==0 ) goto update_cleanup;
okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
for(i=0; i<nPk; i++){
- assert( pPk->aiColumn[i]>=0 );
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pPk->aiColumn[i],
iPk+i);
}
@@ -120248,7 +113788,7 @@ SQLITE_PRIVATE void sqlite3Update(
regKey = iPk;
}else{
sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey,
- sqlite3IndexAffinityStr(db, pPk), nPk);
+ sqlite3IndexAffinityStr(v, pPk), nPk);
sqlite3VdbeAddOp2(v, OP_IdxInsert, iEph, regKey);
}
sqlite3WhereEnd(pWInfo);
@@ -120283,7 +113823,7 @@ SQLITE_PRIVATE void sqlite3Update(
if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iBaseCur] = 0;
if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iBaseCur] = 0;
}
- sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur, aToOpen,
+ sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iBaseCur, aToOpen,
0, 0);
}
@@ -120361,6 +113901,7 @@ SQLITE_PRIVATE void sqlite3Update(
newmask = sqlite3TriggerColmask(
pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
);
+ /*sqlite3VdbeAddOp3(v, OP_Null, 0, regNew, regNew+pTab->nCol-1);*/
for(i=0; i<pTab->nCol; i++){
if( i==pTab->iPKey ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
@@ -120376,7 +113917,7 @@ SQLITE_PRIVATE void sqlite3Update(
*/
testcase( i==31 );
testcase( i==32 );
- sqlite3ExprCodeGetColumnToReg(pParse, pTab, i, iDataCur, regNew+i);
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i);
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
}
@@ -120418,14 +113959,13 @@ SQLITE_PRIVATE void sqlite3Update(
}
if( !isView ){
- int addr1 = 0; /* Address of jump instruction */
+ int j1 = 0; /* Address of jump instruction */
int bReplace = 0; /* True if REPLACE conflict resolution might happen */
/* Do constraint checks. */
assert( regOldRowid>0 );
sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
- regNewRowid, regOldRowid, chngKey, onError, labelContinue, &bReplace,
- aXRef);
+ regNewRowid, regOldRowid, chngKey, onError, labelContinue, &bReplace);
/* Do FK constraint checks. */
if( hasFK ){
@@ -120435,39 +113975,20 @@ SQLITE_PRIVATE void sqlite3Update(
/* Delete the index entries associated with the current record. */
if( bReplace || chngKey ){
if( pPk ){
- addr1 = sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, 0, regKey, nKey);
+ j1 = sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, 0, regKey, nKey);
}else{
- addr1 = sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, 0, regOldRowid);
+ j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, 0, regOldRowid);
}
VdbeCoverageNeverTaken(v);
}
- sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx, -1);
-
- /* If changing the rowid value, or if there are foreign key constraints
- ** to process, delete the old record. Otherwise, add a noop OP_Delete
- ** to invoke the pre-update hook.
- **
- ** That (regNew==regnewRowid+1) is true is also important for the
- ** pre-update hook. If the caller invokes preupdate_new(), the returned
- ** value is copied from memory cell (regNewRowid+1+iCol), where iCol
- ** is the column index supplied by the user.
- */
- assert( regNew==regNewRowid+1 );
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
- sqlite3VdbeAddOp3(v, OP_Delete, iDataCur,
- OPFLAG_ISUPDATE | ((hasFK || chngKey || pPk!=0) ? 0 : OPFLAG_ISNOOP),
- regNewRowid
- );
- if( !pParse->nested ){
- sqlite3VdbeChangeP4(v, -1, (char*)pTab, P4_TABLE);
- }
-#else
+ sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx);
+
+ /* If changing the record number, delete the old record. */
if( hasFK || chngKey || pPk!=0 ){
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0);
}
-#endif
if( bReplace || chngKey ){
- sqlite3VdbeJumpHere(v, addr1);
+ sqlite3VdbeJumpHere(v, j1);
}
if( hasFK ){
@@ -120504,7 +114025,7 @@ SQLITE_PRIVATE void sqlite3Update(
sqlite3VdbeResolveLabel(v, labelContinue);
sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v);
}else{
- sqlite3VdbeGoto(v, labelContinue);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, labelContinue);
}
sqlite3VdbeResolveLabel(v, labelBreak);
@@ -120558,23 +114079,21 @@ update_cleanup:
/*
** Generate code for an UPDATE of a virtual table.
**
-** There are two possible strategies - the default and the special
-** "onepass" strategy. Onepass is only used if the virtual table
-** implementation indicates that pWhere may match at most one row.
-**
-** The default strategy is to create an ephemeral table that contains
+** The strategy is that we create an ephemeral table that contains
** for each row to be changed:
**
** (A) The original rowid of that row.
-** (B) The revised rowid for the row.
+** (B) The revised rowid for the row. (note1)
** (C) The content of every column in the row.
**
-** Then loop through the contents of this ephemeral table executing a
-** VUpdate for each row. When finished, drop the ephemeral table.
+** Then we loop over this ephemeral table and for each row in
+** the ephemeral table call VUpdate.
+**
+** When finished, drop the ephemeral table.
**
-** The "onepass" strategy does not use an ephemeral table. Instead, it
-** stores the same values (A, B and C above) in a register array and
-** makes a single invocation of VUpdate.
+** (note1) Actually, if we know in advance that (A) is always the same
+** as (B) we only store (A), then duplicate (A) when pulling
+** it out of the ephemeral table before calling VUpdate.
*/
static void updateVirtualTable(
Parse *pParse, /* The parsing context */
@@ -120587,96 +114106,68 @@ static void updateVirtualTable(
int onError /* ON CONFLICT strategy */
){
Vdbe *v = pParse->pVdbe; /* Virtual machine under construction */
+ ExprList *pEList = 0; /* The result set of the SELECT statement */
+ Select *pSelect = 0; /* The SELECT statement */
+ Expr *pExpr; /* Temporary expression */
int ephemTab; /* Table holding the result of the SELECT */
int i; /* Loop counter */
+ int addr; /* Address of top of loop */
+ int iReg; /* First register in set passed to OP_VUpdate */
sqlite3 *db = pParse->db; /* Database connection */
const char *pVTab = (const char*)sqlite3GetVTable(db, pTab);
- WhereInfo *pWInfo;
- int nArg = 2 + pTab->nCol; /* Number of arguments to VUpdate */
- int regArg; /* First register in VUpdate arg array */
- int regRec; /* Register in which to assemble record */
- int regRowid; /* Register for ephem table rowid */
- int iCsr = pSrc->a[0].iCursor; /* Cursor used for virtual table scan */
- int aDummy[2]; /* Unused arg for sqlite3WhereOkOnePass() */
- int bOnePass; /* True to use onepass strategy */
- int addr; /* Address of OP_OpenEphemeral */
-
- /* Allocate nArg registers to martial the arguments to VUpdate. Then
- ** create and open the ephemeral table in which the records created from
- ** these arguments will be temporarily stored. */
- assert( v );
- ephemTab = pParse->nTab++;
- addr= sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, nArg);
- regArg = pParse->nMem + 1;
- pParse->nMem += nArg;
- regRec = ++pParse->nMem;
- regRowid = ++pParse->nMem;
-
- /* Start scanning the virtual table */
- pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0,0,WHERE_ONEPASS_DESIRED,0);
- if( pWInfo==0 ) return;
-
- /* Populate the argument registers. */
- sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
+ SelectDest dest;
+
+ /* Construct the SELECT statement that will find the new values for
+ ** all updated rows.
+ */
+ pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, "_rowid_"));
if( pRowid ){
- sqlite3ExprCode(pParse, pRowid, regArg+1);
- }else{
- sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
+ pEList = sqlite3ExprListAppend(pParse, pEList,
+ sqlite3ExprDup(db, pRowid, 0));
}
+ assert( pTab->iPKey<0 );
for(i=0; i<pTab->nCol; i++){
if( aXRef[i]>=0 ){
- sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
+ pExpr = sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0);
}else{
- sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
- }
- }
-
- bOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
-
- if( bOnePass ){
- /* If using the onepass strategy, no-op out the OP_OpenEphemeral coded
- ** above. Also, if this is a top-level parse (not a trigger), clear the
- ** multi-write flag so that the VM does not open a statement journal */
- sqlite3VdbeChangeToNoop(v, addr);
- if( sqlite3IsToplevel(pParse) ){
- pParse->isMultiWrite = 0;
+ pExpr = sqlite3Expr(db, TK_ID, pTab->aCol[i].zName);
}
- }else{
- /* Create a record from the argument register contents and insert it into
- ** the ephemeral table. */
- sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec);
- sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid);
- sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid);
+ pEList = sqlite3ExprListAppend(pParse, pEList, pExpr);
}
+ pSelect = sqlite3SelectNew(pParse, pEList, pSrc, pWhere, 0, 0, 0, 0, 0, 0);
+
+ /* Create the ephemeral table into which the update results will
+ ** be stored.
+ */
+ assert( v );
+ ephemTab = pParse->nTab++;
+ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, pTab->nCol+1+(pRowid!=0));
+ sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
+ /* fill the ephemeral table
+ */
+ sqlite3SelectDestInit(&dest, SRT_Table, ephemTab);
+ sqlite3Select(pParse, pSelect, &dest);
- if( bOnePass==0 ){
- /* End the virtual table scan */
- sqlite3WhereEnd(pWInfo);
-
- /* Begin scannning through the ephemeral table. */
- addr = sqlite3VdbeAddOp1(v, OP_Rewind, ephemTab); VdbeCoverage(v);
-
- /* Extract arguments from the current row of the ephemeral table and
- ** invoke the VUpdate method. */
- for(i=0; i<nArg; i++){
- sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i, regArg+i);
- }
+ /* Generate code to scan the ephemeral table and call VUpdate. */
+ iReg = ++pParse->nMem;
+ pParse->nMem += pTab->nCol+1;
+ addr = sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0); VdbeCoverage(v);
+ sqlite3VdbeAddOp3(v, OP_Column, ephemTab, 0, iReg);
+ sqlite3VdbeAddOp3(v, OP_Column, ephemTab, (pRowid?1:0), iReg+1);
+ for(i=0; i<pTab->nCol; i++){
+ sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i+1+(pRowid!=0), iReg+2+i);
}
sqlite3VtabMakeWritable(pParse, pTab);
- sqlite3VdbeAddOp4(v, OP_VUpdate, 0, nArg, regArg, pVTab, P4_VTAB);
+ sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVTab, P4_VTAB);
sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError);
sqlite3MayAbort(pParse);
+ sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); VdbeCoverage(v);
+ sqlite3VdbeJumpHere(v, addr);
+ sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);
- /* End of the ephemeral table scan. Or, if using the onepass strategy,
- ** jump to here if the scan visited zero rows. */
- if( bOnePass==0 ){
- sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); VdbeCoverage(v);
- sqlite3VdbeJumpHere(v, addr);
- sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);
- }else{
- sqlite3WhereEnd(pWInfo);
- }
+ /* Cleanup */
+ sqlite3SelectDelete(db, pSelect);
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -120698,8 +114189,6 @@ static void updateVirtualTable(
** Most of the code in this file may be omitted by defining the
** SQLITE_OMIT_VACUUM macro.
*/
-/* #include "sqliteInt.h" */
-/* #include "vdbeInt.h" */
#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
/*
@@ -120722,7 +114211,7 @@ static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
sqlite3_stmt *pStmt;
VVA_ONLY( int rc; )
if( !zSql ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
@@ -120903,7 +114392,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|| (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0))
|| NEVER(db->mallocFailed)
){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
goto end_of_vacuum;
}
@@ -121072,7 +114561,6 @@ end_of_vacuum:
** This file contains code used to help implement virtual tables.
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
-/* #include "sqliteInt.h" */
/*
** Before a virtual table xCreate() or xConnect() method is invoked, the
@@ -121109,7 +114597,7 @@ static int createModule(
rc = SQLITE_MISUSE_BKPT;
}else{
Module *pMod;
- pMod = (Module *)sqlite3DbMallocRawNN(db, sizeof(Module) + nName + 1);
+ pMod = (Module *)sqlite3DbMallocRaw(db, sizeof(Module) + nName + 1);
if( pMod ){
Module *pDel;
char *zCopy = (char *)(&pMod[1]);
@@ -121118,11 +114606,10 @@ static int createModule(
pMod->pModule = pModule;
pMod->pAux = pAux;
pMod->xDestroy = xDestroy;
- pMod->pEpoTab = 0;
pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod);
assert( pDel==0 || pDel==pMod );
if( pDel ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
sqlite3DbFree(db, pDel);
}
}
@@ -121346,17 +114833,23 @@ SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){
** deleted.
*/
static void addModuleArgument(sqlite3 *db, Table *pTable, char *zArg){
- int nBytes = sizeof(char *)*(2+pTable->nModuleArg);
+ int i = pTable->nModuleArg++;
+ int nBytes = sizeof(char *)*(1+pTable->nModuleArg);
char **azModuleArg;
azModuleArg = sqlite3DbRealloc(db, pTable->azModuleArg, nBytes);
if( azModuleArg==0 ){
+ int j;
+ for(j=0; j<i; j++){
+ sqlite3DbFree(db, pTable->azModuleArg[j]);
+ }
sqlite3DbFree(db, zArg);
+ sqlite3DbFree(db, pTable->azModuleArg);
+ pTable->nModuleArg = 0;
}else{
- int i = pTable->nModuleArg++;
azModuleArg[i] = zArg;
azModuleArg[i+1] = 0;
- pTable->azModuleArg = azModuleArg;
}
+ pTable->azModuleArg = azModuleArg;
}
/*
@@ -121483,7 +114976,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
iReg = ++pParse->nMem;
- sqlite3VdbeLoadString(v, iReg, pTab->zName);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, iReg, 0, pTab->zName, 0);
sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg);
}
@@ -121499,7 +114992,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
assert( sqlite3SchemaMutexHeld(db, 0, pSchema) );
pOld = sqlite3HashInsert(&pSchema->tblHash, zName, pTab);
if( pOld ){
- sqlite3OomFault(db);
+ db->mallocFailed = 1;
assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */
return;
}
@@ -121566,13 +115059,13 @@ static int vtabCallConstructor(
zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
if( !zModuleName ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
pVTable = sqlite3DbMallocZero(db, sizeof(VTable));
if( !pVTable ){
sqlite3DbFree(db, zModuleName);
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
pVTable->db = db;
pVTable->pMod = pMod;
@@ -121590,7 +115083,7 @@ static int vtabCallConstructor(
db->pVtabCtx = &sCtx;
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
db->pVtabCtx = sCtx.pPrior;
- if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
+ if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
assert( sCtx.pTab==pTab );
if( SQLITE_OK!=rc ){
@@ -121624,16 +115117,22 @@ static int vtabCallConstructor(
pTab->pVTable = pVTable;
for(iCol=0; iCol<pTab->nCol; iCol++){
- char *zType = sqlite3ColumnType(&pTab->aCol[iCol], "");
+ char *zType = pTab->aCol[iCol].zType;
int nType;
int i = 0;
+ if( !zType ){
+ pTab->tabFlags |= oooHidden;
+ continue;
+ }
nType = sqlite3Strlen30(zType);
- for(i=0; i<nType; i++){
- if( 0==sqlite3StrNICmp("hidden", &zType[i], 6)
- && (i==0 || zType[i-1]==' ')
- && (zType[i+6]=='\0' || zType[i+6]==' ')
- ){
- break;
+ if( sqlite3StrNICmp("hidden", zType, 6)||(zType[6] && zType[6]!=' ') ){
+ for(i=0; i<nType; i++){
+ if( (0==sqlite3StrNICmp(" hidden", &zType[i], 7))
+ && (zType[i+7]=='\0' || zType[i+7]==' ')
+ ){
+ i++;
+ break;
+ }
}
}
if( i<nType ){
@@ -121709,7 +115208,7 @@ static int growVTrans(sqlite3 *db){
int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR);
aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes);
if( !aVTrans ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
memset(&aVTrans[db->nVTrans], 0, sizeof(sqlite3_vtab *)*ARRAY_INCR);
db->aVTrans = aVTrans;
@@ -121753,7 +115252,7 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab,
** invoke it now. If the module has not been registered, return an
** error. Otherwise, do nothing.
*/
- if( pMod==0 || pMod->pModule->xCreate==0 || pMod->pModule->xDestroy==0 ){
+ if( !pMod ){
*pzErr = sqlite3MPrintf(db, "no such module: %s", zMod);
rc = SQLITE_ERROR;
}else{
@@ -121801,7 +115300,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3 *db, const char *zCre
pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
if( pParse==0 ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}else{
pParse->declareVtab = 1;
pParse->db = db;
@@ -121855,7 +115354,6 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){
VTable *p;
- int (*xDestroy)(sqlite3_vtab *);
for(p=pTab->pVTable; p; p=p->pNext){
assert( p->pVtab );
if( p->pVtab->nRef>0 ){
@@ -121863,9 +115361,7 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab
}
}
p = vtabDisconnectAll(db, pTab);
- xDestroy = p->pMod->pModule->xDestroy;
- assert( xDestroy!=0 ); /* Checked before the virtual table is created */
- rc = xDestroy(p->pVtab);
+ rc = p->pMod->pModule->xDestroy(p->pVtab);
/* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
if( rc==SQLITE_OK ){
assert( pTab->pVTable==p && p->pNext==0 );
@@ -121889,10 +115385,8 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab
static void callFinaliser(sqlite3 *db, int offset){
int i;
if( db->aVTrans ){
- VTable **aVTrans = db->aVTrans;
- db->aVTrans = 0;
for(i=0; i<db->nVTrans; i++){
- VTable *pVTab = aVTrans[i];
+ VTable *pVTab = db->aVTrans[i];
sqlite3_vtab *p = pVTab->pVtab;
if( p ){
int (*x)(sqlite3_vtab *);
@@ -121902,8 +115396,9 @@ static void callFinaliser(sqlite3 *db, int offset){
pVTab->iSavepoint = 0;
sqlite3VtabUnlock(pVTab);
}
- sqlite3DbFree(db, aVTrans);
+ sqlite3DbFree(db, db->aVTrans);
db->nVTrans = 0;
+ db->aVTrans = 0;
}
}
@@ -121991,9 +115486,7 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
if( rc==SQLITE_OK ){
rc = pModule->xBegin(pVTab->pVtab);
if( rc==SQLITE_OK ){
- int iSvpt = db->nStatement + db->nSavepoint;
addToVTrans(db, pVTab);
- if( iSvpt ) rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, iSvpt-1);
}
}
}
@@ -122070,7 +115563,7 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(
Table *pTab;
sqlite3_vtab *pVtab;
sqlite3_module *pMod;
- void (*xSFunc)(sqlite3_context*,int,sqlite3_value**) = 0;
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**) = 0;
void *pArg = 0;
FuncDef *pNew;
int rc = 0;
@@ -122098,7 +115591,7 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(
for(z=(unsigned char*)zLowerName; *z; z++){
*z = sqlite3UpperToLower[*z];
}
- rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xSFunc, &pArg);
+ rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xFunc, &pArg);
sqlite3DbFree(db, zLowerName);
}
if( rc==0 ){
@@ -122113,9 +115606,9 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(
return pDef;
}
*pNew = *pDef;
- pNew->zName = (const char*)&pNew[1];
- memcpy((char*)&pNew[1], pDef->zName, sqlite3Strlen30(pDef->zName)+1);
- pNew->xSFunc = xSFunc;
+ pNew->zName = (char *)&pNew[1];
+ memcpy(pNew->zName, pDef->zName, sqlite3Strlen30(pDef->zName)+1);
+ pNew->xFunc = xFunc;
pNew->pUserData = pArg;
pNew->funcFlags |= SQLITE_FUNC_EPHEM;
return pNew;
@@ -122142,68 +115635,7 @@ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
pToplevel->apVtabLock = apVtabLock;
pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab;
}else{
- sqlite3OomFault(pToplevel->db);
- }
-}
-
-/*
-** Check to see if virtual tale module pMod can be have an eponymous
-** virtual table instance. If it can, create one if one does not already
-** exist. Return non-zero if the eponymous virtual table instance exists
-** when this routine returns, and return zero if it does not exist.
-**
-** An eponymous virtual table instance is one that is named after its
-** module, and more importantly, does not require a CREATE VIRTUAL TABLE
-** statement in order to come into existance. Eponymous virtual table
-** instances always exist. They cannot be DROP-ed.
-**
-** Any virtual table module for which xConnect and xCreate are the same
-** method can have an eponymous virtual table instance.
-*/
-SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){
- const sqlite3_module *pModule = pMod->pModule;
- Table *pTab;
- char *zErr = 0;
- int nName;
- int rc;
- sqlite3 *db = pParse->db;
- if( pMod->pEpoTab ) return 1;
- if( pModule->xCreate!=0 && pModule->xCreate!=pModule->xConnect ) return 0;
- nName = sqlite3Strlen30(pMod->zName) + 1;
- pTab = sqlite3DbMallocZero(db, sizeof(Table) + nName);
- if( pTab==0 ) return 0;
- pMod->pEpoTab = pTab;
- pTab->zName = (char*)&pTab[1];
- memcpy(pTab->zName, pMod->zName, nName);
- pTab->nRef = 1;
- pTab->pSchema = db->aDb[0].pSchema;
- pTab->tabFlags |= TF_Virtual;
- pTab->nModuleArg = 0;
- pTab->iPKey = -1;
- addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName));
- addModuleArgument(db, pTab, 0);
- addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName));
- rc = vtabCallConstructor(db, pTab, pMod, pModule->xConnect, &zErr);
- if( rc ){
- sqlite3ErrorMsg(pParse, "%s", zErr);
- sqlite3DbFree(db, zErr);
- sqlite3VtabEponymousTableClear(db, pMod);
- return 0;
- }
- return 1;
-}
-
-/*
-** Erase the eponymous virtual table instance associated with
-** virtual table module pMod, if it exists.
-*/
-SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){
- Table *pTab = pMod->pEpoTab;
- if( pTab!=0 ){
- sqlite3DeleteColumnNames(db, pTab);
- sqlite3VtabClear(db, pTab);
- sqlite3DbFree(db, pTab);
- pMod->pEpoTab = 0;
+ pToplevel->db->mallocFailed = 1;
}
}
@@ -122266,9 +115698,9 @@ SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3 *db, int op, ...){
#endif /* SQLITE_OMIT_VIRTUALTABLE */
/************** End of vtab.c ************************************************/
-/************** Begin file wherecode.c ***************************************/
+/************** Begin file where.c *******************************************/
/*
-** 2015-06-06
+** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -122279,15 +115711,13 @@ SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3 *db, int op, ...){
**
*************************************************************************
** This module contains C code that generates VDBE code used to process
-** the WHERE clause of SQL statements.
-**
-** This file was split off from where.c on 2015-06-06 in order to reduce the
-** size of where.c and make it easier to edit. This file contains the routines
-** that actually generate the bulk of the WHERE loop code. The original where.c
-** file retains the code that does query planning and analysis.
+** the WHERE clause of SQL statements. This module is responsible for
+** generating the code that loops through a table looking for applicable
+** rows. Indices are selected and used to speed the search when doing
+** so is applicable. Because this module is responsible for selecting
+** indices, you might also think of this module as the "query optimizer".
*/
-/* #include "sqliteInt.h" */
-/************** Include whereInt.h in the middle of wherecode.c **************/
+/************** Include whereInt.h in the middle of where.c ******************/
/************** Begin file whereInt.h ****************************************/
/*
** 2013-11-12
@@ -122310,7 +115740,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3 *db, int op, ...){
** Trace output macros
*/
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
-/***/ int sqlite3WhereTrace;
+/***/ int sqlite3WhereTrace = 0;
#endif
#if defined(SQLITE_DEBUG) \
&& (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE))
@@ -122360,10 +115790,8 @@ struct WhereLevel {
int addrCont; /* Jump here to continue with the next loop cycle */
int addrFirst; /* First instruction of interior of the loop */
int addrBody; /* Beginning of the body of this loop */
-#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
- u32 iLikeRepCntr; /* LIKE range processing counter register (times 2) */
+ int iLikeRepCntr; /* LIKE range processing counter register */
int addrLikeRep; /* LIKE range processing address */
-#endif
u8 iFrom; /* Which entry in the FROM clause */
u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */
int p1, p2; /* Operands of the opcode used to ends the loop */
@@ -122454,6 +115882,10 @@ struct WhereOrSet {
WhereOrCost a[N_OR_COST]; /* Set of best costs */
};
+
+/* Forward declaration of methods */
+static int whereLoopResize(sqlite3*, WhereLoop*, int);
+
/*
** Each instance of this object holds a sequence of WhereLoop objects
** that implement some or all of a query plan.
@@ -122546,7 +115978,6 @@ struct WhereTerm {
u16 eOperator; /* A WO_xx value describing <op> */
u16 wtFlags; /* TERM_xxx bit flags. See below */
u8 nChild; /* Number of children that must disable us */
- u8 eMatchOp; /* Op for vtab MATCH/LIKE/GLOB/REGEXP terms */
WhereClause *pWC; /* The clause this term is part of */
Bitmask prereqRight; /* Bitmask of tables used by pExpr->pRight */
Bitmask prereqAll; /* Bitmask of tables referenced by pExpr */
@@ -122570,7 +116001,6 @@ struct WhereTerm {
#define TERM_LIKEOPT 0x100 /* Virtual terms from the LIKE optimization */
#define TERM_LIKECOND 0x200 /* Conditionally this LIKE operator term */
#define TERM_LIKE 0x400 /* The original LIKE operator */
-#define TERM_IS 0x800 /* Term.pExpr is an IS operator */
/*
** An instance of the WhereScan object is used as an iterator for locating
@@ -122579,15 +116009,13 @@ struct WhereTerm {
struct WhereScan {
WhereClause *pOrigWC; /* Original, innermost WhereClause */
WhereClause *pWC; /* WhereClause currently being scanned */
- const char *zCollName; /* Required collating sequence, if not NULL */
- Expr *pIdxExpr; /* Search for this index expression */
+ char *zCollName; /* Required collating sequence, if not NULL */
char idxaff; /* Must match this affinity, if zCollName!=NULL */
unsigned char nEquiv; /* Number of entries in aEquiv[] */
unsigned char iEquiv; /* Next unused slot in aEquiv[] */
u32 opMask; /* Acceptable operators */
int k; /* Resume scanning at this->pWC->a[this->k] */
- int aiCur[11]; /* Cursors in the equivalence class */
- i16 aiColumn[11]; /* Corresponding column number in the eq-class */
+ int aEquiv[22]; /* Cursor,Column pairs for equivalence classes */
};
/*
@@ -122665,11 +116093,6 @@ struct WhereMaskSet {
};
/*
-** Initialize a WhereMaskSet object
-*/
-#define initMaskSet(P) (P)->n=0
-
-/*
** This object is a convenience wrapper holding all information needed
** to construct WhereLoop objects for a particular query.
*/
@@ -122699,15 +116122,14 @@ struct WhereInfo {
Parse *pParse; /* Parsing and code generating context */
SrcList *pTabList; /* List of tables in the join */
ExprList *pOrderBy; /* The ORDER BY clause or NULL */
- ExprList *pDistinctSet; /* DISTINCT over all these values */
+ ExprList *pResultSet; /* Result set. DISTINCT operates on these */
WhereLoop *pLoops; /* List of all WhereLoop objects */
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
LogEst nRowOut; /* Estimated number of output rows */
- LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */
u8 sorted; /* True if really sorted (not just grouped) */
- u8 eOnePass; /* ONEPASS_OFF, or _SINGLE, or _MULTI */
+ u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */
u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */
u8 nLevel; /* Number of nested loop */
@@ -122722,92 +116144,26 @@ struct WhereInfo {
};
/*
-** Private interfaces - callable only by other where.c routines.
-**
-** where.c:
-*/
-SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet*,int);
-SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm(
- WhereClause *pWC, /* The WHERE clause to be searched */
- int iCur, /* Cursor number of LHS */
- int iColumn, /* Column number of LHS */
- Bitmask notReady, /* RHS must not overlap with this mask */
- u32 op, /* Mask of WO_xx values describing operator */
- Index *pIdx /* Must be compatible with this index, if not NULL */
-);
-
-/* wherecode.c: */
-#ifndef SQLITE_OMIT_EXPLAIN
-SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
- 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() */
-);
-#else
-# define sqlite3WhereExplainOneScan(u,v,w,x,y,z) 0
-#endif /* SQLITE_OMIT_EXPLAIN */
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
-SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
- Vdbe *v, /* Vdbe to add scanstatus entry to */
- SrcList *pSrclist, /* FROM clause pLvl reads data from */
- WhereLevel *pLvl, /* Level to add scanstatus() entry for */
- int addrExplain /* Address of OP_Explain (or 0) */
-);
-#else
-# define sqlite3WhereAddScanStatus(a, b, c, d) ((void)d)
-#endif
-SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
- WhereInfo *pWInfo, /* Complete information about the WHERE clause */
- int iLevel, /* Which level of pWInfo->a[] should be coded */
- Bitmask notReady /* Which tables are currently available */
-);
-
-/* whereexpr.c: */
-SQLITE_PRIVATE void sqlite3WhereClauseInit(WhereClause*,WhereInfo*);
-SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause*);
-SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause*,Expr*,u8);
-SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*);
-SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*);
-SQLITE_PRIVATE void sqlite3WhereExprAnalyze(SrcList*, WhereClause*);
-SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*);
-
-
-
-
-
-/*
** Bitmasks for the operators on WhereTerm objects. These are all
** operators that are of interest to the query planner. An
** OR-ed combination of these values can be used when searching for
** particular WhereTerms within a WhereClause.
-**
-** Value constraints:
-** WO_EQ == SQLITE_INDEX_CONSTRAINT_EQ
-** WO_LT == SQLITE_INDEX_CONSTRAINT_LT
-** WO_LE == SQLITE_INDEX_CONSTRAINT_LE
-** WO_GT == SQLITE_INDEX_CONSTRAINT_GT
-** WO_GE == SQLITE_INDEX_CONSTRAINT_GE
-** WO_MATCH == SQLITE_INDEX_CONSTRAINT_MATCH
*/
-#define WO_IN 0x0001
-#define WO_EQ 0x0002
+#define WO_IN 0x001
+#define WO_EQ 0x002
#define WO_LT (WO_EQ<<(TK_LT-TK_EQ))
#define WO_LE (WO_EQ<<(TK_LE-TK_EQ))
#define WO_GT (WO_EQ<<(TK_GT-TK_EQ))
#define WO_GE (WO_EQ<<(TK_GE-TK_EQ))
-#define WO_MATCH 0x0040
-#define WO_IS 0x0080
-#define WO_ISNULL 0x0100
-#define WO_OR 0x0200 /* Two or more OR-connected terms */
-#define WO_AND 0x0400 /* Two or more AND-connected terms */
-#define WO_EQUIV 0x0800 /* Of the form A==B, both columns */
-#define WO_NOOP 0x1000 /* This term does not restrict search space */
+#define WO_MATCH 0x040
+#define WO_ISNULL 0x080
+#define WO_OR 0x100 /* Two or more OR-connected terms */
+#define WO_AND 0x200 /* Two or more AND-connected terms */
+#define WO_EQUIV 0x400 /* Of the form A==B, both columns */
+#define WO_NOOP 0x800 /* This term does not restrict search space */
-#define WO_ALL 0x1fff /* Mask of all possible WO_* values */
-#define WO_SINGLE 0x01ff /* Mask of all non-compound WO_* values */
+#define WO_ALL 0xfff /* Mask of all possible WO_* values */
+#define WO_SINGLE 0x0ff /* Mask of all non-compound WO_* values */
/*
** These are definitions of bits in the WhereLoop.wsFlags field.
@@ -122835,1809 +116191,170 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
#define WHERE_PARTIALIDX 0x00020000 /* The automatic index is partial */
/************** End of whereInt.h ********************************************/
-/************** Continuing where we left off in wherecode.c ******************/
+/************** Continuing where we left off in where.c **********************/
-#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.
+** Return the estimated number of output rows from a WHERE clause
*/
-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);
- sqlite3StrAccumAppendAll(pStr, zColumn);
- sqlite3StrAccumAppend(pStr, zOp, 1);
- sqlite3StrAccumAppend(pStr, "?", 1);
+SQLITE_PRIVATE u64 sqlite3WhereOutputRowCount(WhereInfo *pWInfo){
+ return sqlite3LogEstToInt(pWInfo->nRowOut);
}
/*
-** Return the name of the i-th column of the pIdx index.
+** Return one of the WHERE_DISTINCT_xxxxx values to indicate how this
+** WHERE clause returns outputs for DISTINCT processing.
*/
-static const char *explainIndexColumnName(Index *pIdx, int i){
- i = pIdx->aiColumn[i];
- if( i==XN_EXPR ) return "<expr>";
- if( i==XN_ROWID ) return "rowid";
- return pIdx->pTable->aCol[i].zName;
+SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo *pWInfo){
+ return pWInfo->eDistinct;
}
/*
-** Argument pLevel describes a strategy for scanning table pTab. This
-** function appends text to pStr that describes the subset of table
-** rows scanned by the strategy in the form of an SQL expression.
-**
-** For example, if the query:
-**
-** 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>?"
+** Return TRUE if the WHERE clause returns rows in ORDER BY order.
+** Return FALSE if the output needs to be sorted.
*/
-static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){
- Index *pIndex = pLoop->u.btree.pIndex;
- u16 nEq = pLoop->u.btree.nEq;
- u16 nSkip = pLoop->nSkip;
- int i, j;
-
- if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return;
- sqlite3StrAccumAppend(pStr, " (", 2);
- for(i=0; i<nEq; i++){
- const char *z = explainIndexColumnName(pIndex, i);
- if( i ) sqlite3StrAccumAppend(pStr, " AND ", 5);
- sqlite3XPrintf(pStr, i>=nSkip ? "%s=?" : "ANY(%s)", z);
- }
-
- j = i;
- if( pLoop->wsFlags&WHERE_BTM_LIMIT ){
- const char *z = explainIndexColumnName(pIndex, i);
- explainAppendTerm(pStr, i++, z, ">");
- }
- if( pLoop->wsFlags&WHERE_TOP_LIMIT ){
- const char *z = explainIndexColumnName(pIndex, j);
- explainAppendTerm(pStr, i, z, "<");
- }
- sqlite3StrAccumAppend(pStr, ")", 1);
+SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
+ return pWInfo->nOBSat;
}
/*
-** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
-** command, or if either SQLITE_DEBUG or SQLITE_ENABLE_STMT_SCANSTATUS was
-** defined at compile-time. If it is not a no-op, a single OP_Explain opcode
-** is added to the output to describe the table scan strategy in pLevel.
-**
-** If an OP_Explain opcode is added to the VM, its address is returned.
-** Otherwise, if no OP_Explain is coded, zero is returned.
+** Return the VDBE address or label to jump to in order to continue
+** immediately with the next row of a WHERE clause.
*/
-SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
- 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() */
-){
- int ret = 0;
-#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
- if( pParse->explain==2 )
-#endif
- {
- struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
- Vdbe *v = pParse->pVdbe; /* VM being constructed */
- sqlite3 *db = pParse->db; /* Database handle */
- int iId = pParse->iSelectId; /* Select id (left-most output column) */
- int isSearch; /* True for a SEARCH. False for SCAN. */
- WhereLoop *pLoop; /* The controlling WhereLoop object */
- u32 flags; /* Flags that describe this loop */
- char *zMsg; /* Text to add to EQP output */
- StrAccum str; /* EQP output string */
- char zBuf[100]; /* Initial space for EQP output string */
-
- pLoop = pLevel->pWLoop;
- flags = pLoop->wsFlags;
- if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return 0;
-
- isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0
- || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0))
- || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX));
-
- sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
- sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN");
- if( pItem->pSelect ){
- sqlite3XPrintf(&str, " SUBQUERY %d", pItem->iSelectId);
- }else{
- sqlite3XPrintf(&str, " TABLE %s", pItem->zName);
- }
-
- if( pItem->zAlias ){
- sqlite3XPrintf(&str, " AS %s", pItem->zAlias);
- }
- if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){
- const char *zFmt = 0;
- Index *pIdx;
-
- assert( pLoop->u.btree.pIndex!=0 );
- pIdx = pLoop->u.btree.pIndex;
- assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) );
- if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){
- if( isSearch ){
- zFmt = "PRIMARY KEY";
- }
- }else if( flags & WHERE_PARTIALIDX ){
- zFmt = "AUTOMATIC PARTIAL COVERING INDEX";
- }else if( flags & WHERE_AUTO_INDEX ){
- zFmt = "AUTOMATIC COVERING INDEX";
- }else if( flags & WHERE_IDX_ONLY ){
- zFmt = "COVERING INDEX %s";
- }else{
- zFmt = "INDEX %s";
- }
- if( zFmt ){
- sqlite3StrAccumAppend(&str, " USING ", 7);
- sqlite3XPrintf(&str, zFmt, pIdx->zName);
- explainIndexRange(&str, pLoop);
- }
- }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){
- const char *zRangeOp;
- if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){
- zRangeOp = "=";
- }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){
- zRangeOp = ">? AND rowid<";
- }else if( flags&WHERE_BTM_LIMIT ){
- zRangeOp = ">";
- }else{
- assert( flags&WHERE_TOP_LIMIT);
- zRangeOp = "<";
- }
- sqlite3XPrintf(&str, " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp);
- }
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
- sqlite3XPrintf(&str, " VIRTUAL TABLE INDEX %d:%s",
- pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
- }
-#endif
-#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
- if( pLoop->nOut>=10 ){
- sqlite3XPrintf(&str, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut));
- }else{
- sqlite3StrAccumAppend(&str, " (~1 row)", 9);
- }
-#endif
- zMsg = sqlite3StrAccumFinish(&str);
- ret = sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg,P4_DYNAMIC);
- }
- return ret;
+SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo *pWInfo){
+ assert( pWInfo->iContinue!=0 );
+ return pWInfo->iContinue;
}
-#endif /* SQLITE_OMIT_EXPLAIN */
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
/*
-** Configure the VM passed as the first argument with an
-** sqlite3_stmt_scanstatus() entry corresponding to the scan used to
-** implement level pLvl. Argument pSrclist is a pointer to the FROM
-** clause that the scan reads data from.
-**
-** If argument addrExplain is not 0, it must be the address of an
-** OP_Explain instruction that describes the same loop.
+** Return the VDBE address or label to jump to in order to break
+** out of a WHERE loop.
*/
-SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
- Vdbe *v, /* Vdbe to add scanstatus entry to */
- SrcList *pSrclist, /* FROM clause pLvl reads data from */
- WhereLevel *pLvl, /* Level to add scanstatus() entry for */
- int addrExplain /* Address of OP_Explain (or 0) */
-){
- const char *zObj = 0;
- WhereLoop *pLoop = pLvl->pWLoop;
- if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){
- zObj = pLoop->u.btree.pIndex->zName;
- }else{
- zObj = pSrclist->a[pLvl->iFrom].zName;
- }
- sqlite3VdbeScanStatus(
- v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj
- );
+SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo *pWInfo){
+ return pWInfo->iBreak;
}
-#endif
-
/*
-** Disable a term in the WHERE clause. Except, do not disable the term
-** if it controls a LEFT OUTER JOIN and it did not originate in the ON
-** or USING clause of that join.
-**
-** Consider the term t2.z='ok' in the following queries:
-**
-** (1) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x WHERE t2.z='ok'
-** (2) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x AND t2.z='ok'
-** (3) SELECT * FROM t1, t2 WHERE t1.a=t2.x AND t2.z='ok'
-**
-** The t2.z='ok' is disabled in the in (2) because it originates
-** in the ON clause. The term is disabled in (3) because it is not part
-** of a LEFT OUTER JOIN. In (1), the term is not disabled.
-**
-** Disabling a term causes that term to not be tested in the inner loop
-** of the join. Disabling is an optimization. When terms are satisfied
-** by indices, we disable them to prevent redundant tests in the inner
-** loop. We would get the correct results if nothing were ever disabled,
-** but joins might run a little slower. The trick is to disable as much
-** as we can without disabling too much. If we disabled in (1), we'd get
-** the wrong answer. See ticket #813.
-**
-** If all the children of a term are disabled, then that term is also
-** automatically disabled. In this way, terms get disabled if derived
-** virtual terms are tested first. For example:
-**
-** x GLOB 'abc*' AND x>='abc' AND x<'acd'
-** \___________/ \______/ \_____/
-** parent child1 child2
+** Return TRUE if an UPDATE or DELETE statement can operate directly on
+** the rowids returned by a WHERE clause. Return FALSE if doing an
+** UPDATE or DELETE might change subsequent WHERE clause results.
**
-** Only the parent term was in the original WHERE clause. The child1
-** and child2 terms were added by the LIKE optimization. If both of
-** the virtual child terms are valid, then testing of the parent can be
-** skipped.
+** If the ONEPASS optimization is used (if this routine returns true)
+** then also write the indices of open cursors used by ONEPASS
+** into aiCur[0] and aiCur[1]. iaCur[0] gets the cursor of the data
+** table and iaCur[1] gets the cursor used by an auxiliary index.
+** Either value may be -1, indicating that cursor is not used.
+** Any cursors returned will have been opened for writing.
**
-** Usually the parent term is marked as TERM_CODED. But if the parent
-** term was originally TERM_LIKE, then the parent gets TERM_LIKECOND instead.
-** The TERM_LIKECOND marking indicates that the term should be coded inside
-** a conditional such that is only evaluated on the second pass of a
-** LIKE-optimization loop, when scanning BLOBs instead of strings.
+** aiCur[0] and aiCur[1] both get -1 if the where-clause logic is
+** unable to use the ONEPASS optimization.
*/
-static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
- int nLoop = 0;
- while( pTerm
- && (pTerm->wtFlags & TERM_CODED)==0
- && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
- && (pLevel->notReady & pTerm->prereqAll)==0
- ){
- if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){
- pTerm->wtFlags |= TERM_LIKECOND;
- }else{
- pTerm->wtFlags |= TERM_CODED;
- }
- if( pTerm->iParent<0 ) break;
- pTerm = &pTerm->pWC->a[pTerm->iParent];
- pTerm->nChild--;
- if( pTerm->nChild!=0 ) break;
- nLoop++;
- }
+SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo *pWInfo, int *aiCur){
+ memcpy(aiCur, pWInfo->aiCurOnePass, sizeof(int)*2);
+ return pWInfo->okOnePass;
}
/*
-** Code an OP_Affinity opcode to apply the column affinity string zAff
-** to the n registers starting at base.
-**
-** As an optimization, SQLITE_AFF_BLOB entries (which are no-ops) at the
-** beginning and end of zAff are ignored. If all entries in zAff are
-** SQLITE_AFF_BLOB, then no code gets generated.
-**
-** This routine makes its own copy of zAff so that the caller is free
-** to modify zAff after this routine returns.
+** Move the content of pSrc into pDest
*/
-static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){
- Vdbe *v = pParse->pVdbe;
- if( zAff==0 ){
- assert( pParse->db->mallocFailed );
- return;
- }
- assert( v!=0 );
-
- /* Adjust base and n to skip over SQLITE_AFF_BLOB entries at the beginning
- ** and end of the affinity string.
- */
- while( n>0 && zAff[0]==SQLITE_AFF_BLOB ){
- n--;
- base++;
- zAff++;
- }
- while( n>1 && zAff[n-1]==SQLITE_AFF_BLOB ){
- n--;
- }
-
- /* Code the OP_Affinity opcode if there is anything left to do. */
- if( n>0 ){
- sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n);
- sqlite3ExprCacheAffinityChange(pParse, base, n);
- }
+static void whereOrMove(WhereOrSet *pDest, WhereOrSet *pSrc){
+ pDest->n = pSrc->n;
+ memcpy(pDest->a, pSrc->a, pDest->n*sizeof(pDest->a[0]));
}
-
/*
-** Generate code for a single equality term of the WHERE clause. An equality
-** term can be either X=expr or X IN (...). pTerm is the term to be
-** coded.
-**
-** The current value for the constraint is left in register iReg.
+** Try to insert a new prerequisite/cost entry into the WhereOrSet pSet.
**
-** For a constraint of the form X=expr, the expression is evaluated and its
-** result is left on the stack. For constraints of the form X IN (...)
-** this routine sets up a loop that will iterate over all values of X.
+** The new entry might overwrite an existing entry, or it might be
+** appended, or it might be discarded. Do whatever is the right thing
+** so that pSet keeps the N_OR_COST best entries seen so far.
*/
-static int codeEqualityTerm(
- Parse *pParse, /* The parsing context */
- WhereTerm *pTerm, /* The term of the WHERE clause to be coded */
- WhereLevel *pLevel, /* The level of the FROM clause we are working on */
- int iEq, /* Index of the equality term within this level */
- int bRev, /* True for reverse-order IN operations */
- int iTarget /* Attempt to leave results in this register */
+static int whereOrInsert(
+ WhereOrSet *pSet, /* The WhereOrSet to be updated */
+ Bitmask prereq, /* Prerequisites of the new entry */
+ LogEst rRun, /* Run-cost of the new entry */
+ LogEst nOut /* Number of outputs for the new entry */
){
- Expr *pX = pTerm->pExpr;
- Vdbe *v = pParse->pVdbe;
- int iReg; /* Register holding results */
-
- assert( iTarget>0 );
- if( pX->op==TK_EQ || pX->op==TK_IS ){
- iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget);
- }else if( pX->op==TK_ISNULL ){
- iReg = iTarget;
- sqlite3VdbeAddOp2(v, OP_Null, 0, iReg);
-#ifndef SQLITE_OMIT_SUBQUERY
- }else{
- int eType;
- int iTab;
- struct InLoop *pIn;
- WhereLoop *pLoop = pLevel->pWLoop;
-
- if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0
- && pLoop->u.btree.pIndex!=0
- && pLoop->u.btree.pIndex->aSortOrder[iEq]
- ){
- testcase( iEq==0 );
- testcase( bRev );
- bRev = !bRev;
- }
- assert( pX->op==TK_IN );
- iReg = iTarget;
- eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0);
- if( eType==IN_INDEX_INDEX_DESC ){
- testcase( bRev );
- bRev = !bRev;
- }
- iTab = pX->iTable;
- sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
- VdbeCoverageIf(v, bRev);
- VdbeCoverageIf(v, !bRev);
- assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 );
- pLoop->wsFlags |= WHERE_IN_ABLE;
- if( pLevel->u.in.nIn==0 ){
- pLevel->addrNxt = sqlite3VdbeMakeLabel(v);
+ u16 i;
+ WhereOrCost *p;
+ for(i=pSet->n, p=pSet->a; i>0; i--, p++){
+ if( rRun<=p->rRun && (prereq & p->prereq)==prereq ){
+ goto whereOrInsert_done;
}
- pLevel->u.in.nIn++;
- pLevel->u.in.aInLoop =
- sqlite3DbReallocOrFree(pParse->db, pLevel->u.in.aInLoop,
- sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn);
- pIn = pLevel->u.in.aInLoop;
- if( pIn ){
- pIn += pLevel->u.in.nIn - 1;
- pIn->iCur = iTab;
- if( eType==IN_INDEX_ROWID ){
- pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg);
- }else{
- pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg);
- }
- pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen;
- sqlite3VdbeAddOp1(v, OP_IsNull, iReg); VdbeCoverage(v);
- }else{
- pLevel->u.in.nIn = 0;
+ if( p->rRun<=rRun && (p->prereq & prereq)==p->prereq ){
+ return 0;
}
-#endif
}
- disableTerm(pLevel, pTerm);
- return iReg;
-}
-
-/*
-** Generate code that will evaluate all == and IN constraints for an
-** index scan.
-**
-** For example, consider table t1(a,b,c,d,e,f) with index i1(a,b,c).
-** Suppose the WHERE clause is this: a==5 AND b IN (1,2,3) AND c>5 AND c<10
-** The index has as many as three equality constraints, but in this
-** example, the third "c" value is an inequality. So only two
-** constraints are coded. This routine will generate code to evaluate
-** a==5 and b IN (1,2,3). The current values for a and b will be stored
-** in consecutive registers and the index of the first register is returned.
-**
-** In the example above nEq==2. But this subroutine works for any value
-** of nEq including 0. If nEq==0, this routine is nearly a no-op.
-** The only thing it does is allocate the pLevel->iMem memory cell and
-** compute the affinity string.
-**
-** The nExtraReg parameter is 0 or 1. It is 0 if all WHERE clause constraints
-** are == or IN and are covered by the nEq. nExtraReg is 1 if there is
-** an inequality constraint (such as the "c>=5 AND c<10" in the example) that
-** occurs after the nEq quality constraints.
-**
-** This routine allocates a range of nEq+nExtraReg memory cells and returns
-** the index of the first memory cell in that range. The code that
-** calls this routine will use that memory range to store keys for
-** start and termination conditions of the loop.
-** key value of the loop. If one or more IN operators appear, then
-** this routine allocates an additional nEq memory cells for internal
-** use.
-**
-** Before returning, *pzAff is set to point to a buffer containing a
-** copy of the column affinity string of the index allocated using
-** sqlite3DbMalloc(). Except, entries in the copy of the string associated
-** with equality constraints that use BLOB or NONE affinity are set to
-** SQLITE_AFF_BLOB. This is to deal with SQL such as the following:
-**
-** CREATE TABLE t1(a TEXT PRIMARY KEY, b);
-** SELECT ... FROM t1 AS t2, t1 WHERE t1.a = t2.b;
-**
-** In the example above, the index on t1(a) has TEXT affinity. But since
-** the right hand side of the equality constraint (t2.b) has BLOB/NONE affinity,
-** no conversion should be attempted before using a t2.b value as part of
-** a key to search the index. Hence the first byte in the returned affinity
-** string in this example would be set to SQLITE_AFF_BLOB.
-*/
-static int codeAllEqualityTerms(
- Parse *pParse, /* Parsing context */
- WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */
- int bRev, /* Reverse the order of IN operators */
- int nExtraReg, /* Number of extra registers to allocate */
- char **pzAff /* OUT: Set to point to affinity string */
-){
- u16 nEq; /* The number of == or IN constraints to code */
- u16 nSkip; /* Number of left-most columns to skip */
- Vdbe *v = pParse->pVdbe; /* The vm under construction */
- Index *pIdx; /* The index being used for this loop */
- WhereTerm *pTerm; /* A single constraint term */
- WhereLoop *pLoop; /* The WhereLoop object */
- int j; /* Loop counter */
- int regBase; /* Base register */
- int nReg; /* Number of registers to allocate */
- char *zAff; /* Affinity string to return */
-
- /* This module is only called on query plans that use an index. */
- pLoop = pLevel->pWLoop;
- assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 );
- nEq = pLoop->u.btree.nEq;
- nSkip = pLoop->nSkip;
- pIdx = pLoop->u.btree.pIndex;
- assert( pIdx!=0 );
-
- /* Figure out how many memory cells we will need then allocate them.
- */
- regBase = pParse->nMem + 1;
- nReg = pLoop->u.btree.nEq + nExtraReg;
- pParse->nMem += nReg;
-
- zAff = sqlite3DbStrDup(pParse->db,sqlite3IndexAffinityStr(pParse->db,pIdx));
- assert( zAff!=0 || pParse->db->mallocFailed );
-
- if( nSkip ){
- int iIdxCur = pLevel->iIdxCur;
- sqlite3VdbeAddOp1(v, (bRev?OP_Last:OP_Rewind), iIdxCur);
- VdbeCoverageIf(v, bRev==0);
- VdbeCoverageIf(v, bRev!=0);
- VdbeComment((v, "begin skip-scan on %s", pIdx->zName));
- j = sqlite3VdbeAddOp0(v, OP_Goto);
- pLevel->addrSkip = sqlite3VdbeAddOp4Int(v, (bRev?OP_SeekLT:OP_SeekGT),
- iIdxCur, 0, regBase, nSkip);
- VdbeCoverageIf(v, bRev==0);
- VdbeCoverageIf(v, bRev!=0);
- sqlite3VdbeJumpHere(v, j);
- for(j=0; j<nSkip; j++){
- sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, j, regBase+j);
- testcase( pIdx->aiColumn[j]==XN_EXPR );
- VdbeComment((v, "%s", explainIndexColumnName(pIdx, j)));
- }
- }
-
- /* Evaluate the equality constraints
- */
- assert( zAff==0 || (int)strlen(zAff)>=nEq );
- for(j=nSkip; j<nEq; j++){
- int r1;
- pTerm = pLoop->aLTerm[j];
- assert( pTerm!=0 );
- /* The following testcase is true for indices with redundant columns.
- ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
- testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
- testcase( pTerm->wtFlags & TERM_VIRTUAL );
- r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, regBase+j);
- if( r1!=regBase+j ){
- if( nReg==1 ){
- sqlite3ReleaseTempReg(pParse, regBase);
- regBase = r1;
- }else{
- sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j);
- }
- }
- testcase( pTerm->eOperator & WO_ISNULL );
- testcase( pTerm->eOperator & WO_IN );
- if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
- Expr *pRight = pTerm->pExpr->pRight;
- if( (pTerm->wtFlags & TERM_IS)==0 && sqlite3ExprCanBeNull(pRight) ){
- sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk);
- VdbeCoverage(v);
- }
- if( zAff ){
- if( sqlite3CompareAffinity(pRight, zAff[j])==SQLITE_AFF_BLOB ){
- zAff[j] = SQLITE_AFF_BLOB;
- }
- if( sqlite3ExprNeedsNoAffinityChange(pRight, zAff[j]) ){
- zAff[j] = SQLITE_AFF_BLOB;
- }
- }
+ if( pSet->n<N_OR_COST ){
+ p = &pSet->a[pSet->n++];
+ p->nOut = nOut;
+ }else{
+ p = pSet->a;
+ for(i=1; i<pSet->n; i++){
+ if( p->rRun>pSet->a[i].rRun ) p = pSet->a + i;
}
+ if( p->rRun<=rRun ) return 0;
}
- *pzAff = zAff;
- return regBase;
+whereOrInsert_done:
+ p->prereq = prereq;
+ p->rRun = rRun;
+ if( p->nOut>nOut ) p->nOut = nOut;
+ return 1;
}
-#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
/*
-** If the most recently coded instruction is a constant range constraint
-** (a string literal) that originated from the LIKE optimization, then
-** set P3 and P5 on the OP_String opcode so that the string will be cast
-** to a BLOB at appropriate times.
-**
-** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range
-** expression: "x>='ABC' AND x<'abd'". But this requires that the range
-** scan loop run twice, once for strings and a second time for BLOBs.
-** The OP_String opcodes on the second pass convert the upper and lower
-** bound string contants to blobs. This routine makes the necessary changes
-** to the OP_String opcodes for that to happen.
-**
-** Except, of course, if SQLITE_LIKE_DOESNT_MATCH_BLOBS is defined, then
-** only the one pass through the string space is required, so this routine
-** becomes a no-op.
+** Initialize a preallocated WhereClause structure.
*/
-static void whereLikeOptimizationStringFixup(
- Vdbe *v, /* prepared statement under construction */
- WhereLevel *pLevel, /* The loop that contains the LIKE operator */
- WhereTerm *pTerm /* The upper or lower bound just coded */
+static void whereClauseInit(
+ WhereClause *pWC, /* The WhereClause to be initialized */
+ WhereInfo *pWInfo /* The WHERE processing context */
){
- if( pTerm->wtFlags & TERM_LIKEOPT ){
- VdbeOp *pOp;
- assert( pLevel->iLikeRepCntr>0 );
- pOp = sqlite3VdbeGetOp(v, -1);
- assert( pOp!=0 );
- assert( pOp->opcode==OP_String8
- || pTerm->pWC->pWInfo->pParse->db->mallocFailed );
- pOp->p3 = (int)(pLevel->iLikeRepCntr>>1); /* Register holding counter */
- pOp->p5 = (u8)(pLevel->iLikeRepCntr&1); /* ASC or DESC */
- }
-}
-#else
-# define whereLikeOptimizationStringFixup(A,B,C)
-#endif
-
-#ifdef SQLITE_ENABLE_CURSOR_HINTS
-/*
-** Information is passed from codeCursorHint() down to individual nodes of
-** the expression tree (by sqlite3WalkExpr()) using an instance of this
-** structure.
-*/
-struct CCurHint {
- int iTabCur; /* Cursor for the main table */
- int iIdxCur; /* Cursor for the index, if pIdx!=0. Unused otherwise */
- Index *pIdx; /* The index used to access the table */
-};
-
-/*
-** This function is called for every node of an expression that is a candidate
-** for a cursor hint on an index cursor. For TK_COLUMN nodes that reference
-** the table CCurHint.iTabCur, verify that the same column can be
-** accessed through the index. If it cannot, then set pWalker->eCode to 1.
-*/
-static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){
- struct CCurHint *pHint = pWalker->u.pCCurHint;
- assert( pHint->pIdx!=0 );
- if( pExpr->op==TK_COLUMN
- && pExpr->iTable==pHint->iTabCur
- && sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn)<0
- ){
- pWalker->eCode = 1;
- }
- return WRC_Continue;
+ pWC->pWInfo = pWInfo;
+ pWC->pOuter = 0;
+ pWC->nTerm = 0;
+ pWC->nSlot = ArraySize(pWC->aStatic);
+ pWC->a = pWC->aStatic;
}
+/* Forward reference */
+static void whereClauseClear(WhereClause*);
/*
-** This function is called on every node of an expression tree used as an
-** argument to the OP_CursorHint instruction. If the node is a TK_COLUMN
-** that accesses any table other than the one identified by
-** CCurHint.iTabCur, then do the following:
-**
-** 1) allocate a register and code an OP_Column instruction to read
-** the specified column into the new register, and
-**
-** 2) transform the expression node to a TK_REGISTER node that reads
-** from the newly populated register.
-**
-** Also, if the node is a TK_COLUMN that does access the table idenified
-** by pCCurHint.iTabCur, and an index is being used (which we will
-** know because CCurHint.pIdx!=0) then transform the TK_COLUMN into
-** an access of the index rather than the original table.
-*/
-static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
- int rc = WRC_Continue;
- struct CCurHint *pHint = pWalker->u.pCCurHint;
- if( pExpr->op==TK_COLUMN ){
- if( pExpr->iTable!=pHint->iTabCur ){
- Vdbe *v = pWalker->pParse->pVdbe;
- int reg = ++pWalker->pParse->nMem; /* Register for column value */
- sqlite3ExprCodeGetColumnOfTable(
- v, pExpr->pTab, pExpr->iTable, pExpr->iColumn, reg
- );
- pExpr->op = TK_REGISTER;
- pExpr->iTable = reg;
- }else if( pHint->pIdx!=0 ){
- pExpr->iTable = pHint->iIdxCur;
- pExpr->iColumn = sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn);
- assert( pExpr->iColumn>=0 );
- }
- }else if( pExpr->op==TK_AGG_FUNCTION ){
- /* An aggregate function in the WHERE clause of a query means this must
- ** be a correlated sub-query, and expression pExpr is an aggregate from
- ** the parent context. Do not walk the function arguments in this case.
- **
- ** todo: It should be possible to replace this node with a TK_REGISTER
- ** expression, as the result of the expression must be stored in a
- ** register at this point. The same holds for TK_AGG_COLUMN nodes. */
- rc = WRC_Prune;
- }
- return rc;
-}
-
-/*
-** Insert an OP_CursorHint instruction if it is appropriate to do so.
+** Deallocate all memory associated with a WhereOrInfo object.
*/
-static void codeCursorHint(
- WhereInfo *pWInfo, /* The where clause */
- WhereLevel *pLevel, /* Which loop to provide hints for */
- WhereTerm *pEndRange /* Hint this end-of-scan boundary term if not NULL */
-){
- Parse *pParse = pWInfo->pParse;
- sqlite3 *db = pParse->db;
- Vdbe *v = pParse->pVdbe;
- Expr *pExpr = 0;
- WhereLoop *pLoop = pLevel->pWLoop;
- int iCur;
- WhereClause *pWC;
- WhereTerm *pTerm;
- int i, j;
- struct CCurHint sHint;
- Walker sWalker;
-
- if( OptimizationDisabled(db, SQLITE_CursorHints) ) return;
- iCur = pLevel->iTabCur;
- assert( iCur==pWInfo->pTabList->a[pLevel->iFrom].iCursor );
- sHint.iTabCur = iCur;
- sHint.iIdxCur = pLevel->iIdxCur;
- sHint.pIdx = pLoop->u.btree.pIndex;
- memset(&sWalker, 0, sizeof(sWalker));
- sWalker.pParse = pParse;
- sWalker.u.pCCurHint = &sHint;
- pWC = &pWInfo->sWC;
- for(i=0; i<pWC->nTerm; i++){
- pTerm = &pWC->a[i];
- if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
- if( pTerm->prereqAll & pLevel->notReady ) continue;
- if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue;
-
- /* All terms in pWLoop->aLTerm[] except pEndRange are used to initialize
- ** the cursor. These terms are not needed as hints for a pure range
- ** scan (that has no == terms) so omit them. */
- if( pLoop->u.btree.nEq==0 && pTerm!=pEndRange ){
- for(j=0; j<pLoop->nLTerm && pLoop->aLTerm[j]!=pTerm; j++){}
- if( j<pLoop->nLTerm ) continue;
- }
-
- /* No subqueries or non-deterministic functions allowed */
- if( sqlite3ExprContainsSubquery(pTerm->pExpr) ) continue;
-
- /* For an index scan, make sure referenced columns are actually in
- ** the index. */
- if( sHint.pIdx!=0 ){
- sWalker.eCode = 0;
- sWalker.xExprCallback = codeCursorHintCheckExpr;
- sqlite3WalkExpr(&sWalker, pTerm->pExpr);
- if( sWalker.eCode ) continue;
- }
-
- /* If we survive all prior tests, that means this term is worth hinting */
- pExpr = sqlite3ExprAnd(db, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0));
- }
- if( pExpr!=0 ){
- sWalker.xExprCallback = codeCursorHintFixExpr;
- sqlite3WalkExpr(&sWalker, pExpr);
- sqlite3VdbeAddOp4(v, OP_CursorHint,
- (sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0,
- (const char*)pExpr, P4_EXPR);
- }
+static void whereOrInfoDelete(sqlite3 *db, WhereOrInfo *p){
+ whereClauseClear(&p->wc);
+ sqlite3DbFree(db, p);
}
-#else
-# define codeCursorHint(A,B,C) /* No-op */
-#endif /* SQLITE_ENABLE_CURSOR_HINTS */
/*
-** Cursor iCur is open on an intkey b-tree (a table). Register iRowid contains
-** a rowid value just read from cursor iIdxCur, open on index pIdx. This
-** function generates code to do a deferred seek of cursor iCur to the
-** rowid stored in register iRowid.
-**
-** Normally, this is just:
-**
-** OP_Seek $iCur $iRowid
-**
-** However, if the scan currently being coded is a branch of an OR-loop and
-** the statement currently being coded is a SELECT, then P3 of the OP_Seek
-** is set to iIdxCur and P4 is set to point to an array of integers
-** containing one entry for each column of the table cursor iCur is open
-** on. For each table column, if the column is the i'th column of the
-** index, then the corresponding array entry is set to (i+1). If the column
-** does not appear in the index at all, the array entry is set to 0.
+** Deallocate all memory associated with a WhereAndInfo object.
*/
-static void codeDeferredSeek(
- WhereInfo *pWInfo, /* Where clause context */
- Index *pIdx, /* Index scan is using */
- int iCur, /* Cursor for IPK b-tree */
- int iIdxCur /* Index cursor */
-){
- Parse *pParse = pWInfo->pParse; /* Parse context */
- Vdbe *v = pParse->pVdbe; /* Vdbe to generate code within */
-
- assert( iIdxCur>0 );
- assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 );
-
- sqlite3VdbeAddOp3(v, OP_Seek, iIdxCur, 0, iCur);
- if( (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)
- && DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
- ){
- int i;
- Table *pTab = pIdx->pTable;
- int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1));
- if( ai ){
- ai[0] = pTab->nCol;
- for(i=0; i<pIdx->nColumn-1; i++){
- assert( pIdx->aiColumn[i]<pTab->nCol );
- if( pIdx->aiColumn[i]>=0 ) ai[pIdx->aiColumn[i]+1] = i+1;
- }
- sqlite3VdbeChangeP4(v, -1, (char*)ai, P4_INTARRAY);
- }
- }
+static void whereAndInfoDelete(sqlite3 *db, WhereAndInfo *p){
+ whereClauseClear(&p->wc);
+ sqlite3DbFree(db, p);
}
/*
-** Generate code for the start of the iLevel-th loop in the WHERE clause
-** implementation described by pWInfo.
+** Deallocate a WhereClause structure. The WhereClause structure
+** itself is not freed. This routine is the inverse of whereClauseInit().
*/
-SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
- WhereInfo *pWInfo, /* Complete information about the WHERE clause */
- int iLevel, /* Which level of pWInfo->a[] should be coded */
- Bitmask notReady /* Which tables are currently available */
-){
- int j, k; /* Loop counters */
- int iCur; /* The VDBE cursor for the table */
- int addrNxt; /* Where to jump to continue with the next IN case */
- int omitTable; /* True if we use the index only */
- int bRev; /* True if we need to scan in reverse order */
- WhereLevel *pLevel; /* The where level to be coded */
- WhereLoop *pLoop; /* The WhereLoop object being coded */
- WhereClause *pWC; /* Decomposition of the entire WHERE clause */
- WhereTerm *pTerm; /* A WHERE clause term */
- Parse *pParse; /* Parsing context */
- sqlite3 *db; /* Database connection */
- Vdbe *v; /* The prepared stmt under constructions */
- struct SrcList_item *pTabItem; /* FROM clause term being coded */
- int addrBrk; /* Jump here to break out of the loop */
- int addrCont; /* Jump here to continue with next cycle */
- int iRowidReg = 0; /* Rowid is stored in this register, if not zero */
- int iReleaseReg = 0; /* Temp register to free before returning */
-
- pParse = pWInfo->pParse;
- v = pParse->pVdbe;
- pWC = &pWInfo->sWC;
- db = pParse->db;
- pLevel = &pWInfo->a[iLevel];
- pLoop = pLevel->pWLoop;
- pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
- iCur = pTabItem->iCursor;
- pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
- bRev = (pWInfo->revMask>>iLevel)&1;
- omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0
- && (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)==0;
- VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
-
- /* Create labels for the "break" and "continue" instructions
- ** for the current loop. Jump to addrBrk to break out of a loop.
- ** Jump to cont to go immediately to the next iteration of the
- ** loop.
- **
- ** When there is an IN operator, we also have a "addrNxt" label that
- ** means to continue with the next IN value combination. When
- ** there are no IN operators in the constraints, the "addrNxt" label
- ** is the same as "addrBrk".
- */
- addrBrk = pLevel->addrBrk = pLevel->addrNxt = sqlite3VdbeMakeLabel(v);
- addrCont = pLevel->addrCont = sqlite3VdbeMakeLabel(v);
-
- /* If this is the right table of a LEFT OUTER JOIN, allocate and
- ** initialize a memory cell that records if this table matches any
- ** row of the left table of the join.
- */
- if( pLevel->iFrom>0 && (pTabItem[0].fg.jointype & JT_LEFT)!=0 ){
- pLevel->iLeftJoin = ++pParse->nMem;
- sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin);
- VdbeComment((v, "init LEFT JOIN no-match flag"));
- }
-
- /* Special case of a FROM clause subquery implemented as a co-routine */
- if( pTabItem->fg.viaCoroutine ){
- int regYield = pTabItem->regReturn;
- sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
- pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk);
- VdbeCoverage(v);
- VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName));
- pLevel->op = OP_Goto;
- }else
-
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){
- /* Case 1: The table is a virtual-table. Use the VFilter and VNext
- ** to access the data.
- */
- int iReg; /* P3 Value for OP_VFilter */
- int addrNotFound;
- int nConstraint = pLoop->nLTerm;
- int iIn; /* Counter for IN constraints */
-
- sqlite3ExprCachePush(pParse);
- iReg = sqlite3GetTempRange(pParse, nConstraint+2);
- addrNotFound = pLevel->addrBrk;
- for(j=0; j<nConstraint; j++){
- int iTarget = iReg+j+2;
- pTerm = pLoop->aLTerm[j];
- if( NEVER(pTerm==0) ) continue;
- if( pTerm->eOperator & WO_IN ){
- codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget);
- addrNotFound = pLevel->addrNxt;
- }else{
- sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget);
- }
- }
- sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg);
- sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1);
- sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg,
- pLoop->u.vtab.idxStr,
- pLoop->u.vtab.needFree ? P4_MPRINTF : P4_STATIC);
- VdbeCoverage(v);
- pLoop->u.vtab.needFree = 0;
- pLevel->p1 = iCur;
- pLevel->op = pWInfo->eOnePass ? OP_Noop : OP_VNext;
- pLevel->p2 = sqlite3VdbeCurrentAddr(v);
- iIn = pLevel->u.in.nIn;
- for(j=nConstraint-1; j>=0; j--){
- pTerm = pLoop->aLTerm[j];
- if( j<16 && (pLoop->u.vtab.omitMask>>j)&1 ){
- disableTerm(pLevel, pTerm);
- }else if( (pTerm->eOperator & WO_IN)!=0 ){
- Expr *pCompare; /* The comparison operator */
- Expr *pRight; /* RHS of the comparison */
- VdbeOp *pOp; /* Opcode to access the value of the IN constraint */
-
- /* Reload the constraint value into reg[iReg+j+2]. The same value
- ** was loaded into the same register prior to the OP_VFilter, but
- ** the xFilter implementation might have changed the datatype or
- ** encoding of the value in the register, so it *must* be reloaded. */
- assert( pLevel->u.in.aInLoop!=0 || db->mallocFailed );
- if( !db->mallocFailed ){
- assert( iIn>0 );
- pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[--iIn].addrInTop);
- assert( pOp->opcode==OP_Column || pOp->opcode==OP_Rowid );
- assert( pOp->opcode!=OP_Column || pOp->p3==iReg+j+2 );
- assert( pOp->opcode!=OP_Rowid || pOp->p2==iReg+j+2 );
- testcase( pOp->opcode==OP_Rowid );
- sqlite3VdbeAddOp3(v, pOp->opcode, pOp->p1, pOp->p2, pOp->p3);
- }
-
- /* Generate code that will continue to the next row if
- ** the IN constraint is not satisfied */
- pCompare = sqlite3PExpr(pParse, TK_EQ, 0, 0, 0);
- assert( pCompare!=0 || db->mallocFailed );
- if( pCompare ){
- pCompare->pLeft = pTerm->pExpr->pLeft;
- pCompare->pRight = pRight = sqlite3Expr(db, TK_REGISTER, 0);
- if( pRight ){
- pRight->iTable = iReg+j+2;
- sqlite3ExprIfFalse(pParse, pCompare, pLevel->addrCont, 0);
- }
- pCompare->pLeft = 0;
- sqlite3ExprDelete(db, pCompare);
- }
- }
- }
- /* These registers need to be preserved in case there is an IN operator
- ** loop. So we could deallocate the registers here (and potentially
- ** reuse them later) if (pLoop->wsFlags & WHERE_IN_ABLE)==0. But it seems
- ** simpler and safer to simply not reuse the registers.
- **
- ** sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
- */
- sqlite3ExprCachePop(pParse);
- }else
-#endif /* SQLITE_OMIT_VIRTUALTABLE */
-
- if( (pLoop->wsFlags & WHERE_IPK)!=0
- && (pLoop->wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_EQ))!=0
- ){
- /* Case 2: We can directly reference a single row using an
- ** equality comparison against the ROWID field. Or
- ** we reference multiple rows using a "rowid IN (...)"
- ** construct.
- */
- assert( pLoop->u.btree.nEq==1 );
- pTerm = pLoop->aLTerm[0];
- assert( pTerm!=0 );
- assert( pTerm->pExpr!=0 );
- assert( omitTable==0 );
- testcase( pTerm->wtFlags & TERM_VIRTUAL );
- iReleaseReg = ++pParse->nMem;
- iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg);
- if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg);
- addrNxt = pLevel->addrNxt;
- sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt); VdbeCoverage(v);
- sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg);
- VdbeCoverage(v);
- sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1);
- sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
- VdbeComment((v, "pk"));
- pLevel->op = OP_Noop;
- }else if( (pLoop->wsFlags & WHERE_IPK)!=0
- && (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0
- ){
- /* Case 3: We have an inequality comparison against the ROWID field.
- */
- int testOp = OP_Noop;
- int start;
- int memEndValue = 0;
- WhereTerm *pStart, *pEnd;
-
- assert( omitTable==0 );
- j = 0;
- pStart = pEnd = 0;
- if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aLTerm[j++];
- if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aLTerm[j++];
- assert( pStart!=0 || pEnd!=0 );
- if( bRev ){
- pTerm = pStart;
- pStart = pEnd;
- pEnd = pTerm;
- }
- codeCursorHint(pWInfo, pLevel, pEnd);
- if( pStart ){
- Expr *pX; /* The expression that defines the start bound */
- int r1, rTemp; /* Registers for holding the start boundary */
-
- /* The following constant maps TK_xx codes into corresponding
- ** seek opcodes. It depends on a particular ordering of TK_xx
- */
- const u8 aMoveOp[] = {
- /* TK_GT */ OP_SeekGT,
- /* TK_LE */ OP_SeekLE,
- /* TK_LT */ OP_SeekLT,
- /* TK_GE */ OP_SeekGE
- };
- assert( TK_LE==TK_GT+1 ); /* Make sure the ordering.. */
- assert( TK_LT==TK_GT+2 ); /* ... of the TK_xx values... */
- assert( TK_GE==TK_GT+3 ); /* ... is correcct. */
-
- assert( (pStart->wtFlags & TERM_VNULL)==0 );
- testcase( pStart->wtFlags & TERM_VIRTUAL );
- pX = pStart->pExpr;
- assert( pX!=0 );
- testcase( pStart->leftCursor!=iCur ); /* transitive constraints */
- r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp);
- sqlite3VdbeAddOp3(v, aMoveOp[pX->op-TK_GT], iCur, addrBrk, r1);
- VdbeComment((v, "pk"));
- VdbeCoverageIf(v, pX->op==TK_GT);
- VdbeCoverageIf(v, pX->op==TK_LE);
- VdbeCoverageIf(v, pX->op==TK_LT);
- VdbeCoverageIf(v, pX->op==TK_GE);
- sqlite3ExprCacheAffinityChange(pParse, r1, 1);
- sqlite3ReleaseTempReg(pParse, rTemp);
- disableTerm(pLevel, pStart);
- }else{
- sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrBrk);
- VdbeCoverageIf(v, bRev==0);
- VdbeCoverageIf(v, bRev!=0);
- }
- if( pEnd ){
- Expr *pX;
- pX = pEnd->pExpr;
- assert( pX!=0 );
- assert( (pEnd->wtFlags & TERM_VNULL)==0 );
- testcase( pEnd->leftCursor!=iCur ); /* Transitive constraints */
- testcase( pEnd->wtFlags & TERM_VIRTUAL );
- memEndValue = ++pParse->nMem;
- sqlite3ExprCode(pParse, pX->pRight, memEndValue);
- if( pX->op==TK_LT || pX->op==TK_GT ){
- testOp = bRev ? OP_Le : OP_Ge;
- }else{
- testOp = bRev ? OP_Lt : OP_Gt;
- }
- disableTerm(pLevel, pEnd);
- }
- start = sqlite3VdbeCurrentAddr(v);
- pLevel->op = bRev ? OP_Prev : OP_Next;
- pLevel->p1 = iCur;
- pLevel->p2 = start;
- assert( pLevel->p5==0 );
- if( testOp!=OP_Noop ){
- iRowidReg = ++pParse->nMem;
- sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg);
- sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
- sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg);
- VdbeCoverageIf(v, testOp==OP_Le);
- VdbeCoverageIf(v, testOp==OP_Lt);
- VdbeCoverageIf(v, testOp==OP_Ge);
- VdbeCoverageIf(v, testOp==OP_Gt);
- sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL);
- }
- }else if( pLoop->wsFlags & WHERE_INDEXED ){
- /* Case 4: A scan using an index.
- **
- ** The WHERE clause may contain zero or more equality
- ** terms ("==" or "IN" operators) that refer to the N
- ** left-most columns of the index. It may also contain
- ** inequality constraints (>, <, >= or <=) on the indexed
- ** column that immediately follows the N equalities. Only
- ** the right-most column can be an inequality - the rest must
- ** use the "==" and "IN" operators. For example, if the
- ** index is on (x,y,z), then the following clauses are all
- ** optimized:
- **
- ** x=5
- ** x=5 AND y=10
- ** x=5 AND y<10
- ** x=5 AND y>5 AND y<10
- ** x=5 AND y=5 AND z<=10
- **
- ** The z<10 term of the following cannot be used, only
- ** the x=5 term:
- **
- ** x=5 AND z<10
- **
- ** N may be zero if there are inequality constraints.
- ** If there are no inequality constraints, then N is at
- ** least one.
- **
- ** This case is also used when there are no WHERE clause
- ** constraints but an index is selected anyway, in order
- ** to force the output order to conform to an ORDER BY.
- */
- static const u8 aStartOp[] = {
- 0,
- 0,
- OP_Rewind, /* 2: (!start_constraints && startEq && !bRev) */
- OP_Last, /* 3: (!start_constraints && startEq && bRev) */
- OP_SeekGT, /* 4: (start_constraints && !startEq && !bRev) */
- OP_SeekLT, /* 5: (start_constraints && !startEq && bRev) */
- OP_SeekGE, /* 6: (start_constraints && startEq && !bRev) */
- OP_SeekLE /* 7: (start_constraints && startEq && bRev) */
- };
- static const u8 aEndOp[] = {
- OP_IdxGE, /* 0: (end_constraints && !bRev && !endEq) */
- OP_IdxGT, /* 1: (end_constraints && !bRev && endEq) */
- OP_IdxLE, /* 2: (end_constraints && bRev && !endEq) */
- OP_IdxLT, /* 3: (end_constraints && bRev && endEq) */
- };
- u16 nEq = pLoop->u.btree.nEq; /* Number of == or IN terms */
- int regBase; /* Base register holding constraint values */
- WhereTerm *pRangeStart = 0; /* Inequality constraint at range start */
- WhereTerm *pRangeEnd = 0; /* Inequality constraint at range end */
- int startEq; /* True if range start uses ==, >= or <= */
- int endEq; /* True if range end uses ==, >= or <= */
- int start_constraints; /* Start of range is constrained */
- int nConstraint; /* Number of constraint terms */
- Index *pIdx; /* The index we will be using */
- int iIdxCur; /* The VDBE cursor for the index */
- int nExtraReg = 0; /* Number of extra registers needed */
- int op; /* Instruction opcode */
- char *zStartAff; /* Affinity for start of range constraint */
- char cEndAff = 0; /* Affinity for end of range constraint */
- u8 bSeekPastNull = 0; /* True to seek past initial nulls */
- u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */
-
- pIdx = pLoop->u.btree.pIndex;
- iIdxCur = pLevel->iIdxCur;
- assert( nEq>=pLoop->nSkip );
-
- /* If this loop satisfies a sort order (pOrderBy) request that
- ** was passed to this function to implement a "SELECT min(x) ..."
- ** query, then the caller will only allow the loop to run for
- ** a single iteration. This means that the first row returned
- ** should not have a NULL value stored in 'x'. If column 'x' is
- ** the first one after the nEq equality constraints in the index,
- ** this requires some special handling.
- */
- assert( pWInfo->pOrderBy==0
- || pWInfo->pOrderBy->nExpr==1
- || (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 );
- if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0
- && pWInfo->nOBSat>0
- && (pIdx->nKeyCol>nEq)
- ){
- assert( pLoop->nSkip==0 );
- bSeekPastNull = 1;
- nExtraReg = 1;
- }
-
- /* Find any inequality constraint terms for the start and end
- ** of the range.
- */
- j = nEq;
- if( pLoop->wsFlags & WHERE_BTM_LIMIT ){
- pRangeStart = pLoop->aLTerm[j++];
- nExtraReg = 1;
- /* Like optimization range constraints always occur in pairs */
- assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 ||
- (pLoop->wsFlags & WHERE_TOP_LIMIT)!=0 );
- }
- if( pLoop->wsFlags & WHERE_TOP_LIMIT ){
- pRangeEnd = pLoop->aLTerm[j++];
- nExtraReg = 1;
-#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
- if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){
- assert( pRangeStart!=0 ); /* LIKE opt constraints */
- assert( pRangeStart->wtFlags & TERM_LIKEOPT ); /* occur in pairs */
- pLevel->iLikeRepCntr = (u32)++pParse->nMem;
- sqlite3VdbeAddOp2(v, OP_Integer, 1, (int)pLevel->iLikeRepCntr);
- VdbeComment((v, "LIKE loop counter"));
- pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v);
- /* iLikeRepCntr actually stores 2x the counter register number. The
- ** bottom bit indicates whether the search order is ASC or DESC. */
- testcase( bRev );
- testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC );
- assert( (bRev & ~1)==0 );
- pLevel->iLikeRepCntr <<=1;
- pLevel->iLikeRepCntr |= bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC);
- }
-#endif
- if( pRangeStart==0
- && (j = pIdx->aiColumn[nEq])>=0
- && pIdx->pTable->aCol[j].notNull==0
- ){
- bSeekPastNull = 1;
- }
- }
- assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 );
-
- /* If we are doing a reverse order scan on an ascending index, or
- ** a forward order scan on a descending index, interchange the
- ** start and end terms (pRangeStart and pRangeEnd).
- */
- if( (nEq<pIdx->nKeyCol && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC))
- || (bRev && pIdx->nKeyCol==nEq)
- ){
- SWAP(WhereTerm *, pRangeEnd, pRangeStart);
- SWAP(u8, bSeekPastNull, bStopAtNull);
- }
-
- /* Generate code to evaluate all constraint terms using == or IN
- ** and store the values of those terms in an array of registers
- ** starting at regBase.
- */
- codeCursorHint(pWInfo, pLevel, pRangeEnd);
- regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff);
- assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq );
- if( zStartAff ) cEndAff = zStartAff[nEq];
- addrNxt = pLevel->addrNxt;
-
- testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 );
- testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 );
- testcase( pRangeEnd && (pRangeEnd->eOperator & WO_LE)!=0 );
- testcase( pRangeEnd && (pRangeEnd->eOperator & WO_GE)!=0 );
- startEq = !pRangeStart || pRangeStart->eOperator & (WO_LE|WO_GE);
- endEq = !pRangeEnd || pRangeEnd->eOperator & (WO_LE|WO_GE);
- start_constraints = pRangeStart || nEq>0;
-
- /* Seek the index cursor to the start of the range. */
- nConstraint = nEq;
- if( pRangeStart ){
- Expr *pRight = pRangeStart->pExpr->pRight;
- sqlite3ExprCode(pParse, pRight, regBase+nEq);
- whereLikeOptimizationStringFixup(v, pLevel, pRangeStart);
- if( (pRangeStart->wtFlags & TERM_VNULL)==0
- && sqlite3ExprCanBeNull(pRight)
- ){
- sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
- VdbeCoverage(v);
- }
- if( zStartAff ){
- if( sqlite3CompareAffinity(pRight, zStartAff[nEq])==SQLITE_AFF_BLOB){
- /* Since the comparison is to be performed with no conversions
- ** applied to the operands, set the affinity to apply to pRight to
- ** SQLITE_AFF_BLOB. */
- zStartAff[nEq] = SQLITE_AFF_BLOB;
- }
- if( sqlite3ExprNeedsNoAffinityChange(pRight, zStartAff[nEq]) ){
- zStartAff[nEq] = SQLITE_AFF_BLOB;
- }
- }
- nConstraint++;
- testcase( pRangeStart->wtFlags & TERM_VIRTUAL );
- }else if( bSeekPastNull ){
- sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
- nConstraint++;
- startEq = 0;
- start_constraints = 1;
- }
- codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff);
- if( pLoop->nSkip>0 && nConstraint==pLoop->nSkip ){
- /* The skip-scan logic inside the call to codeAllEqualityConstraints()
- ** above has already left the cursor sitting on the correct row,
- ** so no further seeking is needed */
- }else{
- op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
- assert( op!=0 );
- sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
- VdbeCoverage(v);
- VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind );
- VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last );
- VdbeCoverageIf(v, op==OP_SeekGT); testcase( op==OP_SeekGT );
- VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE );
- VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE );
- VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT );
- }
-
- /* Load the value for the inequality constraint at the end of the
- ** range (if any).
- */
- nConstraint = nEq;
- if( pRangeEnd ){
- Expr *pRight = pRangeEnd->pExpr->pRight;
- sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
- sqlite3ExprCode(pParse, pRight, regBase+nEq);
- whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
- if( (pRangeEnd->wtFlags & TERM_VNULL)==0
- && sqlite3ExprCanBeNull(pRight)
- ){
- sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
- VdbeCoverage(v);
- }
- if( sqlite3CompareAffinity(pRight, cEndAff)!=SQLITE_AFF_BLOB
- && !sqlite3ExprNeedsNoAffinityChange(pRight, cEndAff)
- ){
- codeApplyAffinity(pParse, regBase+nEq, 1, &cEndAff);
- }
- nConstraint++;
- testcase( pRangeEnd->wtFlags & TERM_VIRTUAL );
- }else if( bStopAtNull ){
- sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
- endEq = 0;
- nConstraint++;
- }
- sqlite3DbFree(db, zStartAff);
-
- /* Top of the loop body */
- pLevel->p2 = sqlite3VdbeCurrentAddr(v);
-
- /* Check if the index cursor is past the end of the range. */
- if( nConstraint ){
- op = aEndOp[bRev*2 + endEq];
- sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
- testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT );
- testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE );
- testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT );
- testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE );
- }
-
- /* Seek the table cursor, if required */
- disableTerm(pLevel, pRangeStart);
- disableTerm(pLevel, pRangeEnd);
- if( omitTable ){
- /* pIdx is a covering index. No need to access the main table. */
- }else if( HasRowid(pIdx->pTable) ){
- if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE)!=0 ){
- iRowidReg = ++pParse->nMem;
- sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
- sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
- sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg);
- VdbeCoverage(v);
- }else{
- codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur);
- }
- }else if( iCur!=iIdxCur ){
- Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
- iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol);
- for(j=0; j<pPk->nKeyCol; j++){
- k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
- sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, iRowidReg+j);
- }
- sqlite3VdbeAddOp4Int(v, OP_NotFound, iCur, addrCont,
- iRowidReg, pPk->nKeyCol); VdbeCoverage(v);
- }
-
- /* Record the instruction used to terminate the loop. Disable
- ** WHERE clause terms made redundant by the index range scan.
- */
- if( pLoop->wsFlags & WHERE_ONEROW ){
- pLevel->op = OP_Noop;
- }else if( bRev ){
- pLevel->op = OP_Prev;
- }else{
- pLevel->op = OP_Next;
- }
- pLevel->p1 = iIdxCur;
- pLevel->p3 = (pLoop->wsFlags&WHERE_UNQ_WANTED)!=0 ? 1:0;
- if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){
- pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
- }else{
- assert( pLevel->p5==0 );
- }
- }else
-
-#ifndef SQLITE_OMIT_OR_OPTIMIZATION
- if( pLoop->wsFlags & WHERE_MULTI_OR ){
- /* Case 5: Two or more separately indexed terms connected by OR
- **
- ** Example:
- **
- ** CREATE TABLE t1(a,b,c,d);
- ** CREATE INDEX i1 ON t1(a);
- ** CREATE INDEX i2 ON t1(b);
- ** CREATE INDEX i3 ON t1(c);
- **
- ** SELECT * FROM t1 WHERE a=5 OR b=7 OR (c=11 AND d=13)
- **
- ** In the example, there are three indexed terms connected by OR.
- ** The top of the loop looks like this:
- **
- ** Null 1 # Zero the rowset in reg 1
- **
- ** Then, for each indexed term, the following. The arguments to
- ** RowSetTest are such that the rowid of the current row is inserted
- ** into the RowSet. If it is already present, control skips the
- ** Gosub opcode and jumps straight to the code generated by WhereEnd().
- **
- ** sqlite3WhereBegin(<term>)
- ** RowSetTest # Insert rowid into rowset
- ** Gosub 2 A
- ** sqlite3WhereEnd()
- **
- ** Following the above, code to terminate the loop. Label A, the target
- ** of the Gosub above, jumps to the instruction right after the Goto.
- **
- ** Null 1 # Zero the rowset in reg 1
- ** Goto B # The loop is finished.
- **
- ** A: <loop body> # Return data, whatever.
- **
- ** Return 2 # Jump back to the Gosub
- **
- ** B: <after the loop>
- **
- ** Added 2014-05-26: If the table is a WITHOUT ROWID table, then
- ** use an ephemeral index instead of a RowSet to record the primary
- ** keys of the rows we have already seen.
- **
- */
- WhereClause *pOrWc; /* The OR-clause broken out into subterms */
- SrcList *pOrTab; /* Shortened table list or OR-clause generation */
- Index *pCov = 0; /* Potential covering index (or NULL) */
- int iCovCur = pParse->nTab++; /* Cursor used for index scans (if any) */
-
- int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */
- int regRowset = 0; /* Register for RowSet object */
- int regRowid = 0; /* Register holding rowid */
- int iLoopBody = sqlite3VdbeMakeLabel(v); /* Start of loop body */
- int iRetInit; /* Address of regReturn init */
- int untestedTerms = 0; /* Some terms not completely tested */
- int ii; /* Loop counter */
- u16 wctrlFlags; /* Flags for sub-WHERE clause */
- Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
- Table *pTab = pTabItem->pTab;
-
- pTerm = pLoop->aLTerm[0];
- assert( pTerm!=0 );
- assert( pTerm->eOperator & WO_OR );
- assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
- pOrWc = &pTerm->u.pOrInfo->wc;
- pLevel->op = OP_Return;
- pLevel->p1 = regReturn;
-
- /* Set up a new SrcList in pOrTab containing the table being scanned
- ** by this loop in the a[0] slot and all notReady tables in a[1..] slots.
- ** This becomes the SrcList in the recursive call to sqlite3WhereBegin().
- */
- if( pWInfo->nLevel>1 ){
- int nNotReady; /* The number of notReady tables */
- struct SrcList_item *origSrc; /* Original list of tables */
- nNotReady = pWInfo->nLevel - iLevel - 1;
- pOrTab = sqlite3StackAllocRaw(db,
- sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0]));
- if( pOrTab==0 ) return notReady;
- pOrTab->nAlloc = (u8)(nNotReady + 1);
- pOrTab->nSrc = pOrTab->nAlloc;
- memcpy(pOrTab->a, pTabItem, sizeof(*pTabItem));
- origSrc = pWInfo->pTabList->a;
- for(k=1; k<=nNotReady; k++){
- memcpy(&pOrTab->a[k], &origSrc[pLevel[k].iFrom], sizeof(pOrTab->a[k]));
- }
- }else{
- pOrTab = pWInfo->pTabList;
- }
-
- /* Initialize the rowset register to contain NULL. An SQL NULL is
- ** equivalent to an empty rowset. Or, create an ephemeral index
- ** capable of holding primary keys in the case of a WITHOUT ROWID.
- **
- ** Also initialize regReturn to contain the address of the instruction
- ** immediately following the OP_Return at the bottom of the loop. This
- ** is required in a few obscure LEFT JOIN cases where control jumps
- ** over the top of the loop into the body of it. In this case the
- ** correct response for the end-of-loop code (the OP_Return) is to
- ** fall through to the next instruction, just as an OP_Next does if
- ** called on an uninitialized cursor.
- */
- if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
- if( HasRowid(pTab) ){
- regRowset = ++pParse->nMem;
- sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset);
- }else{
- Index *pPk = sqlite3PrimaryKeyIndex(pTab);
- regRowset = pParse->nTab++;
- sqlite3VdbeAddOp2(v, OP_OpenEphemeral, regRowset, pPk->nKeyCol);
- sqlite3VdbeSetP4KeyInfo(pParse, pPk);
- }
- regRowid = ++pParse->nMem;
- }
- iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn);
-
- /* If the original WHERE clause is z of the form: (x1 OR x2 OR ...) AND y
- ** Then for every term xN, evaluate as the subexpression: xN AND z
- ** That way, terms in y that are factored into the disjunction will
- ** be picked up by the recursive calls to sqlite3WhereBegin() below.
- **
- ** Actually, each subexpression is converted to "xN AND w" where w is
- ** the "interesting" terms of z - terms that did not originate in the
- ** ON or USING clause of a LEFT JOIN, and terms that are usable as
- ** indices.
- **
- ** This optimization also only applies if the (x1 OR x2 OR ...) term
- ** is not contained in the ON clause of a LEFT JOIN.
- ** See ticket http://www.sqlite.org/src/info/f2369304e4
- */
- if( pWC->nTerm>1 ){
- int iTerm;
- for(iTerm=0; iTerm<pWC->nTerm; iTerm++){
- Expr *pExpr = pWC->a[iTerm].pExpr;
- if( &pWC->a[iTerm] == pTerm ) continue;
- if( ExprHasProperty(pExpr, EP_FromJoin) ) continue;
- testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL );
- testcase( pWC->a[iTerm].wtFlags & TERM_CODED );
- if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED))!=0 ) continue;
- if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
- testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO );
- pExpr = sqlite3ExprDup(db, pExpr, 0);
- pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr);
- }
- if( pAndExpr ){
- pAndExpr = sqlite3PExpr(pParse, TK_AND|TKFLG_DONTFOLD, 0, pAndExpr, 0);
- }
- }
-
- /* Run a separate WHERE clause for each term of the OR clause. After
- ** eliminating duplicates from other WHERE clauses, the action for each
- ** sub-WHERE clause is to to invoke the main loop body as a subroutine.
- */
- wctrlFlags = WHERE_OMIT_OPEN_CLOSE
- | WHERE_FORCE_TABLE
- | WHERE_ONETABLE_ONLY
- | WHERE_NO_AUTOINDEX
- | (pWInfo->wctrlFlags & WHERE_SEEK_TABLE);
- for(ii=0; ii<pOrWc->nTerm; ii++){
- WhereTerm *pOrTerm = &pOrWc->a[ii];
- if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
- WhereInfo *pSubWInfo; /* Info for single OR-term scan */
- Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */
- int jmp1 = 0; /* Address of jump operation */
- if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){
- pAndExpr->pLeft = pOrExpr;
- pOrExpr = pAndExpr;
- }
- /* Loop through table entries that match term pOrTerm. */
- WHERETRACE(0xffff, ("Subplan for OR-clause:\n"));
- pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0,
- wctrlFlags, iCovCur);
- assert( pSubWInfo || pParse->nErr || db->mallocFailed );
- if( pSubWInfo ){
- WhereLoop *pSubLoop;
- int addrExplain = sqlite3WhereExplainOneScan(
- pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
- );
- sqlite3WhereAddScanStatus(v, pOrTab, &pSubWInfo->a[0], addrExplain);
-
- /* This is the sub-WHERE clause body. First skip over
- ** duplicate rows from prior sub-WHERE clauses, and record the
- ** rowid (or PRIMARY KEY) for the current row so that the same
- ** row will be skipped in subsequent sub-WHERE clauses.
- */
- if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
- int r;
- int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
- if( HasRowid(pTab) ){
- r = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, regRowid, 0);
- jmp1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0,
- r,iSet);
- VdbeCoverage(v);
- }else{
- Index *pPk = sqlite3PrimaryKeyIndex(pTab);
- int nPk = pPk->nKeyCol;
- int iPk;
-
- /* Read the PK into an array of temp registers. */
- r = sqlite3GetTempRange(pParse, nPk);
- for(iPk=0; iPk<nPk; iPk++){
- int iCol = pPk->aiColumn[iPk];
- sqlite3ExprCodeGetColumnToReg(pParse, pTab, iCol, iCur, r+iPk);
- }
-
- /* Check if the temp table already contains this key. If so,
- ** the row has already been included in the result set and
- ** can be ignored (by jumping past the Gosub below). Otherwise,
- ** insert the key into the temp table and proceed with processing
- ** the row.
- **
- ** Use some of the same optimizations as OP_RowSetTest: If iSet
- ** is zero, assume that the key cannot already be present in
- ** the temp table. And if iSet is -1, assume that there is no
- ** need to insert the key into the temp table, as it will never
- ** be tested for. */
- if( iSet ){
- jmp1 = sqlite3VdbeAddOp4Int(v, OP_Found, regRowset, 0, r, nPk);
- VdbeCoverage(v);
- }
- if( iSet>=0 ){
- sqlite3VdbeAddOp3(v, OP_MakeRecord, r, nPk, regRowid);
- sqlite3VdbeAddOp3(v, OP_IdxInsert, regRowset, regRowid, 0);
- if( iSet ) sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
- }
-
- /* Release the array of temp registers */
- sqlite3ReleaseTempRange(pParse, r, nPk);
- }
- }
-
- /* Invoke the main loop body as a subroutine */
- sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, iLoopBody);
-
- /* Jump here (skipping the main loop body subroutine) if the
- ** current sub-WHERE row is a duplicate from prior sub-WHEREs. */
- if( jmp1 ) sqlite3VdbeJumpHere(v, jmp1);
-
- /* The pSubWInfo->untestedTerms flag means that this OR term
- ** contained one or more AND term from a notReady table. The
- ** terms from the notReady table could not be tested and will
- ** need to be tested later.
- */
- if( pSubWInfo->untestedTerms ) untestedTerms = 1;
-
- /* If all of the OR-connected terms are optimized using the same
- ** index, and the index is opened using the same cursor number
- ** by each call to sqlite3WhereBegin() made by this loop, it may
- ** be possible to use that index as a covering index.
- **
- ** If the call to sqlite3WhereBegin() above resulted in a scan that
- ** uses an index, and this is either the first OR-connected term
- ** processed or the index is the same as that used by all previous
- ** terms, set pCov to the candidate covering index. Otherwise, set
- ** pCov to NULL to indicate that no candidate covering index will
- ** be available.
- */
- pSubLoop = pSubWInfo->a[0].pWLoop;
- assert( (pSubLoop->wsFlags & WHERE_AUTO_INDEX)==0 );
- if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0
- && (ii==0 || pSubLoop->u.btree.pIndex==pCov)
- && (HasRowid(pTab) || !IsPrimaryKeyIndex(pSubLoop->u.btree.pIndex))
- ){
- assert( pSubWInfo->a[0].iIdxCur==iCovCur );
- pCov = pSubLoop->u.btree.pIndex;
- wctrlFlags |= WHERE_REOPEN_IDX;
- }else{
- pCov = 0;
- }
-
- /* Finish the loop through table entries that match term pOrTerm. */
- sqlite3WhereEnd(pSubWInfo);
- }
- }
- }
- pLevel->u.pCovidx = pCov;
- if( pCov ) pLevel->iIdxCur = iCovCur;
- if( pAndExpr ){
- pAndExpr->pLeft = 0;
- sqlite3ExprDelete(db, pAndExpr);
- }
- sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v));
- sqlite3VdbeGoto(v, pLevel->addrBrk);
- sqlite3VdbeResolveLabel(v, iLoopBody);
-
- if( pWInfo->nLevel>1 ) sqlite3StackFree(db, pOrTab);
- if( !untestedTerms ) disableTerm(pLevel, pTerm);
- }else
-#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
-
- {
- /* Case 6: There is no usable index. We must do a complete
- ** scan of the entire table.
- */
- static const u8 aStep[] = { OP_Next, OP_Prev };
- static const u8 aStart[] = { OP_Rewind, OP_Last };
- assert( bRev==0 || bRev==1 );
- if( pTabItem->fg.isRecursive ){
- /* Tables marked isRecursive have only a single row that is stored in
- ** a pseudo-cursor. No need to Rewind or Next such cursors. */
- pLevel->op = OP_Noop;
- }else{
- codeCursorHint(pWInfo, pLevel, 0);
- pLevel->op = aStep[bRev];
- pLevel->p1 = iCur;
- pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);
- VdbeCoverageIf(v, bRev==0);
- VdbeCoverageIf(v, bRev!=0);
- pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
- }
- }
-
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- pLevel->addrVisit = sqlite3VdbeCurrentAddr(v);
-#endif
-
- /* Insert code to test every subexpression that can be completely
- ** computed using the current set of tables.
- */
- for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
- Expr *pE;
- int skipLikeAddr = 0;
- testcase( pTerm->wtFlags & TERM_VIRTUAL );
- testcase( pTerm->wtFlags & TERM_CODED );
- if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
- if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
- testcase( pWInfo->untestedTerms==0
- && (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 );
- pWInfo->untestedTerms = 1;
- continue;
- }
- pE = pTerm->pExpr;
- assert( pE!=0 );
- if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
- continue;
- }
- if( pTerm->wtFlags & TERM_LIKECOND ){
- /* If the TERM_LIKECOND flag is set, that means that the range search
- ** is sufficient to guarantee that the LIKE operator is true, so we
- ** can skip the call to the like(A,B) function. But this only works
- ** for strings. So do not skip the call to the function on the pass
- ** that compares BLOBs. */
-#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
- continue;
-#else
- u32 x = pLevel->iLikeRepCntr;
- assert( x>0 );
- skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)? OP_IfNot : OP_If, (int)(x>>1));
- VdbeCoverage(v);
-#endif
+static void whereClauseClear(WhereClause *pWC){
+ int i;
+ WhereTerm *a;
+ sqlite3 *db = pWC->pWInfo->pParse->db;
+ for(i=pWC->nTerm-1, a=pWC->a; i>=0; i--, a++){
+ if( a->wtFlags & TERM_DYNAMIC ){
+ sqlite3ExprDelete(db, a->pExpr);
}
- sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
- if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
- pTerm->wtFlags |= TERM_CODED;
- }
-
- /* Insert code to test for implied constraints based on transitivity
- ** of the "==" operator.
- **
- ** Example: If the WHERE clause contains "t1.a=t2.b" and "t2.b=123"
- ** and we are coding the t1 loop and the t2 loop has not yet coded,
- ** then we cannot use the "t1.a=t2.b" constraint, but we can code
- ** the implied "t1.a=123" constraint.
- */
- for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
- Expr *pE, *pEAlt;
- WhereTerm *pAlt;
- if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
- if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue;
- if( (pTerm->eOperator & WO_EQUIV)==0 ) continue;
- if( pTerm->leftCursor!=iCur ) continue;
- if( pLevel->iLeftJoin ) continue;
- pE = pTerm->pExpr;
- assert( !ExprHasProperty(pE, EP_FromJoin) );
- assert( (pTerm->prereqRight & pLevel->notReady)!=0 );
- pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.leftColumn, notReady,
- WO_EQ|WO_IN|WO_IS, 0);
- if( pAlt==0 ) continue;
- if( pAlt->wtFlags & (TERM_CODED) ) continue;
- testcase( pAlt->eOperator & WO_EQ );
- testcase( pAlt->eOperator & WO_IS );
- testcase( pAlt->eOperator & WO_IN );
- VdbeModuleComment((v, "begin transitive constraint"));
- pEAlt = sqlite3StackAllocRaw(db, sizeof(*pEAlt));
- if( pEAlt ){
- *pEAlt = *pAlt->pExpr;
- pEAlt->pLeft = pE->pLeft;
- sqlite3ExprIfFalse(pParse, pEAlt, addrCont, SQLITE_JUMPIFNULL);
- sqlite3StackFree(db, pEAlt);
+ if( a->wtFlags & TERM_ORINFO ){
+ whereOrInfoDelete(db, a->u.pOrInfo);
+ }else if( a->wtFlags & TERM_ANDINFO ){
+ whereAndInfoDelete(db, a->u.pAndInfo);
}
}
-
- /* For a LEFT OUTER JOIN, generate code that will record the fact that
- ** at least one row of the right table has matched the left table.
- */
- if( pLevel->iLeftJoin ){
- pLevel->addrFirst = sqlite3VdbeCurrentAddr(v);
- sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin);
- VdbeComment((v, "record LEFT JOIN hit"));
- sqlite3ExprCacheClear(pParse);
- for(pTerm=pWC->a, j=0; j<pWC->nTerm; j++, pTerm++){
- testcase( pTerm->wtFlags & TERM_VIRTUAL );
- testcase( pTerm->wtFlags & TERM_CODED );
- if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
- if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
- assert( pWInfo->untestedTerms );
- continue;
- }
- assert( pTerm->pExpr );
- sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
- pTerm->wtFlags |= TERM_CODED;
- }
+ if( pWC->a!=pWC->aStatic ){
+ sqlite3DbFree(db, pWC->a);
}
-
- return pLevel->notReady;
-}
-
-/************** End of wherecode.c *******************************************/
-/************** Begin file whereexpr.c ***************************************/
-/*
-** 2015-06-08
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This module contains C code that generates VDBE code used to process
-** the WHERE clause of SQL statements.
-**
-** This file was originally part of where.c but was split out to improve
-** readability and editabiliity. This file contains utility routines for
-** analyzing Expr objects in the WHERE clause.
-*/
-/* #include "sqliteInt.h" */
-/* #include "whereInt.h" */
-
-/* Forward declarations */
-static void exprAnalyze(SrcList*, WhereClause*, int);
-
-/*
-** Deallocate all memory associated with a WhereOrInfo object.
-*/
-static void whereOrInfoDelete(sqlite3 *db, WhereOrInfo *p){
- sqlite3WhereClauseClear(&p->wc);
- sqlite3DbFree(db, p);
-}
-
-/*
-** Deallocate all memory associated with a WhereAndInfo object.
-*/
-static void whereAndInfoDelete(sqlite3 *db, WhereAndInfo *p){
- sqlite3WhereClauseClear(&p->wc);
- sqlite3DbFree(db, p);
}
/*
@@ -124666,7 +116383,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
if( pWC->nTerm>=pWC->nSlot ){
WhereTerm *pOld = pWC->a;
sqlite3 *db = pWC->pWInfo->pParse->db;
- pWC->a = sqlite3DbMallocRawNN(db, sizeof(pWC->a[0])*pWC->nSlot*2 );
+ pWC->a = sqlite3DbMallocRaw(db, sizeof(pWC->a[0])*pWC->nSlot*2 );
if( pWC->a==0 ){
if( wtFlags & TERM_DYNAMIC ){
sqlite3ExprDelete(db, p);
@@ -124695,6 +116412,122 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
}
/*
+** This routine identifies subexpressions in the WHERE clause where
+** each subexpression is separated by the AND operator or some other
+** operator specified in the op parameter. The WhereClause structure
+** is filled with pointers to subexpressions. For example:
+**
+** WHERE a=='hello' AND coalesce(b,11)<10 AND (c+12!=d OR c==22)
+** \________/ \_______________/ \________________/
+** slot[0] slot[1] slot[2]
+**
+** The original WHERE clause in pExpr is unaltered. All this routine
+** does is make slot[] entries point to substructure within pExpr.
+**
+** In the previous sentence and in the diagram, "slot[]" refers to
+** the WhereClause.a[] array. The slot[] array grows as needed to contain
+** all terms of the WHERE clause.
+*/
+static void whereSplit(WhereClause *pWC, Expr *pExpr, u8 op){
+ Expr *pE2 = sqlite3ExprSkipCollate(pExpr);
+ pWC->op = op;
+ if( pE2==0 ) return;
+ if( pE2->op!=op ){
+ whereClauseInsert(pWC, pExpr, 0);
+ }else{
+ whereSplit(pWC, pE2->pLeft, op);
+ whereSplit(pWC, pE2->pRight, op);
+ }
+}
+
+/*
+** Initialize a WhereMaskSet object
+*/
+#define initMaskSet(P) (P)->n=0
+
+/*
+** Return the bitmask for the given cursor number. Return 0 if
+** iCursor is not in the set.
+*/
+static Bitmask getMask(WhereMaskSet *pMaskSet, int iCursor){
+ int i;
+ assert( pMaskSet->n<=(int)sizeof(Bitmask)*8 );
+ for(i=0; i<pMaskSet->n; i++){
+ if( pMaskSet->ix[i]==iCursor ){
+ return MASKBIT(i);
+ }
+ }
+ return 0;
+}
+
+/*
+** Create a new mask for cursor iCursor.
+**
+** There is one cursor per table in the FROM clause. The number of
+** tables in the FROM clause is limited by a test early in the
+** sqlite3WhereBegin() routine. So we know that the pMaskSet->ix[]
+** array will never overflow.
+*/
+static void createMask(WhereMaskSet *pMaskSet, int iCursor){
+ assert( pMaskSet->n < ArraySize(pMaskSet->ix) );
+ pMaskSet->ix[pMaskSet->n++] = iCursor;
+}
+
+/*
+** These routines walk (recursively) an expression tree and generate
+** a bitmask indicating which tables are used in that expression
+** tree.
+*/
+static Bitmask exprListTableUsage(WhereMaskSet*, ExprList*);
+static Bitmask exprSelectTableUsage(WhereMaskSet*, Select*);
+static Bitmask exprTableUsage(WhereMaskSet *pMaskSet, Expr *p){
+ Bitmask mask = 0;
+ if( p==0 ) return 0;
+ if( p->op==TK_COLUMN ){
+ mask = getMask(pMaskSet, p->iTable);
+ return mask;
+ }
+ mask = exprTableUsage(pMaskSet, p->pRight);
+ mask |= exprTableUsage(pMaskSet, p->pLeft);
+ if( ExprHasProperty(p, EP_xIsSelect) ){
+ mask |= exprSelectTableUsage(pMaskSet, p->x.pSelect);
+ }else{
+ mask |= exprListTableUsage(pMaskSet, p->x.pList);
+ }
+ return mask;
+}
+static Bitmask exprListTableUsage(WhereMaskSet *pMaskSet, ExprList *pList){
+ int i;
+ Bitmask mask = 0;
+ if( pList ){
+ for(i=0; i<pList->nExpr; i++){
+ mask |= exprTableUsage(pMaskSet, pList->a[i].pExpr);
+ }
+ }
+ return mask;
+}
+static Bitmask exprSelectTableUsage(WhereMaskSet *pMaskSet, Select *pS){
+ Bitmask mask = 0;
+ while( pS ){
+ SrcList *pSrc = pS->pSrc;
+ mask |= exprListTableUsage(pMaskSet, pS->pEList);
+ mask |= exprListTableUsage(pMaskSet, pS->pGroupBy);
+ mask |= exprListTableUsage(pMaskSet, pS->pOrderBy);
+ mask |= exprTableUsage(pMaskSet, pS->pWhere);
+ mask |= exprTableUsage(pMaskSet, pS->pHaving);
+ if( ALWAYS(pSrc!=0) ){
+ int i;
+ for(i=0; i<pSrc->nSrc; i++){
+ mask |= exprSelectTableUsage(pMaskSet, pSrc->a[i].pSelect);
+ mask |= exprTableUsage(pMaskSet, pSrc->a[i].pOn);
+ }
+ }
+ pS = pS->pPrior;
+ }
+ return mask;
+}
+
+/*
** Return TRUE if the given operator is one of the operators that is
** allowed for an indexable WHERE clause term. The allowed operators are
** "=", "<", ">", "<=", ">=", "IN", and "IS NULL"
@@ -124704,7 +116537,7 @@ static int allowedOp(int op){
assert( TK_LT>TK_EQ && TK_LT<TK_GE );
assert( TK_LE>TK_EQ && TK_LE<TK_GE );
assert( TK_GE==TK_EQ+4 );
- return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL || op==TK_IS;
+ return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL;
}
/*
@@ -124757,8 +116590,6 @@ static u16 operatorMask(int op){
c = WO_IN;
}else if( op==TK_ISNULL ){
c = WO_ISNULL;
- }else if( op==TK_IS ){
- c = WO_IS;
}else{
assert( (WO_EQ<<(op-TK_EQ)) < 0x7fff );
c = (u16)(WO_EQ<<(op-TK_EQ));
@@ -124770,10 +116601,199 @@ static u16 operatorMask(int op){
assert( op!=TK_LE || c==WO_LE );
assert( op!=TK_GT || c==WO_GT );
assert( op!=TK_GE || c==WO_GE );
- assert( op!=TK_IS || c==WO_IS );
return c;
}
+/*
+** Advance to the next WhereTerm that matches according to the criteria
+** established when the pScan object was initialized by whereScanInit().
+** Return NULL if there are no more matching WhereTerms.
+*/
+static WhereTerm *whereScanNext(WhereScan *pScan){
+ int iCur; /* The cursor on the LHS of the term */
+ int iColumn; /* The column on the LHS of the term. -1 for IPK */
+ Expr *pX; /* An expression being tested */
+ WhereClause *pWC; /* Shorthand for pScan->pWC */
+ WhereTerm *pTerm; /* The term being tested */
+ int k = pScan->k; /* Where to start scanning */
+
+ while( pScan->iEquiv<=pScan->nEquiv ){
+ iCur = pScan->aEquiv[pScan->iEquiv-2];
+ iColumn = pScan->aEquiv[pScan->iEquiv-1];
+ while( (pWC = pScan->pWC)!=0 ){
+ for(pTerm=pWC->a+k; k<pWC->nTerm; k++, pTerm++){
+ if( pTerm->leftCursor==iCur
+ && pTerm->u.leftColumn==iColumn
+ && (pScan->iEquiv<=2 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin))
+ ){
+ if( (pTerm->eOperator & WO_EQUIV)!=0
+ && pScan->nEquiv<ArraySize(pScan->aEquiv)
+ ){
+ int j;
+ pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight);
+ assert( pX->op==TK_COLUMN );
+ for(j=0; j<pScan->nEquiv; j+=2){
+ if( pScan->aEquiv[j]==pX->iTable
+ && pScan->aEquiv[j+1]==pX->iColumn ){
+ break;
+ }
+ }
+ if( j==pScan->nEquiv ){
+ pScan->aEquiv[j] = pX->iTable;
+ pScan->aEquiv[j+1] = pX->iColumn;
+ pScan->nEquiv += 2;
+ }
+ }
+ if( (pTerm->eOperator & pScan->opMask)!=0 ){
+ /* Verify the affinity and collating sequence match */
+ if( pScan->zCollName && (pTerm->eOperator & WO_ISNULL)==0 ){
+ CollSeq *pColl;
+ Parse *pParse = pWC->pWInfo->pParse;
+ pX = pTerm->pExpr;
+ if( !sqlite3IndexAffinityOk(pX, pScan->idxaff) ){
+ continue;
+ }
+ assert(pX->pLeft);
+ pColl = sqlite3BinaryCompareCollSeq(pParse,
+ pX->pLeft, pX->pRight);
+ if( pColl==0 ) pColl = pParse->db->pDfltColl;
+ if( sqlite3StrICmp(pColl->zName, pScan->zCollName) ){
+ continue;
+ }
+ }
+ if( (pTerm->eOperator & WO_EQ)!=0
+ && (pX = pTerm->pExpr->pRight)->op==TK_COLUMN
+ && pX->iTable==pScan->aEquiv[0]
+ && pX->iColumn==pScan->aEquiv[1]
+ ){
+ continue;
+ }
+ pScan->k = k+1;
+ return pTerm;
+ }
+ }
+ }
+ pScan->pWC = pScan->pWC->pOuter;
+ k = 0;
+ }
+ pScan->pWC = pScan->pOrigWC;
+ k = 0;
+ pScan->iEquiv += 2;
+ }
+ return 0;
+}
+
+/*
+** Initialize a WHERE clause scanner object. Return a pointer to the
+** first match. Return NULL if there are no matches.
+**
+** The scanner will be searching the WHERE clause pWC. It will look
+** for terms of the form "X <op> <expr>" where X is column iColumn of table
+** iCur. The <op> must be one of the operators described by opMask.
+**
+** If the search is for X and the WHERE clause contains terms of the
+** form X=Y then this routine might also return terms of the form
+** "Y <op> <expr>". The number of levels of transitivity is limited,
+** but is enough to handle most commonly occurring SQL statements.
+**
+** If X is not the INTEGER PRIMARY KEY then X must be compatible with
+** index pIdx.
+*/
+static WhereTerm *whereScanInit(
+ WhereScan *pScan, /* The WhereScan object being initialized */
+ WhereClause *pWC, /* The WHERE clause to be scanned */
+ int iCur, /* Cursor to scan for */
+ int iColumn, /* Column to scan for */
+ u32 opMask, /* Operator(s) to scan for */
+ Index *pIdx /* Must be compatible with this index */
+){
+ int j;
+
+ /* memset(pScan, 0, sizeof(*pScan)); */
+ pScan->pOrigWC = pWC;
+ pScan->pWC = pWC;
+ if( pIdx && iColumn>=0 ){
+ pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity;
+ for(j=0; pIdx->aiColumn[j]!=iColumn; j++){
+ if( NEVER(j>pIdx->nColumn) ) return 0;
+ }
+ pScan->zCollName = pIdx->azColl[j];
+ }else{
+ pScan->idxaff = 0;
+ pScan->zCollName = 0;
+ }
+ pScan->opMask = opMask;
+ pScan->k = 0;
+ pScan->aEquiv[0] = iCur;
+ pScan->aEquiv[1] = iColumn;
+ pScan->nEquiv = 2;
+ pScan->iEquiv = 2;
+ return whereScanNext(pScan);
+}
+
+/*
+** Search for a term in the WHERE clause that is of the form "X <op> <expr>"
+** where X is a reference to the iColumn of table iCur and <op> is one of
+** the WO_xx operator codes specified by the op parameter.
+** Return a pointer to the term. Return 0 if not found.
+**
+** The term returned might by Y=<expr> if there is another constraint in
+** the WHERE clause that specifies that X=Y. Any such constraints will be
+** identified by the WO_EQUIV bit in the pTerm->eOperator field. The
+** aEquiv[] array holds X and all its equivalents, with each SQL variable
+** taking up two slots in aEquiv[]. The first slot is for the cursor number
+** and the second is for the column number. There are 22 slots in aEquiv[]
+** so that means we can look for X plus up to 10 other equivalent values.
+** Hence a search for X will return <expr> if X=A1 and A1=A2 and A2=A3
+** and ... and A9=A10 and A10=<expr>.
+**
+** If there are multiple terms in the WHERE clause of the form "X <op> <expr>"
+** then try for the one with no dependencies on <expr> - in other words where
+** <expr> is a constant expression of some kind. Only return entries of
+** the form "X <op> Y" where Y is a column in another table if no terms of
+** the form "X <op> <const-expr>" exist. If no terms with a constant RHS
+** exist, try to return a term that does not use WO_EQUIV.
+*/
+static WhereTerm *findTerm(
+ WhereClause *pWC, /* The WHERE clause to be searched */
+ int iCur, /* Cursor number of LHS */
+ int iColumn, /* Column number of LHS */
+ Bitmask notReady, /* RHS must not overlap with this mask */
+ u32 op, /* Mask of WO_xx values describing operator */
+ Index *pIdx /* Must be compatible with this index, if not NULL */
+){
+ WhereTerm *pResult = 0;
+ WhereTerm *p;
+ WhereScan scan;
+
+ p = whereScanInit(&scan, pWC, iCur, iColumn, op, pIdx);
+ while( p ){
+ if( (p->prereqRight & notReady)==0 ){
+ if( p->prereqRight==0 && (p->eOperator&WO_EQ)!=0 ){
+ return p;
+ }
+ if( pResult==0 ) pResult = p;
+ }
+ p = whereScanNext(&scan);
+ }
+ return pResult;
+}
+
+/* Forward reference */
+static void exprAnalyze(SrcList*, WhereClause*, int);
+
+/*
+** Call exprAnalyze on all terms in a WHERE clause.
+*/
+static void exprAnalyzeAll(
+ SrcList *pTabList, /* the FROM clause */
+ WhereClause *pWC /* the WHERE clause to be analyzed */
+){
+ int i;
+ for(i=pWC->nTerm-1; i>=0; i--){
+ exprAnalyze(pTabList, pWC, i);
+ }
+}
#ifndef SQLITE_OMIT_LIKE_OPTIMIZATION
/*
@@ -124784,7 +116804,7 @@ static u16 operatorMask(int op){
** In order for the operator to be optimizible, the RHS must be a string
** literal that does not begin with a wildcard. The LHS must be a column
** that may only be NULL, a string, or a BLOB, never a number. (This means
-** that virtual tables cannot participate in the LIKE optimization.) The
+** that virtual tables cannot participate in the LIKE optimization.) If the
** collating sequence for the column on the LHS must be appropriate for
** the operator.
*/
@@ -124804,7 +116824,6 @@ static int isLikeOrGlob(
sqlite3 *db = pParse->db; /* Database connection */
sqlite3_value *pVal = 0;
int op; /* Opcode of pRight */
- int rc; /* Result code to return */
if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){
return 0;
@@ -124829,7 +116848,7 @@ static int isLikeOrGlob(
if( op==TK_VARIABLE ){
Vdbe *pReprepare = pParse->pReprepare;
int iCol = pRight->iColumn;
- pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_BLOB);
+ pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_NONE);
if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){
z = (char *)sqlite3_value_text(pVal);
}
@@ -124870,9 +116889,8 @@ static int isLikeOrGlob(
}
}
- rc = (z!=0);
sqlite3ValueFree(pVal);
- return rc;
+ return (z!=0);
}
#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
@@ -124881,48 +116899,29 @@ static int isLikeOrGlob(
/*
** Check to see if the given expression is of the form
**
-** column OP expr
-**
-** where OP is one of MATCH, GLOB, LIKE or REGEXP and "column" is a
-** column of a virtual table.
+** column MATCH expr
**
** If it is then return TRUE. If not, return FALSE.
*/
static int isMatchOfColumn(
- Expr *pExpr, /* Test this expression */
- unsigned char *peOp2 /* OUT: 0 for MATCH, or else an op2 value */
-){
- struct Op2 {
- const char *zOp;
- unsigned char eOp2;
- } aOp[] = {
- { "match", SQLITE_INDEX_CONSTRAINT_MATCH },
- { "glob", SQLITE_INDEX_CONSTRAINT_GLOB },
- { "like", SQLITE_INDEX_CONSTRAINT_LIKE },
- { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP }
- };
+ Expr *pExpr /* Test this expression */
+){
ExprList *pList;
- Expr *pCol; /* Column reference */
- int i;
if( pExpr->op!=TK_FUNCTION ){
return 0;
}
- pList = pExpr->x.pList;
- if( pList==0 || pList->nExpr!=2 ){
+ if( sqlite3StrICmp(pExpr->u.zToken,"match")!=0 ){
return 0;
}
- pCol = pList->a[1].pExpr;
- if( pCol->op!=TK_COLUMN || !IsVirtual(pCol->pTab) ){
+ pList = pExpr->x.pList;
+ if( pList->nExpr!=2 ){
return 0;
}
- for(i=0; i<ArraySize(aOp); i++){
- if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
- *peOp2 = aOp[i].eOp2;
- return 1;
- }
+ if( pList->a[1].pExpr->op != TK_COLUMN ){
+ return 0;
}
- return 0;
+ return 1;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -125060,7 +117059,7 @@ static void whereCombineDisjuncts(
**
** CASE 2:
**
-** If there are exactly two disjuncts and one side has x>A and the other side
+** If there are exactly two disjuncts one side has x>A and the other side
** has x=A (for the same x and A) then add a new virtual conjunct term to the
** WHERE clause of the form "x>=A". Example:
**
@@ -125089,22 +117088,22 @@ static void whereCombineDisjuncts(
** is decided elsewhere. This analysis only looks at whether subterms
** appropriate for indexing exist.
**
-** All examples A through E above satisfy case 3. But if a term
+** All examples A through E above satisfy case 2. But if a term
** also satisfies case 1 (such as B) we know that the optimizer will
-** always prefer case 1, so in that case we pretend that case 3 is not
+** always prefer case 1, so in that case we pretend that case 2 is not
** satisfied.
**
** It might be the case that multiple tables are indexable. For example,
** (E) above is indexable on tables P, Q, and R.
**
-** Terms that satisfy case 3 are candidates for lookup by using
+** Terms that satisfy case 2 are candidates for lookup by using
** separate indices to find rowids for each subterm and composing
** the union of all rowids using a RowSet object. This is similar
** to "bitmap indices" in other database engines.
**
** OTHERWISE:
**
-** If none of cases 1, 2, or 3 apply, then leave the eOperator set to
+** If neither case 1 nor case 2 apply, then leave the eOperator set to
** zero. This term is not useful for search.
*/
static void exprAnalyzeOrTerm(
@@ -125135,15 +117134,14 @@ static void exprAnalyzeOrTerm(
if( pOrInfo==0 ) return;
pTerm->wtFlags |= TERM_ORINFO;
pOrWc = &pOrInfo->wc;
- memset(pOrWc->aStatic, 0, sizeof(pOrWc->aStatic));
- sqlite3WhereClauseInit(pOrWc, pWInfo);
- sqlite3WhereSplit(pOrWc, pExpr, TK_OR);
- sqlite3WhereExprAnalyze(pSrc, pOrWc);
+ whereClauseInit(pOrWc, pWInfo);
+ whereSplit(pOrWc, pExpr, TK_OR);
+ exprAnalyzeAll(pSrc, pOrWc);
if( db->mallocFailed ) return;
assert( pOrWc->nTerm>=2 );
/*
- ** Compute the set of tables that might satisfy cases 1 or 3.
+ ** Compute the set of tables that might satisfy cases 1 or 2.
*/
indexable = ~(Bitmask)0;
chngToIN = ~(Bitmask)0;
@@ -125152,7 +117150,7 @@ static void exprAnalyzeOrTerm(
WhereAndInfo *pAndInfo;
assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 );
chngToIN = 0;
- pAndInfo = sqlite3DbMallocRawNN(db, sizeof(*pAndInfo));
+ pAndInfo = sqlite3DbMallocRaw(db, sizeof(*pAndInfo));
if( pAndInfo ){
WhereClause *pAndWC;
WhereTerm *pAndTerm;
@@ -125162,16 +117160,16 @@ static void exprAnalyzeOrTerm(
pOrTerm->wtFlags |= TERM_ANDINFO;
pOrTerm->eOperator = WO_AND;
pAndWC = &pAndInfo->wc;
- memset(pAndWC->aStatic, 0, sizeof(pAndWC->aStatic));
- sqlite3WhereClauseInit(pAndWC, pWC->pWInfo);
- sqlite3WhereSplit(pAndWC, pOrTerm->pExpr, TK_AND);
- sqlite3WhereExprAnalyze(pSrc, pAndWC);
+ whereClauseInit(pAndWC, pWC->pWInfo);
+ whereSplit(pAndWC, pOrTerm->pExpr, TK_AND);
+ exprAnalyzeAll(pSrc, pAndWC);
pAndWC->pOuter = pWC;
+ testcase( db->mallocFailed );
if( !db->mallocFailed ){
for(j=0, pAndTerm=pAndWC->a; j<pAndWC->nTerm; j++, pAndTerm++){
assert( pAndTerm->pExpr );
if( allowedOp(pAndTerm->pExpr->op) ){
- b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor);
+ b |= getMask(&pWInfo->sMaskSet, pAndTerm->leftCursor);
}
}
}
@@ -125182,10 +117180,10 @@ static void exprAnalyzeOrTerm(
** corresponding TERM_VIRTUAL term */
}else{
Bitmask b;
- b = sqlite3WhereGetMask(&pWInfo->sMaskSet, pOrTerm->leftCursor);
+ b = getMask(&pWInfo->sMaskSet, pOrTerm->leftCursor);
if( pOrTerm->wtFlags & TERM_VIRTUAL ){
WhereTerm *pOther = &pOrWc->a[pOrTerm->iParent];
- b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pOther->leftCursor);
+ b |= getMask(&pWInfo->sMaskSet, pOther->leftCursor);
}
indexable &= b;
if( (pOrTerm->eOperator & WO_EQ)==0 ){
@@ -125261,8 +117259,7 @@ static void exprAnalyzeOrTerm(
assert( j==1 );
continue;
}
- if( (chngToIN & sqlite3WhereGetMask(&pWInfo->sMaskSet,
- pOrTerm->leftCursor))==0 ){
+ if( (chngToIN & getMask(&pWInfo->sMaskSet, pOrTerm->leftCursor))==0 ){
/* This term must be of the form t1.a==t2.b where t2 is in the
** chngToIN set but t1 is not. This term will be either preceded
** or follwed by an inverted copy (t2.b==t1.a). Skip this term
@@ -125281,7 +117278,7 @@ static void exprAnalyzeOrTerm(
** on the second iteration */
assert( j==1 );
assert( IsPowerOfTwo(chngToIN) );
- assert( chngToIN==sqlite3WhereGetMask(&pWInfo->sMaskSet, iCursor) );
+ assert( chngToIN==getMask(&pWInfo->sMaskSet, iCursor) );
break;
}
testcase( j==1 );
@@ -125354,117 +117351,6 @@ static void exprAnalyzeOrTerm(
#endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */
/*
-** We already know that pExpr is a binary operator where both operands are
-** column references. This routine checks to see if pExpr is an equivalence
-** relation:
-** 1. The SQLITE_Transitive optimization must be enabled
-** 2. Must be either an == or an IS operator
-** 3. Not originating in the ON clause of an OUTER JOIN
-** 4. The affinities of A and B must be compatible
-** 5a. Both operands use the same collating sequence OR
-** 5b. The overall collating sequence is BINARY
-** If this routine returns TRUE, that means that the RHS can be substituted
-** for the LHS anyplace else in the WHERE clause where the LHS column occurs.
-** This is an optimization. No harm comes from returning 0. But if 1 is
-** returned when it should not be, then incorrect answers might result.
-*/
-static int termIsEquivalence(Parse *pParse, Expr *pExpr){
- char aff1, aff2;
- CollSeq *pColl;
- const char *zColl1, *zColl2;
- if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0;
- if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0;
- if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0;
- aff1 = sqlite3ExprAffinity(pExpr->pLeft);
- aff2 = sqlite3ExprAffinity(pExpr->pRight);
- if( aff1!=aff2
- && (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2))
- ){
- return 0;
- }
- pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
- if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1;
- pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
- /* Since pLeft and pRight are both a column references, their collating
- ** sequence should always be defined. */
- zColl1 = ALWAYS(pColl) ? pColl->zName : 0;
- pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight);
- zColl2 = ALWAYS(pColl) ? pColl->zName : 0;
- return sqlite3StrICmp(zColl1, zColl2)==0;
-}
-
-/*
-** Recursively walk the expressions of a SELECT statement and generate
-** a bitmask indicating which tables are used in that expression
-** tree.
-*/
-static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
- Bitmask mask = 0;
- while( pS ){
- SrcList *pSrc = pS->pSrc;
- mask |= sqlite3WhereExprListUsage(pMaskSet, pS->pEList);
- mask |= sqlite3WhereExprListUsage(pMaskSet, pS->pGroupBy);
- mask |= sqlite3WhereExprListUsage(pMaskSet, pS->pOrderBy);
- mask |= sqlite3WhereExprUsage(pMaskSet, pS->pWhere);
- mask |= sqlite3WhereExprUsage(pMaskSet, pS->pHaving);
- if( ALWAYS(pSrc!=0) ){
- int i;
- for(i=0; i<pSrc->nSrc; i++){
- mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect);
- mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].pOn);
- }
- }
- pS = pS->pPrior;
- }
- return mask;
-}
-
-/*
-** Expression pExpr is one operand of a comparison operator that might
-** be useful for indexing. This routine checks to see if pExpr appears
-** in any index. Return TRUE (1) if pExpr is an indexed term and return
-** FALSE (0) if not. If TRUE is returned, also set *piCur to the cursor
-** number of the table that is indexed and *piColumn to the column number
-** of the column that is indexed, or -2 if an expression is being indexed.
-**
-** If pExpr is a TK_COLUMN column reference, then this routine always returns
-** true even if that particular column is not indexed, because the column
-** might be added to an automatic index later.
-*/
-static int exprMightBeIndexed(
- SrcList *pFrom, /* The FROM clause */
- Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */
- Expr *pExpr, /* An operand of a comparison operator */
- int *piCur, /* Write the referenced table cursor number here */
- int *piColumn /* Write the referenced table column number here */
-){
- Index *pIdx;
- int i;
- int iCur;
- if( pExpr->op==TK_COLUMN ){
- *piCur = pExpr->iTable;
- *piColumn = pExpr->iColumn;
- return 1;
- }
- if( mPrereq==0 ) return 0; /* No table references */
- if( (mPrereq&(mPrereq-1))!=0 ) return 0; /* Refs more than one table */
- for(i=0; mPrereq>1; i++, mPrereq>>=1){}
- iCur = pFrom->a[i].iCursor;
- for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( pIdx->aColExpr==0 ) continue;
- for(i=0; i<pIdx->nKeyCol; i++){
- if( pIdx->aiColumn[i]!=(-2) ) continue;
- if( sqlite3ExprCompare(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
- *piCur = iCur;
- *piColumn = -2;
- return 1;
- }
- }
- }
- return 0;
-}
-
-/*
** The input to this routine is an WhereTerm structure with only the
** "pExpr" field filled in. The job of this routine is to analyze the
** subexpression and populate all the other fields of the WhereTerm
@@ -125500,7 +117386,6 @@ static void exprAnalyze(
int op; /* Top-level operator. pExpr->op */
Parse *pParse = pWInfo->pParse; /* Parsing context */
sqlite3 *db = pParse->db; /* Database connection */
- unsigned char eOp2; /* op2 value for LIKE/REGEXP/GLOB */
if( db->mallocFailed ){
return;
@@ -125509,23 +117394,23 @@ static void exprAnalyze(
pMaskSet = &pWInfo->sMaskSet;
pExpr = pTerm->pExpr;
assert( pExpr->op!=TK_AS && pExpr->op!=TK_COLLATE );
- prereqLeft = sqlite3WhereExprUsage(pMaskSet, pExpr->pLeft);
+ prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
op = pExpr->op;
if( op==TK_IN ){
assert( pExpr->pRight==0 );
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
- pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect);
+ pTerm->prereqRight = exprSelectTableUsage(pMaskSet, pExpr->x.pSelect);
}else{
- pTerm->prereqRight = sqlite3WhereExprListUsage(pMaskSet, pExpr->x.pList);
+ pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->x.pList);
}
}else if( op==TK_ISNULL ){
pTerm->prereqRight = 0;
}else{
- pTerm->prereqRight = sqlite3WhereExprUsage(pMaskSet, pExpr->pRight);
+ pTerm->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight);
}
- prereqAll = sqlite3WhereExprUsage(pMaskSet, pExpr);
+ prereqAll = exprTableUsage(pMaskSet, pExpr);
if( ExprHasProperty(pExpr, EP_FromJoin) ){
- Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->iRightJoinTable);
+ Bitmask x = getMask(pMaskSet, pExpr->iRightJoinTable);
prereqAll |= x;
extraRight = x-1; /* ON clause terms may not be used with an index
** on left table of a LEFT JOIN. Ticket #3015 */
@@ -125535,19 +117420,15 @@ static void exprAnalyze(
pTerm->iParent = -1;
pTerm->eOperator = 0;
if( allowedOp(op) ){
- int iCur, iColumn;
Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
- if( exprMightBeIndexed(pSrc, prereqLeft, pLeft, &iCur, &iColumn) ){
- pTerm->leftCursor = iCur;
- pTerm->u.leftColumn = iColumn;
+ if( pLeft->op==TK_COLUMN ){
+ pTerm->leftCursor = pLeft->iTable;
+ pTerm->u.leftColumn = pLeft->iColumn;
pTerm->eOperator = operatorMask(op) & opMask;
}
- if( op==TK_IS ) pTerm->wtFlags |= TERM_IS;
- if( pRight
- && exprMightBeIndexed(pSrc, pTerm->prereqRight, pRight, &iCur, &iColumn)
- ){
+ if( pRight && pRight->op==TK_COLUMN ){
WhereTerm *pNew;
Expr *pDup;
u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */
@@ -125562,11 +117443,12 @@ static void exprAnalyze(
if( idxNew==0 ) return;
pNew = &pWC->a[idxNew];
markTermAsChild(pWC, idxNew, idxTerm);
- if( op==TK_IS ) pNew->wtFlags |= TERM_IS;
pTerm = &pWC->a[idxTerm];
pTerm->wtFlags |= TERM_COPIED;
-
- if( termIsEquivalence(pParse, pDup) ){
+ if( pExpr->op==TK_EQ
+ && !ExprHasProperty(pExpr, EP_FromJoin)
+ && OptimizationEnabled(db, SQLITE_Transitive)
+ ){
pTerm->eOperator |= WO_EQUIV;
eExtraOp = WO_EQUIV;
}
@@ -125575,8 +117457,9 @@ static void exprAnalyze(
pNew = pTerm;
}
exprCommute(pParse, pDup);
- pNew->leftCursor = iCur;
- pNew->u.leftColumn = iColumn;
+ pLeft = sqlite3ExprSkipCollate(pDup->pLeft);
+ pNew->leftCursor = pLeft->iTable;
+ pNew->u.leftColumn = pLeft->iColumn;
testcase( (prereqLeft | extraRight) != prereqLeft );
pNew->prereqRight = prereqLeft | extraRight;
pNew->prereqAll = prereqAll;
@@ -125724,7 +117607,7 @@ static void exprAnalyze(
** virtual tables. The native query optimizer does not attempt
** to do anything with MATCH functions.
*/
- if( isMatchOfColumn(pExpr, &eOp2) ){
+ if( isMatchOfColumn(pExpr) ){
int idxNew;
Expr *pRight, *pLeft;
WhereTerm *pNewTerm;
@@ -125732,8 +117615,8 @@ static void exprAnalyze(
pRight = pExpr->x.pList->a[0].pExpr;
pLeft = pExpr->x.pList->a[1].pExpr;
- prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight);
- prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft);
+ prereqExpr = exprTableUsage(pMaskSet, pRight);
+ prereqColumn = exprTableUsage(pMaskSet, pLeft);
if( (prereqExpr & prereqColumn)==0 ){
Expr *pNewExpr;
pNewExpr = sqlite3PExpr(pParse, TK_MATCH,
@@ -125745,7 +117628,6 @@ static void exprAnalyze(
pNewTerm->leftCursor = pLeft->iTable;
pNewTerm->u.leftColumn = pLeft->iColumn;
pNewTerm->eOperator = WO_MATCH;
- pNewTerm->eMatchOp = eOp2;
markTermAsChild(pWC, idxNew, idxTerm);
pTerm = &pWC->a[idxTerm];
pTerm->wtFlags |= TERM_COPIED;
@@ -125760,7 +117642,10 @@ static void exprAnalyze(
** as "x>NULL" if x is not an INTEGER PRIMARY KEY. So construct a
** virtual term of that form.
**
- ** Note that the virtual term must be tagged with TERM_VNULL.
+ ** Note that the virtual term must be tagged with TERM_VNULL. This
+ ** TERM_VNULL tag will suppress the not-null check at the beginning
+ ** of the loop. Without the TERM_VNULL flag, the not-null check at
+ ** the start of the loop will prevent any results from being returned.
*/
if( pExpr->op==TK_NOTNULL
&& pExpr->pLeft->op==TK_COLUMN
@@ -125798,536 +117683,6 @@ static void exprAnalyze(
pTerm->prereqRight |= extraRight;
}
-/***************************************************************************
-** Routines with file scope above. Interface to the rest of the where.c
-** subsystem follows.
-***************************************************************************/
-
-/*
-** This routine identifies subexpressions in the WHERE clause where
-** each subexpression is separated by the AND operator or some other
-** operator specified in the op parameter. The WhereClause structure
-** is filled with pointers to subexpressions. For example:
-**
-** WHERE a=='hello' AND coalesce(b,11)<10 AND (c+12!=d OR c==22)
-** \________/ \_______________/ \________________/
-** slot[0] slot[1] slot[2]
-**
-** The original WHERE clause in pExpr is unaltered. All this routine
-** does is make slot[] entries point to substructure within pExpr.
-**
-** In the previous sentence and in the diagram, "slot[]" refers to
-** the WhereClause.a[] array. The slot[] array grows as needed to contain
-** all terms of the WHERE clause.
-*/
-SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){
- Expr *pE2 = sqlite3ExprSkipCollate(pExpr);
- pWC->op = op;
- if( pE2==0 ) return;
- if( pE2->op!=op ){
- whereClauseInsert(pWC, pExpr, 0);
- }else{
- sqlite3WhereSplit(pWC, pE2->pLeft, op);
- sqlite3WhereSplit(pWC, pE2->pRight, op);
- }
-}
-
-/*
-** Initialize a preallocated WhereClause structure.
-*/
-SQLITE_PRIVATE void sqlite3WhereClauseInit(
- WhereClause *pWC, /* The WhereClause to be initialized */
- WhereInfo *pWInfo /* The WHERE processing context */
-){
- pWC->pWInfo = pWInfo;
- pWC->pOuter = 0;
- pWC->nTerm = 0;
- pWC->nSlot = ArraySize(pWC->aStatic);
- pWC->a = pWC->aStatic;
-}
-
-/*
-** Deallocate a WhereClause structure. The WhereClause structure
-** itself is not freed. This routine is the inverse of
-** sqlite3WhereClauseInit().
-*/
-SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause *pWC){
- int i;
- WhereTerm *a;
- sqlite3 *db = pWC->pWInfo->pParse->db;
- for(i=pWC->nTerm-1, a=pWC->a; i>=0; i--, a++){
- if( a->wtFlags & TERM_DYNAMIC ){
- sqlite3ExprDelete(db, a->pExpr);
- }
- if( a->wtFlags & TERM_ORINFO ){
- whereOrInfoDelete(db, a->u.pOrInfo);
- }else if( a->wtFlags & TERM_ANDINFO ){
- whereAndInfoDelete(db, a->u.pAndInfo);
- }
- }
- if( pWC->a!=pWC->aStatic ){
- sqlite3DbFree(db, pWC->a);
- }
-}
-
-
-/*
-** These routines walk (recursively) an expression tree and generate
-** a bitmask indicating which tables are used in that expression
-** tree.
-*/
-SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
- Bitmask mask = 0;
- if( p==0 ) return 0;
- if( p->op==TK_COLUMN ){
- mask = sqlite3WhereGetMask(pMaskSet, p->iTable);
- return mask;
- }
- mask = sqlite3WhereExprUsage(pMaskSet, p->pRight);
- if( p->pLeft ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft);
- if( ExprHasProperty(p, EP_xIsSelect) ){
- mask |= exprSelectUsage(pMaskSet, p->x.pSelect);
- }else if( p->x.pList ){
- mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList);
- }
- return mask;
-}
-SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet *pMaskSet, ExprList *pList){
- int i;
- Bitmask mask = 0;
- if( pList ){
- for(i=0; i<pList->nExpr; i++){
- mask |= sqlite3WhereExprUsage(pMaskSet, pList->a[i].pExpr);
- }
- }
- return mask;
-}
-
-
-/*
-** Call exprAnalyze on all terms in a WHERE clause.
-**
-** Note that exprAnalyze() might add new virtual terms onto the
-** end of the WHERE clause. We do not want to analyze these new
-** virtual terms, so start analyzing at the end and work forward
-** so that the added virtual terms are never processed.
-*/
-SQLITE_PRIVATE void sqlite3WhereExprAnalyze(
- SrcList *pTabList, /* the FROM clause */
- WhereClause *pWC /* the WHERE clause to be analyzed */
-){
- int i;
- for(i=pWC->nTerm-1; i>=0; i--){
- exprAnalyze(pTabList, pWC, i);
- }
-}
-
-/*
-** For table-valued-functions, transform the function arguments into
-** new WHERE clause terms.
-**
-** Each function argument translates into an equality constraint against
-** a HIDDEN column in the table.
-*/
-SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(
- Parse *pParse, /* Parsing context */
- struct SrcList_item *pItem, /* The FROM clause term to process */
- WhereClause *pWC /* Xfer function arguments to here */
-){
- Table *pTab;
- int j, k;
- ExprList *pArgs;
- Expr *pColRef;
- Expr *pTerm;
- if( pItem->fg.isTabFunc==0 ) return;
- pTab = pItem->pTab;
- assert( pTab!=0 );
- pArgs = pItem->u1.pFuncArg;
- if( pArgs==0 ) return;
- for(j=k=0; j<pArgs->nExpr; j++){
- while( k<pTab->nCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){k++;}
- if( k>=pTab->nCol ){
- sqlite3ErrorMsg(pParse, "too many arguments on %s() - max %d",
- pTab->zName, j);
- return;
- }
- pColRef = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
- if( pColRef==0 ) return;
- pColRef->iTable = pItem->iCursor;
- pColRef->iColumn = k++;
- pColRef->pTab = pTab;
- pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef,
- sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
- whereClauseInsert(pWC, pTerm, TERM_DYNAMIC);
- }
-}
-
-/************** End of whereexpr.c *******************************************/
-/************** Begin file where.c *******************************************/
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This module contains C code that generates VDBE code used to process
-** the WHERE clause of SQL statements. This module is responsible for
-** generating the code that loops through a table looking for applicable
-** rows. Indices are selected and used to speed the search when doing
-** so is applicable. Because this module is responsible for selecting
-** indices, you might also think of this module as the "query optimizer".
-*/
-/* #include "sqliteInt.h" */
-/* #include "whereInt.h" */
-
-/* Forward declaration of methods */
-static int whereLoopResize(sqlite3*, WhereLoop*, int);
-
-/* Test variable that can be set to enable WHERE tracing */
-#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
-/***/ int sqlite3WhereTrace = 0;
-#endif
-
-
-/*
-** Return the estimated number of output rows from a WHERE clause
-*/
-SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo *pWInfo){
- return pWInfo->nRowOut;
-}
-
-/*
-** Return one of the WHERE_DISTINCT_xxxxx values to indicate how this
-** WHERE clause returns outputs for DISTINCT processing.
-*/
-SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo *pWInfo){
- return pWInfo->eDistinct;
-}
-
-/*
-** Return TRUE if the WHERE clause returns rows in ORDER BY order.
-** Return FALSE if the output needs to be sorted.
-*/
-SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
- return pWInfo->nOBSat;
-}
-
-/*
-** Return the VDBE address or label to jump to in order to continue
-** immediately with the next row of a WHERE clause.
-*/
-SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo *pWInfo){
- assert( pWInfo->iContinue!=0 );
- return pWInfo->iContinue;
-}
-
-/*
-** Return the VDBE address or label to jump to in order to break
-** out of a WHERE loop.
-*/
-SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo *pWInfo){
- return pWInfo->iBreak;
-}
-
-/*
-** Return ONEPASS_OFF (0) if an UPDATE or DELETE statement is unable to
-** operate directly on the rowis returned by a WHERE clause. Return
-** ONEPASS_SINGLE (1) if the statement can operation directly because only
-** a single row is to be changed. Return ONEPASS_MULTI (2) if the one-pass
-** optimization can be used on multiple
-**
-** If the ONEPASS optimization is used (if this routine returns true)
-** then also write the indices of open cursors used by ONEPASS
-** into aiCur[0] and aiCur[1]. iaCur[0] gets the cursor of the data
-** table and iaCur[1] gets the cursor used by an auxiliary index.
-** Either value may be -1, indicating that cursor is not used.
-** Any cursors returned will have been opened for writing.
-**
-** aiCur[0] and aiCur[1] both get -1 if the where-clause logic is
-** unable to use the ONEPASS optimization.
-*/
-SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo *pWInfo, int *aiCur){
- memcpy(aiCur, pWInfo->aiCurOnePass, sizeof(int)*2);
-#ifdef WHERETRACE_ENABLED
- if( sqlite3WhereTrace && pWInfo->eOnePass!=ONEPASS_OFF ){
- sqlite3DebugPrintf("%s cursors: %d %d\n",
- pWInfo->eOnePass==ONEPASS_SINGLE ? "ONEPASS_SINGLE" : "ONEPASS_MULTI",
- aiCur[0], aiCur[1]);
- }
-#endif
- return pWInfo->eOnePass;
-}
-
-/*
-** Move the content of pSrc into pDest
-*/
-static void whereOrMove(WhereOrSet *pDest, WhereOrSet *pSrc){
- pDest->n = pSrc->n;
- memcpy(pDest->a, pSrc->a, pDest->n*sizeof(pDest->a[0]));
-}
-
-/*
-** Try to insert a new prerequisite/cost entry into the WhereOrSet pSet.
-**
-** The new entry might overwrite an existing entry, or it might be
-** appended, or it might be discarded. Do whatever is the right thing
-** so that pSet keeps the N_OR_COST best entries seen so far.
-*/
-static int whereOrInsert(
- WhereOrSet *pSet, /* The WhereOrSet to be updated */
- Bitmask prereq, /* Prerequisites of the new entry */
- LogEst rRun, /* Run-cost of the new entry */
- LogEst nOut /* Number of outputs for the new entry */
-){
- u16 i;
- WhereOrCost *p;
- for(i=pSet->n, p=pSet->a; i>0; i--, p++){
- if( rRun<=p->rRun && (prereq & p->prereq)==prereq ){
- goto whereOrInsert_done;
- }
- if( p->rRun<=rRun && (p->prereq & prereq)==p->prereq ){
- return 0;
- }
- }
- if( pSet->n<N_OR_COST ){
- p = &pSet->a[pSet->n++];
- p->nOut = nOut;
- }else{
- p = pSet->a;
- for(i=1; i<pSet->n; i++){
- if( p->rRun>pSet->a[i].rRun ) p = pSet->a + i;
- }
- if( p->rRun<=rRun ) return 0;
- }
-whereOrInsert_done:
- p->prereq = prereq;
- p->rRun = rRun;
- if( p->nOut>nOut ) p->nOut = nOut;
- return 1;
-}
-
-/*
-** Return the bitmask for the given cursor number. Return 0 if
-** iCursor is not in the set.
-*/
-SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet *pMaskSet, int iCursor){
- int i;
- assert( pMaskSet->n<=(int)sizeof(Bitmask)*8 );
- for(i=0; i<pMaskSet->n; i++){
- if( pMaskSet->ix[i]==iCursor ){
- return MASKBIT(i);
- }
- }
- return 0;
-}
-
-/*
-** Create a new mask for cursor iCursor.
-**
-** There is one cursor per table in the FROM clause. The number of
-** tables in the FROM clause is limited by a test early in the
-** sqlite3WhereBegin() routine. So we know that the pMaskSet->ix[]
-** array will never overflow.
-*/
-static void createMask(WhereMaskSet *pMaskSet, int iCursor){
- assert( pMaskSet->n < ArraySize(pMaskSet->ix) );
- pMaskSet->ix[pMaskSet->n++] = iCursor;
-}
-
-/*
-** Advance to the next WhereTerm that matches according to the criteria
-** established when the pScan object was initialized by whereScanInit().
-** Return NULL if there are no more matching WhereTerms.
-*/
-static WhereTerm *whereScanNext(WhereScan *pScan){
- int iCur; /* The cursor on the LHS of the term */
- i16 iColumn; /* The column on the LHS of the term. -1 for IPK */
- Expr *pX; /* An expression being tested */
- WhereClause *pWC; /* Shorthand for pScan->pWC */
- WhereTerm *pTerm; /* The term being tested */
- int k = pScan->k; /* Where to start scanning */
-
- while( pScan->iEquiv<=pScan->nEquiv ){
- iCur = pScan->aiCur[pScan->iEquiv-1];
- iColumn = pScan->aiColumn[pScan->iEquiv-1];
- if( iColumn==XN_EXPR && pScan->pIdxExpr==0 ) return 0;
- while( (pWC = pScan->pWC)!=0 ){
- for(pTerm=pWC->a+k; k<pWC->nTerm; k++, pTerm++){
- if( pTerm->leftCursor==iCur
- && pTerm->u.leftColumn==iColumn
- && (iColumn!=XN_EXPR
- || sqlite3ExprCompare(pTerm->pExpr->pLeft,pScan->pIdxExpr,iCur)==0)
- && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin))
- ){
- if( (pTerm->eOperator & WO_EQUIV)!=0
- && pScan->nEquiv<ArraySize(pScan->aiCur)
- && (pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight))->op==TK_COLUMN
- ){
- int j;
- for(j=0; j<pScan->nEquiv; j++){
- if( pScan->aiCur[j]==pX->iTable
- && pScan->aiColumn[j]==pX->iColumn ){
- break;
- }
- }
- if( j==pScan->nEquiv ){
- pScan->aiCur[j] = pX->iTable;
- pScan->aiColumn[j] = pX->iColumn;
- pScan->nEquiv++;
- }
- }
- if( (pTerm->eOperator & pScan->opMask)!=0 ){
- /* Verify the affinity and collating sequence match */
- if( pScan->zCollName && (pTerm->eOperator & WO_ISNULL)==0 ){
- CollSeq *pColl;
- Parse *pParse = pWC->pWInfo->pParse;
- pX = pTerm->pExpr;
- if( !sqlite3IndexAffinityOk(pX, pScan->idxaff) ){
- continue;
- }
- assert(pX->pLeft);
- pColl = sqlite3BinaryCompareCollSeq(pParse,
- pX->pLeft, pX->pRight);
- if( pColl==0 ) pColl = pParse->db->pDfltColl;
- if( sqlite3StrICmp(pColl->zName, pScan->zCollName) ){
- continue;
- }
- }
- if( (pTerm->eOperator & (WO_EQ|WO_IS))!=0
- && (pX = pTerm->pExpr->pRight)->op==TK_COLUMN
- && pX->iTable==pScan->aiCur[0]
- && pX->iColumn==pScan->aiColumn[0]
- ){
- testcase( pTerm->eOperator & WO_IS );
- continue;
- }
- pScan->k = k+1;
- return pTerm;
- }
- }
- }
- pScan->pWC = pScan->pWC->pOuter;
- k = 0;
- }
- pScan->pWC = pScan->pOrigWC;
- k = 0;
- pScan->iEquiv++;
- }
- return 0;
-}
-
-/*
-** Initialize a WHERE clause scanner object. Return a pointer to the
-** first match. Return NULL if there are no matches.
-**
-** The scanner will be searching the WHERE clause pWC. It will look
-** for terms of the form "X <op> <expr>" where X is column iColumn of table
-** iCur. Or if pIdx!=0 then X is column iColumn of index pIdx. pIdx
-** must be one of the indexes of table iCur.
-**
-** The <op> must be one of the operators described by opMask.
-**
-** If the search is for X and the WHERE clause contains terms of the
-** form X=Y then this routine might also return terms of the form
-** "Y <op> <expr>". The number of levels of transitivity is limited,
-** but is enough to handle most commonly occurring SQL statements.
-**
-** If X is not the INTEGER PRIMARY KEY then X must be compatible with
-** index pIdx.
-*/
-static WhereTerm *whereScanInit(
- WhereScan *pScan, /* The WhereScan object being initialized */
- WhereClause *pWC, /* The WHERE clause to be scanned */
- int iCur, /* Cursor to scan for */
- int iColumn, /* Column to scan for */
- u32 opMask, /* Operator(s) to scan for */
- Index *pIdx /* Must be compatible with this index */
-){
- int j = 0;
-
- /* memset(pScan, 0, sizeof(*pScan)); */
- pScan->pOrigWC = pWC;
- pScan->pWC = pWC;
- pScan->pIdxExpr = 0;
- if( pIdx ){
- j = iColumn;
- iColumn = pIdx->aiColumn[j];
- if( iColumn==XN_EXPR ) pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr;
- if( iColumn==pIdx->pTable->iPKey ) iColumn = XN_ROWID;
- }
- if( pIdx && iColumn>=0 ){
- pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity;
- pScan->zCollName = pIdx->azColl[j];
- }else{
- pScan->idxaff = 0;
- pScan->zCollName = 0;
- }
- pScan->opMask = opMask;
- pScan->k = 0;
- pScan->aiCur[0] = iCur;
- pScan->aiColumn[0] = iColumn;
- pScan->nEquiv = 1;
- pScan->iEquiv = 1;
- return whereScanNext(pScan);
-}
-
-/*
-** Search for a term in the WHERE clause that is of the form "X <op> <expr>"
-** where X is a reference to the iColumn of table iCur or of index pIdx
-** if pIdx!=0 and <op> is one of the WO_xx operator codes specified by
-** the op parameter. Return a pointer to the term. Return 0 if not found.
-**
-** If pIdx!=0 then it must be one of the indexes of table iCur.
-** Search for terms matching the iColumn-th column of pIdx
-** rather than the iColumn-th column of table iCur.
-**
-** The term returned might by Y=<expr> if there is another constraint in
-** the WHERE clause that specifies that X=Y. Any such constraints will be
-** identified by the WO_EQUIV bit in the pTerm->eOperator field. The
-** aiCur[]/iaColumn[] arrays hold X and all its equivalents. There are 11
-** slots in aiCur[]/aiColumn[] so that means we can look for X plus up to 10
-** other equivalent values. Hence a search for X will return <expr> if X=A1
-** and A1=A2 and A2=A3 and ... and A9=A10 and A10=<expr>.
-**
-** If there are multiple terms in the WHERE clause of the form "X <op> <expr>"
-** then try for the one with no dependencies on <expr> - in other words where
-** <expr> is a constant expression of some kind. Only return entries of
-** the form "X <op> Y" where Y is a column in another table if no terms of
-** the form "X <op> <const-expr>" exist. If no terms with a constant RHS
-** exist, try to return a term that does not use WO_EQUIV.
-*/
-SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm(
- WhereClause *pWC, /* The WHERE clause to be searched */
- int iCur, /* Cursor number of LHS */
- int iColumn, /* Column number of LHS */
- Bitmask notReady, /* RHS must not overlap with this mask */
- u32 op, /* Mask of WO_xx values describing operator */
- Index *pIdx /* Must be compatible with this index, if not NULL */
-){
- WhereTerm *pResult = 0;
- WhereTerm *p;
- WhereScan scan;
-
- p = whereScanInit(&scan, pWC, iCur, iColumn, op, pIdx);
- op &= WO_EQ|WO_IS;
- while( p ){
- if( (p->prereqRight & notReady)==0 ){
- if( p->prereqRight==0 && (p->eOperator&op)!=0 ){
- testcase( p->eOperator & WO_IS );
- return p;
- }
- if( pResult==0 ) pResult = p;
- }
- p = whereScanNext(&scan);
- }
- return pResult;
-}
-
/*
** This function searches pList for an entry that matches the iCol-th column
** of index pIdx.
@@ -126362,30 +117717,11 @@ static int findIndexCol(
}
/*
-** Return TRUE if the iCol-th column of index pIdx is NOT NULL
-*/
-static int indexColumnNotNull(Index *pIdx, int iCol){
- int j;
- assert( pIdx!=0 );
- assert( iCol>=0 && iCol<pIdx->nColumn );
- j = pIdx->aiColumn[iCol];
- if( j>=0 ){
- return pIdx->pTable->aCol[j].notNull;
- }else if( j==(-1) ){
- return 1;
- }else{
- assert( j==(-2) );
- return 0; /* Assume an indexed expression can always yield a NULL */
-
- }
-}
-
-/*
** Return true if the DISTINCT expression-list passed as the third argument
** is redundant.
**
-** A DISTINCT list is redundant if any subset of the columns in the
-** DISTINCT list are collectively unique and individually non-null.
+** A DISTINCT list is redundant if the database contains some subset of
+** columns that are unique and non-null.
*/
static int isDistinctRedundant(
Parse *pParse, /* Parsing context */
@@ -126430,9 +117766,12 @@ static int isDistinctRedundant(
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( !IsUniqueIndex(pIdx) ) continue;
for(i=0; i<pIdx->nKeyCol; i++){
- if( 0==sqlite3WhereFindTerm(pWC, iBase, i, ~(Bitmask)0, WO_EQ, pIdx) ){
- if( findIndexCol(pParse, pDistinct, iBase, pIdx, i)<0 ) break;
- if( indexColumnNotNull(pIdx, i)==0 ) break;
+ i16 iCol = pIdx->aiColumn[i];
+ if( 0==findTerm(pWC, iBase, iCol, ~(Bitmask)0, WO_EQ, pIdx) ){
+ int iIdxCol = findIndexCol(pParse, pDistinct, iBase, pIdx, i);
+ if( iIdxCol<0 || pTab->aCol[iCol].notNull==0 ){
+ break;
+ }
}
}
if( i==pIdx->nKeyCol ){
@@ -126453,49 +117792,6 @@ static LogEst estLog(LogEst N){
}
/*
-** Convert OP_Column opcodes to OP_Copy in previously generated code.
-**
-** This routine runs over generated VDBE code and translates OP_Column
-** opcodes into OP_Copy when the table is being accessed via co-routine
-** instead of via table lookup.
-**
-** If the bIncrRowid parameter is 0, then any OP_Rowid instructions on
-** cursor iTabCur are transformed into OP_Null. Or, if bIncrRowid is non-zero,
-** then each OP_Rowid is transformed into an instruction to increment the
-** value stored in its output register.
-*/
-static void translateColumnToCopy(
- Vdbe *v, /* The VDBE containing code to translate */
- int iStart, /* Translate from this opcode to the end */
- int iTabCur, /* OP_Column/OP_Rowid references to this table */
- int iRegister, /* The first column is in this register */
- int bIncrRowid /* If non-zero, transform OP_rowid to OP_AddImm(1) */
-){
- VdbeOp *pOp = sqlite3VdbeGetOp(v, iStart);
- int iEnd = sqlite3VdbeCurrentAddr(v);
- for(; iStart<iEnd; iStart++, pOp++){
- if( pOp->p1!=iTabCur ) continue;
- if( pOp->opcode==OP_Column ){
- pOp->opcode = OP_Copy;
- pOp->p1 = pOp->p2 + iRegister;
- pOp->p2 = pOp->p3;
- pOp->p3 = 0;
- }else if( pOp->opcode==OP_Rowid ){
- if( bIncrRowid ){
- /* Increment the value stored in the P2 operand of the OP_Rowid. */
- pOp->opcode = OP_AddImm;
- pOp->p1 = pOp->p2;
- pOp->p2 = 1;
- }else{
- pOp->opcode = OP_Null;
- pOp->p1 = 0;
- pOp->p3 = 0;
- }
- }
- }
-}
-
-/*
** Two routines for printing the content of an sqlite3_index_info
** structure. Used for testing and debugging only. If neither
** SQLITE_TEST or SQLITE_DEBUG are defined, then these routines
@@ -126553,12 +117849,11 @@ static int termCanDriveIndex(
){
char aff;
if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
- if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0;
+ if( (pTerm->eOperator & WO_EQ)==0 ) return 0;
if( (pTerm->prereqRight & notReady)!=0 ) return 0;
if( pTerm->u.leftColumn<0 ) return 0;
aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity;
if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
- testcase( pTerm->pExpr->op==TK_IS );
return 1;
}
#endif
@@ -126597,9 +117892,6 @@ static void constructAutomaticIndex(
u8 sentWarning = 0; /* True if a warnning has been issued */
Expr *pPartial = 0; /* Partial Index Expression */
int iContinue = 0; /* Jump here to skip excluded rows */
- struct SrcList_item *pTabItem; /* FROM clause term being indexed */
- int addrCounter = 0; /* Address where integer counter is initialized */
- int regBase; /* Array of registers where record is assembled */
/* Generate code to skip over the creation and initialization of the
** transient index on 2nd and subsequent iterations of the loop. */
@@ -126689,7 +117981,7 @@ static void constructAutomaticIndex(
idxCols |= cMask;
pIdx->aiColumn[n] = pTerm->u.leftColumn;
pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
- pIdx->azColl[n] = pColl ? pColl->zName : sqlite3StrBINARY;
+ pIdx->azColl[n] = pColl ? pColl->zName : "BINARY";
n++;
}
}
@@ -126701,20 +117993,20 @@ static void constructAutomaticIndex(
for(i=0; i<mxBitCol; i++){
if( extraCols & MASKBIT(i) ){
pIdx->aiColumn[n] = i;
- pIdx->azColl[n] = sqlite3StrBINARY;
+ pIdx->azColl[n] = "BINARY";
n++;
}
}
if( pSrc->colUsed & MASKBIT(BMS-1) ){
for(i=BMS-1; i<pTable->nCol; i++){
pIdx->aiColumn[n] = i;
- pIdx->azColl[n] = sqlite3StrBINARY;
+ pIdx->azColl[n] = "BINARY";
n++;
}
}
assert( n==nKeyCol );
- pIdx->aiColumn[n] = XN_ROWID;
- pIdx->azColl[n] = sqlite3StrBINARY;
+ pIdx->aiColumn[n] = -1;
+ pIdx->azColl[n] = "BINARY";
/* Create the automatic index */
assert( pLevel->iIdxCur>=0 );
@@ -126725,37 +118017,18 @@ static void constructAutomaticIndex(
/* Fill the automatic index with content */
sqlite3ExprCachePush(pParse);
- pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom];
- if( pTabItem->fg.viaCoroutine ){
- int regYield = pTabItem->regReturn;
- addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0);
- sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
- addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
- VdbeCoverage(v);
- VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName));
- }else{
- addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
- }
+ addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
if( pPartial ){
iContinue = sqlite3VdbeMakeLabel(v);
sqlite3ExprIfFalse(pParse, pPartial, iContinue, SQLITE_JUMPIFNULL);
pLoop->wsFlags |= WHERE_PARTIALIDX;
}
regRecord = sqlite3GetTempReg(pParse);
- regBase = sqlite3GenerateIndexKey(
- pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0
- );
+ sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0);
sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
- if( pTabItem->fg.viaCoroutine ){
- sqlite3VdbeChangeP2(v, addrCounter, regBase+n);
- translateColumnToCopy(v, addrTop, pLevel->iTabCur, pTabItem->regResult, 1);
- sqlite3VdbeGoto(v, addrTop);
- pTabItem->fg.viaCoroutine = 0;
- }else{
- sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
- }
+ sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
sqlite3VdbeJumpHere(v, addrTop);
sqlite3ReleaseTempReg(pParse, regRecord);
@@ -126778,7 +118051,6 @@ end_auto_index_create:
static sqlite3_index_info *allocateIndexInfo(
Parse *pParse,
WhereClause *pWC,
- Bitmask mUnusable, /* Ignore terms with these prereqs */
struct SrcList_item *pSrc,
ExprList *pOrderBy
){
@@ -126795,15 +118067,12 @@ static sqlite3_index_info *allocateIndexInfo(
** to this virtual table */
for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
if( pTerm->leftCursor != pSrc->iCursor ) continue;
- if( pTerm->prereqRight & mUnusable ) continue;
assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
testcase( pTerm->eOperator & WO_IN );
testcase( pTerm->eOperator & WO_ISNULL );
- testcase( pTerm->eOperator & WO_IS );
testcase( pTerm->eOperator & WO_ALL );
- if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue;
+ if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV))==0 ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue;
- assert( pTerm->u.leftColumn>=(-1) );
nTerm++;
}
@@ -126851,22 +118120,16 @@ static sqlite3_index_info *allocateIndexInfo(
for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
u8 op;
if( pTerm->leftCursor != pSrc->iCursor ) continue;
- if( pTerm->prereqRight & mUnusable ) continue;
assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
testcase( pTerm->eOperator & WO_IN );
- testcase( pTerm->eOperator & WO_IS );
testcase( pTerm->eOperator & WO_ISNULL );
testcase( pTerm->eOperator & WO_ALL );
- if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue;
+ if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV))==0 ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue;
- assert( pTerm->u.leftColumn>=(-1) );
pIdxCons[j].iColumn = pTerm->u.leftColumn;
pIdxCons[j].iTermOffset = i;
op = (u8)pTerm->eOperator & WO_ALL;
if( op==WO_IN ) op = WO_EQ;
- if( op==WO_MATCH ){
- op = pTerm->eMatchOp;
- }
pIdxCons[j].op = op;
/* The direct assignment in the previous line is possible only because
** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
@@ -126905,6 +118168,7 @@ static sqlite3_index_info *allocateIndexInfo(
*/
static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab;
+ int i;
int rc;
TRACE_IDX_INPUTS(p);
@@ -126913,7 +118177,7 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
if( rc!=SQLITE_OK ){
if( rc==SQLITE_NOMEM ){
- sqlite3OomFault(pParse->db);
+ pParse->db->mallocFailed = 1;
}else if( !pVtab->zErrMsg ){
sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc));
}else{
@@ -126923,16 +118187,12 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
sqlite3_free(pVtab->zErrMsg);
pVtab->zErrMsg = 0;
-#if 0
- /* This error is now caught by the caller.
- ** Search for "xBestIndex malfunction" below */
for(i=0; i<p->nConstraint; i++){
if( !p->aConstraint[i].usable && p->aConstraintUsage[i].argvIndex>0 ){
sqlite3ErrorMsg(pParse,
"table %s: xBestIndex returned an invalid plan", pTab->zName);
}
}
-#endif
return pParse->nErr;
}
@@ -127156,21 +118416,6 @@ static LogEst whereRangeAdjust(WhereTerm *pTerm, LogEst nNew){
return nRet;
}
-
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
-/*
-** Return the affinity for a single column of an index.
-*/
-static char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){
- assert( iCol>=0 && iCol<pIdx->nColumn );
- if( !pIdx->zColAff ){
- if( sqlite3IndexAffinityStr(db, pIdx)==0 ) return SQLITE_AFF_BLOB;
- }
- return pIdx->zColAff[iCol];
-}
-#endif
-
-
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
/*
** This function is called to estimate the number of rows visited by a
@@ -127220,7 +118465,8 @@ static int whereRangeSkipScanEst(
int nLower = -1;
int nUpper = p->nSample+1;
int rc = SQLITE_OK;
- u8 aff = sqlite3IndexColumnAffinity(db, p, nEq);
+ int iCol = p->aiColumn[nEq];
+ u8 aff = iCol>=0 ? p->pTable->aCol[iCol].affinity : SQLITE_AFF_INTEGER;
CollSeq *pColl;
sqlite3_value *p1 = 0; /* Value extracted from pLower */
@@ -127368,8 +118614,11 @@ static int whereRangeScanEst(
testcase( pRec->nField!=pBuilder->nRecValid );
pRec->nField = pBuilder->nRecValid;
}
- aff = sqlite3IndexColumnAffinity(pParse->db, p, nEq);
- assert( nEq!=p->nKeyCol || aff==SQLITE_AFF_INTEGER );
+ if( nEq==p->nKeyCol ){
+ aff = SQLITE_AFF_INTEGER;
+ }else{
+ aff = p->pTable->aCol[p->aiColumn[nEq]].affinity;
+ }
/* Determine iLower and iUpper using ($P) only. */
if( nEq==0 ){
iLower = 0;
@@ -127527,7 +118776,7 @@ static int whereEqualScanEst(
return SQLITE_OK;
}
- aff = sqlite3IndexColumnAffinity(pParse->db, p, nEq-1);
+ aff = p->pTable->aCol[p->aiColumn[nEq-1]].affinity;
rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq-1, &bOk);
pBuilder->pRec = pRec;
if( rc!=SQLITE_OK ) return rc;
@@ -127535,8 +118784,7 @@ static int whereEqualScanEst(
pBuilder->nRecValid = nEq;
whereKeyStats(pParse, p, pRec, 0, a);
- WHERETRACE(0x10,("equality scan regions %s(%d): %d\n",
- p->zName, nEq-1, (int)a[1]));
+ WHERETRACE(0x10,("equality scan regions: %d\n", (int)a[1]));
*pnRow = a[1];
return rc;
@@ -127592,6 +118840,1484 @@ static int whereInScanEst(
}
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
+/*
+** Disable a term in the WHERE clause. Except, do not disable the term
+** if it controls a LEFT OUTER JOIN and it did not originate in the ON
+** or USING clause of that join.
+**
+** Consider the term t2.z='ok' in the following queries:
+**
+** (1) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x WHERE t2.z='ok'
+** (2) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x AND t2.z='ok'
+** (3) SELECT * FROM t1, t2 WHERE t1.a=t2.x AND t2.z='ok'
+**
+** The t2.z='ok' is disabled in the in (2) because it originates
+** in the ON clause. The term is disabled in (3) because it is not part
+** of a LEFT OUTER JOIN. In (1), the term is not disabled.
+**
+** Disabling a term causes that term to not be tested in the inner loop
+** of the join. Disabling is an optimization. When terms are satisfied
+** by indices, we disable them to prevent redundant tests in the inner
+** loop. We would get the correct results if nothing were ever disabled,
+** but joins might run a little slower. The trick is to disable as much
+** as we can without disabling too much. If we disabled in (1), we'd get
+** the wrong answer. See ticket #813.
+**
+** If all the children of a term are disabled, then that term is also
+** automatically disabled. In this way, terms get disabled if derived
+** virtual terms are tested first. For example:
+**
+** x GLOB 'abc*' AND x>='abc' AND x<'acd'
+** \___________/ \______/ \_____/
+** parent child1 child2
+**
+** Only the parent term was in the original WHERE clause. The child1
+** and child2 terms were added by the LIKE optimization. If both of
+** the virtual child terms are valid, then testing of the parent can be
+** skipped.
+**
+** Usually the parent term is marked as TERM_CODED. But if the parent
+** term was originally TERM_LIKE, then the parent gets TERM_LIKECOND instead.
+** The TERM_LIKECOND marking indicates that the term should be coded inside
+** a conditional such that is only evaluated on the second pass of a
+** LIKE-optimization loop, when scanning BLOBs instead of strings.
+*/
+static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
+ int nLoop = 0;
+ while( pTerm
+ && (pTerm->wtFlags & TERM_CODED)==0
+ && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
+ && (pLevel->notReady & pTerm->prereqAll)==0
+ ){
+ if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){
+ pTerm->wtFlags |= TERM_LIKECOND;
+ }else{
+ pTerm->wtFlags |= TERM_CODED;
+ }
+ if( pTerm->iParent<0 ) break;
+ pTerm = &pTerm->pWC->a[pTerm->iParent];
+ pTerm->nChild--;
+ if( pTerm->nChild!=0 ) break;
+ nLoop++;
+ }
+}
+
+/*
+** Code an OP_Affinity opcode to apply the column affinity string zAff
+** to the n registers starting at base.
+**
+** As an optimization, SQLITE_AFF_NONE entries (which are no-ops) at the
+** beginning and end of zAff are ignored. If all entries in zAff are
+** SQLITE_AFF_NONE, then no code gets generated.
+**
+** This routine makes its own copy of zAff so that the caller is free
+** to modify zAff after this routine returns.
+*/
+static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){
+ Vdbe *v = pParse->pVdbe;
+ if( zAff==0 ){
+ assert( pParse->db->mallocFailed );
+ return;
+ }
+ assert( v!=0 );
+
+ /* Adjust base and n to skip over SQLITE_AFF_NONE entries at the beginning
+ ** and end of the affinity string.
+ */
+ while( n>0 && zAff[0]==SQLITE_AFF_NONE ){
+ n--;
+ base++;
+ zAff++;
+ }
+ while( n>1 && zAff[n-1]==SQLITE_AFF_NONE ){
+ n--;
+ }
+
+ /* Code the OP_Affinity opcode if there is anything left to do. */
+ if( n>0 ){
+ sqlite3VdbeAddOp2(v, OP_Affinity, base, n);
+ sqlite3VdbeChangeP4(v, -1, zAff, n);
+ sqlite3ExprCacheAffinityChange(pParse, base, n);
+ }
+}
+
+
+/*
+** Generate code for a single equality term of the WHERE clause. An equality
+** term can be either X=expr or X IN (...). pTerm is the term to be
+** coded.
+**
+** The current value for the constraint is left in register iReg.
+**
+** For a constraint of the form X=expr, the expression is evaluated and its
+** result is left on the stack. For constraints of the form X IN (...)
+** this routine sets up a loop that will iterate over all values of X.
+*/
+static int codeEqualityTerm(
+ Parse *pParse, /* The parsing context */
+ WhereTerm *pTerm, /* The term of the WHERE clause to be coded */
+ WhereLevel *pLevel, /* The level of the FROM clause we are working on */
+ int iEq, /* Index of the equality term within this level */
+ int bRev, /* True for reverse-order IN operations */
+ int iTarget /* Attempt to leave results in this register */
+){
+ Expr *pX = pTerm->pExpr;
+ Vdbe *v = pParse->pVdbe;
+ int iReg; /* Register holding results */
+
+ assert( iTarget>0 );
+ if( pX->op==TK_EQ ){
+ iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget);
+ }else if( pX->op==TK_ISNULL ){
+ iReg = iTarget;
+ sqlite3VdbeAddOp2(v, OP_Null, 0, iReg);
+#ifndef SQLITE_OMIT_SUBQUERY
+ }else{
+ int eType;
+ int iTab;
+ struct InLoop *pIn;
+ WhereLoop *pLoop = pLevel->pWLoop;
+
+ if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0
+ && pLoop->u.btree.pIndex!=0
+ && pLoop->u.btree.pIndex->aSortOrder[iEq]
+ ){
+ testcase( iEq==0 );
+ testcase( bRev );
+ bRev = !bRev;
+ }
+ assert( pX->op==TK_IN );
+ iReg = iTarget;
+ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0);
+ if( eType==IN_INDEX_INDEX_DESC ){
+ testcase( bRev );
+ bRev = !bRev;
+ }
+ iTab = pX->iTable;
+ sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
+ VdbeCoverageIf(v, bRev);
+ VdbeCoverageIf(v, !bRev);
+ assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 );
+ pLoop->wsFlags |= WHERE_IN_ABLE;
+ if( pLevel->u.in.nIn==0 ){
+ pLevel->addrNxt = sqlite3VdbeMakeLabel(v);
+ }
+ pLevel->u.in.nIn++;
+ pLevel->u.in.aInLoop =
+ sqlite3DbReallocOrFree(pParse->db, pLevel->u.in.aInLoop,
+ sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn);
+ pIn = pLevel->u.in.aInLoop;
+ if( pIn ){
+ pIn += pLevel->u.in.nIn - 1;
+ pIn->iCur = iTab;
+ if( eType==IN_INDEX_ROWID ){
+ pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg);
+ }else{
+ pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg);
+ }
+ pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen;
+ sqlite3VdbeAddOp1(v, OP_IsNull, iReg); VdbeCoverage(v);
+ }else{
+ pLevel->u.in.nIn = 0;
+ }
+#endif
+ }
+ disableTerm(pLevel, pTerm);
+ return iReg;
+}
+
+/*
+** Generate code that will evaluate all == and IN constraints for an
+** index scan.
+**
+** For example, consider table t1(a,b,c,d,e,f) with index i1(a,b,c).
+** Suppose the WHERE clause is this: a==5 AND b IN (1,2,3) AND c>5 AND c<10
+** The index has as many as three equality constraints, but in this
+** example, the third "c" value is an inequality. So only two
+** constraints are coded. This routine will generate code to evaluate
+** a==5 and b IN (1,2,3). The current values for a and b will be stored
+** in consecutive registers and the index of the first register is returned.
+**
+** In the example above nEq==2. But this subroutine works for any value
+** of nEq including 0. If nEq==0, this routine is nearly a no-op.
+** The only thing it does is allocate the pLevel->iMem memory cell and
+** compute the affinity string.
+**
+** The nExtraReg parameter is 0 or 1. It is 0 if all WHERE clause constraints
+** are == or IN and are covered by the nEq. nExtraReg is 1 if there is
+** an inequality constraint (such as the "c>=5 AND c<10" in the example) that
+** occurs after the nEq quality constraints.
+**
+** This routine allocates a range of nEq+nExtraReg memory cells and returns
+** the index of the first memory cell in that range. The code that
+** calls this routine will use that memory range to store keys for
+** start and termination conditions of the loop.
+** key value of the loop. If one or more IN operators appear, then
+** this routine allocates an additional nEq memory cells for internal
+** use.
+**
+** Before returning, *pzAff is set to point to a buffer containing a
+** copy of the column affinity string of the index allocated using
+** sqlite3DbMalloc(). Except, entries in the copy of the string associated
+** with equality constraints that use NONE affinity are set to
+** SQLITE_AFF_NONE. This is to deal with SQL such as the following:
+**
+** CREATE TABLE t1(a TEXT PRIMARY KEY, b);
+** SELECT ... FROM t1 AS t2, t1 WHERE t1.a = t2.b;
+**
+** In the example above, the index on t1(a) has TEXT affinity. But since
+** the right hand side of the equality constraint (t2.b) has NONE affinity,
+** no conversion should be attempted before using a t2.b value as part of
+** a key to search the index. Hence the first byte in the returned affinity
+** string in this example would be set to SQLITE_AFF_NONE.
+*/
+static int codeAllEqualityTerms(
+ Parse *pParse, /* Parsing context */
+ WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */
+ int bRev, /* Reverse the order of IN operators */
+ int nExtraReg, /* Number of extra registers to allocate */
+ char **pzAff /* OUT: Set to point to affinity string */
+){
+ u16 nEq; /* The number of == or IN constraints to code */
+ u16 nSkip; /* Number of left-most columns to skip */
+ Vdbe *v = pParse->pVdbe; /* The vm under construction */
+ Index *pIdx; /* The index being used for this loop */
+ WhereTerm *pTerm; /* A single constraint term */
+ WhereLoop *pLoop; /* The WhereLoop object */
+ int j; /* Loop counter */
+ int regBase; /* Base register */
+ int nReg; /* Number of registers to allocate */
+ char *zAff; /* Affinity string to return */
+
+ /* This module is only called on query plans that use an index. */
+ pLoop = pLevel->pWLoop;
+ assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 );
+ nEq = pLoop->u.btree.nEq;
+ nSkip = pLoop->nSkip;
+ pIdx = pLoop->u.btree.pIndex;
+ assert( pIdx!=0 );
+
+ /* Figure out how many memory cells we will need then allocate them.
+ */
+ regBase = pParse->nMem + 1;
+ nReg = pLoop->u.btree.nEq + nExtraReg;
+ pParse->nMem += nReg;
+
+ zAff = sqlite3DbStrDup(pParse->db, sqlite3IndexAffinityStr(v, pIdx));
+ if( !zAff ){
+ pParse->db->mallocFailed = 1;
+ }
+
+ if( nSkip ){
+ int iIdxCur = pLevel->iIdxCur;
+ sqlite3VdbeAddOp1(v, (bRev?OP_Last:OP_Rewind), iIdxCur);
+ VdbeCoverageIf(v, bRev==0);
+ VdbeCoverageIf(v, bRev!=0);
+ VdbeComment((v, "begin skip-scan on %s", pIdx->zName));
+ j = sqlite3VdbeAddOp0(v, OP_Goto);
+ pLevel->addrSkip = sqlite3VdbeAddOp4Int(v, (bRev?OP_SeekLT:OP_SeekGT),
+ iIdxCur, 0, regBase, nSkip);
+ VdbeCoverageIf(v, bRev==0);
+ VdbeCoverageIf(v, bRev!=0);
+ sqlite3VdbeJumpHere(v, j);
+ for(j=0; j<nSkip; j++){
+ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, j, regBase+j);
+ assert( pIdx->aiColumn[j]>=0 );
+ VdbeComment((v, "%s", pIdx->pTable->aCol[pIdx->aiColumn[j]].zName));
+ }
+ }
+
+ /* Evaluate the equality constraints
+ */
+ assert( zAff==0 || (int)strlen(zAff)>=nEq );
+ for(j=nSkip; j<nEq; j++){
+ int r1;
+ pTerm = pLoop->aLTerm[j];
+ assert( pTerm!=0 );
+ /* The following testcase is true for indices with redundant columns.
+ ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
+ testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
+ testcase( pTerm->wtFlags & TERM_VIRTUAL );
+ r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, regBase+j);
+ if( r1!=regBase+j ){
+ if( nReg==1 ){
+ sqlite3ReleaseTempReg(pParse, regBase);
+ regBase = r1;
+ }else{
+ sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j);
+ }
+ }
+ testcase( pTerm->eOperator & WO_ISNULL );
+ testcase( pTerm->eOperator & WO_IN );
+ if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
+ Expr *pRight = pTerm->pExpr->pRight;
+ if( sqlite3ExprCanBeNull(pRight) ){
+ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk);
+ VdbeCoverage(v);
+ }
+ if( zAff ){
+ if( sqlite3CompareAffinity(pRight, zAff[j])==SQLITE_AFF_NONE ){
+ zAff[j] = SQLITE_AFF_NONE;
+ }
+ if( sqlite3ExprNeedsNoAffinityChange(pRight, zAff[j]) ){
+ zAff[j] = SQLITE_AFF_NONE;
+ }
+ }
+ }
+ }
+ *pzAff = zAff;
+ 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);
+ sqlite3StrAccumAppendAll(pStr, zColumn);
+ sqlite3StrAccumAppend(pStr, zOp, 1);
+ sqlite3StrAccumAppend(pStr, "?", 1);
+}
+
+/*
+** Argument pLevel describes a strategy for scanning table pTab. This
+** function appends text to pStr that describes the subset of table
+** rows scanned by the strategy in the form of an SQL expression.
+**
+** For example, if the query:
+**
+** 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>?"
+*/
+static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){
+ Index *pIndex = pLoop->u.btree.pIndex;
+ u16 nEq = pLoop->u.btree.nEq;
+ u16 nSkip = pLoop->nSkip;
+ int i, j;
+ Column *aCol = pTab->aCol;
+ i16 *aiColumn = pIndex->aiColumn;
+
+ if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return;
+ sqlite3StrAccumAppend(pStr, " (", 2);
+ for(i=0; i<nEq; i++){
+ char *z = aiColumn[i] < 0 ? "rowid" : aCol[aiColumn[i]].zName;
+ if( i>=nSkip ){
+ explainAppendTerm(pStr, i, z, "=");
+ }else{
+ if( i ) sqlite3StrAccumAppend(pStr, " AND ", 5);
+ sqlite3XPrintf(pStr, 0, "ANY(%s)", z);
+ }
+ }
+
+ j = i;
+ if( pLoop->wsFlags&WHERE_BTM_LIMIT ){
+ char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName;
+ explainAppendTerm(pStr, i++, z, ">");
+ }
+ if( pLoop->wsFlags&WHERE_TOP_LIMIT ){
+ char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName;
+ explainAppendTerm(pStr, i, z, "<");
+ }
+ sqlite3StrAccumAppend(pStr, ")", 1);
+}
+
+/*
+** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
+** command, or if either SQLITE_DEBUG or SQLITE_ENABLE_STMT_SCANSTATUS was
+** defined at compile-time. If it is not a no-op, a single OP_Explain opcode
+** is added to the output to describe the table scan strategy in pLevel.
+**
+** If an OP_Explain opcode is added to the VM, its address is returned.
+** Otherwise, if no OP_Explain is coded, zero is returned.
+*/
+static int 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() */
+){
+ int ret = 0;
+#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+ if( pParse->explain==2 )
+#endif
+ {
+ struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
+ Vdbe *v = pParse->pVdbe; /* VM being constructed */
+ sqlite3 *db = pParse->db; /* Database handle */
+ int iId = pParse->iSelectId; /* Select id (left-most output column) */
+ int isSearch; /* True for a SEARCH. False for SCAN. */
+ WhereLoop *pLoop; /* The controlling WhereLoop object */
+ u32 flags; /* Flags that describe this loop */
+ char *zMsg; /* Text to add to EQP output */
+ StrAccum str; /* EQP output string */
+ char zBuf[100]; /* Initial space for EQP output string */
+
+ pLoop = pLevel->pWLoop;
+ flags = pLoop->wsFlags;
+ if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return 0;
+
+ isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0
+ || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0))
+ || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX));
+
+ sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
+ sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN");
+ if( pItem->pSelect ){
+ sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId);
+ }else{
+ sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName);
+ }
+
+ if( pItem->zAlias ){
+ sqlite3XPrintf(&str, 0, " AS %s", pItem->zAlias);
+ }
+ if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){
+ const char *zFmt = 0;
+ Index *pIdx;
+
+ assert( pLoop->u.btree.pIndex!=0 );
+ pIdx = pLoop->u.btree.pIndex;
+ assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) );
+ if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){
+ if( isSearch ){
+ zFmt = "PRIMARY KEY";
+ }
+ }else if( flags & WHERE_PARTIALIDX ){
+ zFmt = "AUTOMATIC PARTIAL COVERING INDEX";
+ }else if( flags & WHERE_AUTO_INDEX ){
+ zFmt = "AUTOMATIC COVERING INDEX";
+ }else if( flags & WHERE_IDX_ONLY ){
+ zFmt = "COVERING INDEX %s";
+ }else{
+ zFmt = "INDEX %s";
+ }
+ if( zFmt ){
+ sqlite3StrAccumAppend(&str, " USING ", 7);
+ sqlite3XPrintf(&str, 0, zFmt, pIdx->zName);
+ explainIndexRange(&str, pLoop, pItem->pTab);
+ }
+ }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){
+ const char *zRange;
+ if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){
+ zRange = "(rowid=?)";
+ }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){
+ zRange = "(rowid>? AND rowid<?)";
+ }else if( flags&WHERE_BTM_LIMIT ){
+ zRange = "(rowid>?)";
+ }else{
+ assert( flags&WHERE_TOP_LIMIT);
+ zRange = "(rowid<?)";
+ }
+ sqlite3StrAccumAppendAll(&str, " USING INTEGER PRIMARY KEY ");
+ sqlite3StrAccumAppendAll(&str, zRange);
+ }
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
+ sqlite3XPrintf(&str, 0, " VIRTUAL TABLE INDEX %d:%s",
+ pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
+ }
+#endif
+#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
+ if( pLoop->nOut>=10 ){
+ sqlite3XPrintf(&str, 0, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut));
+ }else{
+ sqlite3StrAccumAppend(&str, " (~1 row)", 9);
+ }
+#endif
+ zMsg = sqlite3StrAccumFinish(&str);
+ ret = sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg,P4_DYNAMIC);
+ }
+ return ret;
+}
+#else
+# define explainOneScan(u,v,w,x,y,z) 0
+#endif /* SQLITE_OMIT_EXPLAIN */
+
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+/*
+** Configure the VM passed as the first argument with an
+** sqlite3_stmt_scanstatus() entry corresponding to the scan used to
+** implement level pLvl. Argument pSrclist is a pointer to the FROM
+** clause that the scan reads data from.
+**
+** If argument addrExplain is not 0, it must be the address of an
+** OP_Explain instruction that describes the same loop.
+*/
+static void addScanStatus(
+ Vdbe *v, /* Vdbe to add scanstatus entry to */
+ SrcList *pSrclist, /* FROM clause pLvl reads data from */
+ WhereLevel *pLvl, /* Level to add scanstatus() entry for */
+ int addrExplain /* Address of OP_Explain (or 0) */
+){
+ const char *zObj = 0;
+ WhereLoop *pLoop = pLvl->pWLoop;
+ if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){
+ zObj = pLoop->u.btree.pIndex->zName;
+ }else{
+ zObj = pSrclist->a[pLvl->iFrom].zName;
+ }
+ sqlite3VdbeScanStatus(
+ v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj
+ );
+}
+#else
+# define addScanStatus(a, b, c, d) ((void)d)
+#endif
+
+/*
+** If the most recently coded instruction is a constant range contraint
+** that originated from the LIKE optimization, then change the P3 to be
+** pLoop->iLikeRepCntr and set P5.
+**
+** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range
+** expression: "x>='ABC' AND x<'abd'". But this requires that the range
+** scan loop run twice, once for strings and a second time for BLOBs.
+** The OP_String opcodes on the second pass convert the upper and lower
+** bound string contants to blobs. This routine makes the necessary changes
+** to the OP_String opcodes for that to happen.
+*/
+static void whereLikeOptimizationStringFixup(
+ Vdbe *v, /* prepared statement under construction */
+ WhereLevel *pLevel, /* The loop that contains the LIKE operator */
+ WhereTerm *pTerm /* The upper or lower bound just coded */
+){
+ if( pTerm->wtFlags & TERM_LIKEOPT ){
+ VdbeOp *pOp;
+ assert( pLevel->iLikeRepCntr>0 );
+ pOp = sqlite3VdbeGetOp(v, -1);
+ assert( pOp!=0 );
+ assert( pOp->opcode==OP_String8
+ || pTerm->pWC->pWInfo->pParse->db->mallocFailed );
+ pOp->p3 = pLevel->iLikeRepCntr;
+ pOp->p5 = 1;
+ }
+}
+
+/*
+** Generate code for the start of the iLevel-th loop in the WHERE clause
+** implementation described by pWInfo.
+*/
+static Bitmask codeOneLoopStart(
+ WhereInfo *pWInfo, /* Complete information about the WHERE clause */
+ int iLevel, /* Which level of pWInfo->a[] should be coded */
+ Bitmask notReady /* Which tables are currently available */
+){
+ int j, k; /* Loop counters */
+ int iCur; /* The VDBE cursor for the table */
+ int addrNxt; /* Where to jump to continue with the next IN case */
+ int omitTable; /* True if we use the index only */
+ int bRev; /* True if we need to scan in reverse order */
+ WhereLevel *pLevel; /* The where level to be coded */
+ WhereLoop *pLoop; /* The WhereLoop object being coded */
+ WhereClause *pWC; /* Decomposition of the entire WHERE clause */
+ WhereTerm *pTerm; /* A WHERE clause term */
+ Parse *pParse; /* Parsing context */
+ sqlite3 *db; /* Database connection */
+ Vdbe *v; /* The prepared stmt under constructions */
+ struct SrcList_item *pTabItem; /* FROM clause term being coded */
+ int addrBrk; /* Jump here to break out of the loop */
+ int addrCont; /* Jump here to continue with next cycle */
+ int iRowidReg = 0; /* Rowid is stored in this register, if not zero */
+ int iReleaseReg = 0; /* Temp register to free before returning */
+
+ pParse = pWInfo->pParse;
+ v = pParse->pVdbe;
+ pWC = &pWInfo->sWC;
+ db = pParse->db;
+ pLevel = &pWInfo->a[iLevel];
+ pLoop = pLevel->pWLoop;
+ pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
+ iCur = pTabItem->iCursor;
+ pLevel->notReady = notReady & ~getMask(&pWInfo->sMaskSet, iCur);
+ bRev = (pWInfo->revMask>>iLevel)&1;
+ omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0
+ && (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)==0;
+ VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
+
+ /* Create labels for the "break" and "continue" instructions
+ ** for the current loop. Jump to addrBrk to break out of a loop.
+ ** Jump to cont to go immediately to the next iteration of the
+ ** loop.
+ **
+ ** When there is an IN operator, we also have a "addrNxt" label that
+ ** means to continue with the next IN value combination. When
+ ** there are no IN operators in the constraints, the "addrNxt" label
+ ** is the same as "addrBrk".
+ */
+ addrBrk = pLevel->addrBrk = pLevel->addrNxt = sqlite3VdbeMakeLabel(v);
+ addrCont = pLevel->addrCont = sqlite3VdbeMakeLabel(v);
+
+ /* If this is the right table of a LEFT OUTER JOIN, allocate and
+ ** initialize a memory cell that records if this table matches any
+ ** row of the left table of the join.
+ */
+ if( pLevel->iFrom>0 && (pTabItem[0].jointype & JT_LEFT)!=0 ){
+ pLevel->iLeftJoin = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin);
+ VdbeComment((v, "init LEFT JOIN no-match flag"));
+ }
+
+ /* Special case of a FROM clause subquery implemented as a co-routine */
+ if( pTabItem->viaCoroutine ){
+ int regYield = pTabItem->regReturn;
+ sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
+ pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk);
+ VdbeCoverage(v);
+ VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName));
+ pLevel->op = OP_Goto;
+ }else
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){
+ /* Case 1: The table is a virtual-table. Use the VFilter and VNext
+ ** to access the data.
+ */
+ int iReg; /* P3 Value for OP_VFilter */
+ int addrNotFound;
+ int nConstraint = pLoop->nLTerm;
+
+ sqlite3ExprCachePush(pParse);
+ iReg = sqlite3GetTempRange(pParse, nConstraint+2);
+ addrNotFound = pLevel->addrBrk;
+ for(j=0; j<nConstraint; j++){
+ int iTarget = iReg+j+2;
+ pTerm = pLoop->aLTerm[j];
+ if( pTerm==0 ) continue;
+ if( pTerm->eOperator & WO_IN ){
+ codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget);
+ addrNotFound = pLevel->addrNxt;
+ }else{
+ sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget);
+ }
+ }
+ sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg);
+ sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1);
+ sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg,
+ pLoop->u.vtab.idxStr,
+ pLoop->u.vtab.needFree ? P4_MPRINTF : P4_STATIC);
+ VdbeCoverage(v);
+ pLoop->u.vtab.needFree = 0;
+ for(j=0; j<nConstraint && j<16; j++){
+ if( (pLoop->u.vtab.omitMask>>j)&1 ){
+ disableTerm(pLevel, pLoop->aLTerm[j]);
+ }
+ }
+ pLevel->op = OP_VNext;
+ pLevel->p1 = iCur;
+ pLevel->p2 = sqlite3VdbeCurrentAddr(v);
+ sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
+ sqlite3ExprCachePop(pParse);
+ }else
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+ if( (pLoop->wsFlags & WHERE_IPK)!=0
+ && (pLoop->wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_EQ))!=0
+ ){
+ /* Case 2: We can directly reference a single row using an
+ ** equality comparison against the ROWID field. Or
+ ** we reference multiple rows using a "rowid IN (...)"
+ ** construct.
+ */
+ assert( pLoop->u.btree.nEq==1 );
+ pTerm = pLoop->aLTerm[0];
+ assert( pTerm!=0 );
+ assert( pTerm->pExpr!=0 );
+ assert( omitTable==0 );
+ testcase( pTerm->wtFlags & TERM_VIRTUAL );
+ iReleaseReg = ++pParse->nMem;
+ iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg);
+ if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg);
+ addrNxt = pLevel->addrNxt;
+ sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt); VdbeCoverage(v);
+ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg);
+ VdbeCoverage(v);
+ sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1);
+ sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
+ VdbeComment((v, "pk"));
+ pLevel->op = OP_Noop;
+ }else if( (pLoop->wsFlags & WHERE_IPK)!=0
+ && (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0
+ ){
+ /* Case 3: We have an inequality comparison against the ROWID field.
+ */
+ int testOp = OP_Noop;
+ int start;
+ int memEndValue = 0;
+ WhereTerm *pStart, *pEnd;
+
+ assert( omitTable==0 );
+ j = 0;
+ pStart = pEnd = 0;
+ if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aLTerm[j++];
+ if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aLTerm[j++];
+ assert( pStart!=0 || pEnd!=0 );
+ if( bRev ){
+ pTerm = pStart;
+ pStart = pEnd;
+ pEnd = pTerm;
+ }
+ if( pStart ){
+ Expr *pX; /* The expression that defines the start bound */
+ int r1, rTemp; /* Registers for holding the start boundary */
+
+ /* The following constant maps TK_xx codes into corresponding
+ ** seek opcodes. It depends on a particular ordering of TK_xx
+ */
+ const u8 aMoveOp[] = {
+ /* TK_GT */ OP_SeekGT,
+ /* TK_LE */ OP_SeekLE,
+ /* TK_LT */ OP_SeekLT,
+ /* TK_GE */ OP_SeekGE
+ };
+ assert( TK_LE==TK_GT+1 ); /* Make sure the ordering.. */
+ assert( TK_LT==TK_GT+2 ); /* ... of the TK_xx values... */
+ assert( TK_GE==TK_GT+3 ); /* ... is correcct. */
+
+ assert( (pStart->wtFlags & TERM_VNULL)==0 );
+ testcase( pStart->wtFlags & TERM_VIRTUAL );
+ pX = pStart->pExpr;
+ assert( pX!=0 );
+ testcase( pStart->leftCursor!=iCur ); /* transitive constraints */
+ r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp);
+ sqlite3VdbeAddOp3(v, aMoveOp[pX->op-TK_GT], iCur, addrBrk, r1);
+ VdbeComment((v, "pk"));
+ VdbeCoverageIf(v, pX->op==TK_GT);
+ VdbeCoverageIf(v, pX->op==TK_LE);
+ VdbeCoverageIf(v, pX->op==TK_LT);
+ VdbeCoverageIf(v, pX->op==TK_GE);
+ sqlite3ExprCacheAffinityChange(pParse, r1, 1);
+ sqlite3ReleaseTempReg(pParse, rTemp);
+ disableTerm(pLevel, pStart);
+ }else{
+ sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrBrk);
+ VdbeCoverageIf(v, bRev==0);
+ VdbeCoverageIf(v, bRev!=0);
+ }
+ if( pEnd ){
+ Expr *pX;
+ pX = pEnd->pExpr;
+ assert( pX!=0 );
+ assert( (pEnd->wtFlags & TERM_VNULL)==0 );
+ testcase( pEnd->leftCursor!=iCur ); /* Transitive constraints */
+ testcase( pEnd->wtFlags & TERM_VIRTUAL );
+ memEndValue = ++pParse->nMem;
+ sqlite3ExprCode(pParse, pX->pRight, memEndValue);
+ if( pX->op==TK_LT || pX->op==TK_GT ){
+ testOp = bRev ? OP_Le : OP_Ge;
+ }else{
+ testOp = bRev ? OP_Lt : OP_Gt;
+ }
+ disableTerm(pLevel, pEnd);
+ }
+ start = sqlite3VdbeCurrentAddr(v);
+ pLevel->op = bRev ? OP_Prev : OP_Next;
+ pLevel->p1 = iCur;
+ pLevel->p2 = start;
+ assert( pLevel->p5==0 );
+ if( testOp!=OP_Noop ){
+ iRowidReg = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg);
+ sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
+ sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg);
+ VdbeCoverageIf(v, testOp==OP_Le);
+ VdbeCoverageIf(v, testOp==OP_Lt);
+ VdbeCoverageIf(v, testOp==OP_Ge);
+ VdbeCoverageIf(v, testOp==OP_Gt);
+ sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL);
+ }
+ }else if( pLoop->wsFlags & WHERE_INDEXED ){
+ /* Case 4: A scan using an index.
+ **
+ ** The WHERE clause may contain zero or more equality
+ ** terms ("==" or "IN" operators) that refer to the N
+ ** left-most columns of the index. It may also contain
+ ** inequality constraints (>, <, >= or <=) on the indexed
+ ** column that immediately follows the N equalities. Only
+ ** the right-most column can be an inequality - the rest must
+ ** use the "==" and "IN" operators. For example, if the
+ ** index is on (x,y,z), then the following clauses are all
+ ** optimized:
+ **
+ ** x=5
+ ** x=5 AND y=10
+ ** x=5 AND y<10
+ ** x=5 AND y>5 AND y<10
+ ** x=5 AND y=5 AND z<=10
+ **
+ ** The z<10 term of the following cannot be used, only
+ ** the x=5 term:
+ **
+ ** x=5 AND z<10
+ **
+ ** N may be zero if there are inequality constraints.
+ ** If there are no inequality constraints, then N is at
+ ** least one.
+ **
+ ** This case is also used when there are no WHERE clause
+ ** constraints but an index is selected anyway, in order
+ ** to force the output order to conform to an ORDER BY.
+ */
+ static const u8 aStartOp[] = {
+ 0,
+ 0,
+ OP_Rewind, /* 2: (!start_constraints && startEq && !bRev) */
+ OP_Last, /* 3: (!start_constraints && startEq && bRev) */
+ OP_SeekGT, /* 4: (start_constraints && !startEq && !bRev) */
+ OP_SeekLT, /* 5: (start_constraints && !startEq && bRev) */
+ OP_SeekGE, /* 6: (start_constraints && startEq && !bRev) */
+ OP_SeekLE /* 7: (start_constraints && startEq && bRev) */
+ };
+ static const u8 aEndOp[] = {
+ OP_IdxGE, /* 0: (end_constraints && !bRev && !endEq) */
+ OP_IdxGT, /* 1: (end_constraints && !bRev && endEq) */
+ OP_IdxLE, /* 2: (end_constraints && bRev && !endEq) */
+ OP_IdxLT, /* 3: (end_constraints && bRev && endEq) */
+ };
+ u16 nEq = pLoop->u.btree.nEq; /* Number of == or IN terms */
+ int regBase; /* Base register holding constraint values */
+ WhereTerm *pRangeStart = 0; /* Inequality constraint at range start */
+ WhereTerm *pRangeEnd = 0; /* Inequality constraint at range end */
+ int startEq; /* True if range start uses ==, >= or <= */
+ int endEq; /* True if range end uses ==, >= or <= */
+ int start_constraints; /* Start of range is constrained */
+ int nConstraint; /* Number of constraint terms */
+ Index *pIdx; /* The index we will be using */
+ int iIdxCur; /* The VDBE cursor for the index */
+ int nExtraReg = 0; /* Number of extra registers needed */
+ int op; /* Instruction opcode */
+ char *zStartAff; /* Affinity for start of range constraint */
+ char cEndAff = 0; /* Affinity for end of range constraint */
+ u8 bSeekPastNull = 0; /* True to seek past initial nulls */
+ u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */
+
+ pIdx = pLoop->u.btree.pIndex;
+ iIdxCur = pLevel->iIdxCur;
+ assert( nEq>=pLoop->nSkip );
+
+ /* If this loop satisfies a sort order (pOrderBy) request that
+ ** was passed to this function to implement a "SELECT min(x) ..."
+ ** query, then the caller will only allow the loop to run for
+ ** a single iteration. This means that the first row returned
+ ** should not have a NULL value stored in 'x'. If column 'x' is
+ ** the first one after the nEq equality constraints in the index,
+ ** this requires some special handling.
+ */
+ assert( pWInfo->pOrderBy==0
+ || pWInfo->pOrderBy->nExpr==1
+ || (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 );
+ if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0
+ && pWInfo->nOBSat>0
+ && (pIdx->nKeyCol>nEq)
+ ){
+ assert( pLoop->nSkip==0 );
+ bSeekPastNull = 1;
+ nExtraReg = 1;
+ }
+
+ /* Find any inequality constraint terms for the start and end
+ ** of the range.
+ */
+ j = nEq;
+ if( pLoop->wsFlags & WHERE_BTM_LIMIT ){
+ pRangeStart = pLoop->aLTerm[j++];
+ nExtraReg = 1;
+ /* Like optimization range constraints always occur in pairs */
+ assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 ||
+ (pLoop->wsFlags & WHERE_TOP_LIMIT)!=0 );
+ }
+ if( pLoop->wsFlags & WHERE_TOP_LIMIT ){
+ pRangeEnd = pLoop->aLTerm[j++];
+ nExtraReg = 1;
+ if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){
+ assert( pRangeStart!=0 ); /* LIKE opt constraints */
+ assert( pRangeStart->wtFlags & TERM_LIKEOPT ); /* occur in pairs */
+ pLevel->iLikeRepCntr = ++pParse->nMem;
+ testcase( bRev );
+ testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC );
+ sqlite3VdbeAddOp2(v, OP_Integer,
+ bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC),
+ pLevel->iLikeRepCntr);
+ VdbeComment((v, "LIKE loop counter"));
+ pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v);
+ }
+ if( pRangeStart==0
+ && (j = pIdx->aiColumn[nEq])>=0
+ && pIdx->pTable->aCol[j].notNull==0
+ ){
+ bSeekPastNull = 1;
+ }
+ }
+ assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 );
+
+ /* Generate code to evaluate all constraint terms using == or IN
+ ** and store the values of those terms in an array of registers
+ ** starting at regBase.
+ */
+ regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff);
+ assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq );
+ if( zStartAff ) cEndAff = zStartAff[nEq];
+ addrNxt = pLevel->addrNxt;
+
+ /* If we are doing a reverse order scan on an ascending index, or
+ ** a forward order scan on a descending index, interchange the
+ ** start and end terms (pRangeStart and pRangeEnd).
+ */
+ if( (nEq<pIdx->nKeyCol && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC))
+ || (bRev && pIdx->nKeyCol==nEq)
+ ){
+ SWAP(WhereTerm *, pRangeEnd, pRangeStart);
+ SWAP(u8, bSeekPastNull, bStopAtNull);
+ }
+
+ testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 );
+ testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 );
+ testcase( pRangeEnd && (pRangeEnd->eOperator & WO_LE)!=0 );
+ testcase( pRangeEnd && (pRangeEnd->eOperator & WO_GE)!=0 );
+ startEq = !pRangeStart || pRangeStart->eOperator & (WO_LE|WO_GE);
+ endEq = !pRangeEnd || pRangeEnd->eOperator & (WO_LE|WO_GE);
+ start_constraints = pRangeStart || nEq>0;
+
+ /* Seek the index cursor to the start of the range. */
+ nConstraint = nEq;
+ if( pRangeStart ){
+ Expr *pRight = pRangeStart->pExpr->pRight;
+ sqlite3ExprCode(pParse, pRight, regBase+nEq);
+ whereLikeOptimizationStringFixup(v, pLevel, pRangeStart);
+ if( (pRangeStart->wtFlags & TERM_VNULL)==0
+ && sqlite3ExprCanBeNull(pRight)
+ ){
+ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
+ VdbeCoverage(v);
+ }
+ if( zStartAff ){
+ if( sqlite3CompareAffinity(pRight, zStartAff[nEq])==SQLITE_AFF_NONE){
+ /* Since the comparison is to be performed with no conversions
+ ** applied to the operands, set the affinity to apply to pRight to
+ ** SQLITE_AFF_NONE. */
+ zStartAff[nEq] = SQLITE_AFF_NONE;
+ }
+ if( sqlite3ExprNeedsNoAffinityChange(pRight, zStartAff[nEq]) ){
+ zStartAff[nEq] = SQLITE_AFF_NONE;
+ }
+ }
+ nConstraint++;
+ testcase( pRangeStart->wtFlags & TERM_VIRTUAL );
+ }else if( bSeekPastNull ){
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
+ nConstraint++;
+ startEq = 0;
+ start_constraints = 1;
+ }
+ codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff);
+ op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
+ assert( op!=0 );
+ sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
+ VdbeCoverage(v);
+ VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind );
+ VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last );
+ VdbeCoverageIf(v, op==OP_SeekGT); testcase( op==OP_SeekGT );
+ VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE );
+ VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE );
+ VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT );
+
+ /* Load the value for the inequality constraint at the end of the
+ ** range (if any).
+ */
+ nConstraint = nEq;
+ if( pRangeEnd ){
+ Expr *pRight = pRangeEnd->pExpr->pRight;
+ sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
+ sqlite3ExprCode(pParse, pRight, regBase+nEq);
+ whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
+ if( (pRangeEnd->wtFlags & TERM_VNULL)==0
+ && sqlite3ExprCanBeNull(pRight)
+ ){
+ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
+ VdbeCoverage(v);
+ }
+ if( sqlite3CompareAffinity(pRight, cEndAff)!=SQLITE_AFF_NONE
+ && !sqlite3ExprNeedsNoAffinityChange(pRight, cEndAff)
+ ){
+ codeApplyAffinity(pParse, regBase+nEq, 1, &cEndAff);
+ }
+ nConstraint++;
+ testcase( pRangeEnd->wtFlags & TERM_VIRTUAL );
+ }else if( bStopAtNull ){
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
+ endEq = 0;
+ nConstraint++;
+ }
+ sqlite3DbFree(db, zStartAff);
+
+ /* Top of the loop body */
+ pLevel->p2 = sqlite3VdbeCurrentAddr(v);
+
+ /* Check if the index cursor is past the end of the range. */
+ if( nConstraint ){
+ op = aEndOp[bRev*2 + endEq];
+ sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
+ testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT );
+ testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE );
+ testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT );
+ testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE );
+ }
+
+ /* Seek the table cursor, if required */
+ disableTerm(pLevel, pRangeStart);
+ disableTerm(pLevel, pRangeEnd);
+ if( omitTable ){
+ /* pIdx is a covering index. No need to access the main table. */
+ }else if( HasRowid(pIdx->pTable) ){
+ iRowidReg = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
+ sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
+ sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg); /* Deferred seek */
+ }else if( iCur!=iIdxCur ){
+ Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
+ iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol);
+ for(j=0; j<pPk->nKeyCol; j++){
+ k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
+ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, iRowidReg+j);
+ }
+ sqlite3VdbeAddOp4Int(v, OP_NotFound, iCur, addrCont,
+ iRowidReg, pPk->nKeyCol); VdbeCoverage(v);
+ }
+
+ /* Record the instruction used to terminate the loop. Disable
+ ** WHERE clause terms made redundant by the index range scan.
+ */
+ if( pLoop->wsFlags & WHERE_ONEROW ){
+ pLevel->op = OP_Noop;
+ }else if( bRev ){
+ pLevel->op = OP_Prev;
+ }else{
+ pLevel->op = OP_Next;
+ }
+ pLevel->p1 = iIdxCur;
+ pLevel->p3 = (pLoop->wsFlags&WHERE_UNQ_WANTED)!=0 ? 1:0;
+ if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){
+ pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
+ }else{
+ assert( pLevel->p5==0 );
+ }
+ }else
+
+#ifndef SQLITE_OMIT_OR_OPTIMIZATION
+ if( pLoop->wsFlags & WHERE_MULTI_OR ){
+ /* Case 5: Two or more separately indexed terms connected by OR
+ **
+ ** Example:
+ **
+ ** CREATE TABLE t1(a,b,c,d);
+ ** CREATE INDEX i1 ON t1(a);
+ ** CREATE INDEX i2 ON t1(b);
+ ** CREATE INDEX i3 ON t1(c);
+ **
+ ** SELECT * FROM t1 WHERE a=5 OR b=7 OR (c=11 AND d=13)
+ **
+ ** In the example, there are three indexed terms connected by OR.
+ ** The top of the loop looks like this:
+ **
+ ** Null 1 # Zero the rowset in reg 1
+ **
+ ** Then, for each indexed term, the following. The arguments to
+ ** RowSetTest are such that the rowid of the current row is inserted
+ ** into the RowSet. If it is already present, control skips the
+ ** Gosub opcode and jumps straight to the code generated by WhereEnd().
+ **
+ ** sqlite3WhereBegin(<term>)
+ ** RowSetTest # Insert rowid into rowset
+ ** Gosub 2 A
+ ** sqlite3WhereEnd()
+ **
+ ** Following the above, code to terminate the loop. Label A, the target
+ ** of the Gosub above, jumps to the instruction right after the Goto.
+ **
+ ** Null 1 # Zero the rowset in reg 1
+ ** Goto B # The loop is finished.
+ **
+ ** A: <loop body> # Return data, whatever.
+ **
+ ** Return 2 # Jump back to the Gosub
+ **
+ ** B: <after the loop>
+ **
+ ** Added 2014-05-26: If the table is a WITHOUT ROWID table, then
+ ** use an ephemeral index instead of a RowSet to record the primary
+ ** keys of the rows we have already seen.
+ **
+ */
+ WhereClause *pOrWc; /* The OR-clause broken out into subterms */
+ SrcList *pOrTab; /* Shortened table list or OR-clause generation */
+ Index *pCov = 0; /* Potential covering index (or NULL) */
+ int iCovCur = pParse->nTab++; /* Cursor used for index scans (if any) */
+
+ int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */
+ int regRowset = 0; /* Register for RowSet object */
+ int regRowid = 0; /* Register holding rowid */
+ int iLoopBody = sqlite3VdbeMakeLabel(v); /* Start of loop body */
+ int iRetInit; /* Address of regReturn init */
+ int untestedTerms = 0; /* Some terms not completely tested */
+ int ii; /* Loop counter */
+ u16 wctrlFlags; /* Flags for sub-WHERE clause */
+ Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
+ Table *pTab = pTabItem->pTab;
+
+ pTerm = pLoop->aLTerm[0];
+ assert( pTerm!=0 );
+ assert( pTerm->eOperator & WO_OR );
+ assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
+ pOrWc = &pTerm->u.pOrInfo->wc;
+ pLevel->op = OP_Return;
+ pLevel->p1 = regReturn;
+
+ /* Set up a new SrcList in pOrTab containing the table being scanned
+ ** by this loop in the a[0] slot and all notReady tables in a[1..] slots.
+ ** This becomes the SrcList in the recursive call to sqlite3WhereBegin().
+ */
+ if( pWInfo->nLevel>1 ){
+ int nNotReady; /* The number of notReady tables */
+ struct SrcList_item *origSrc; /* Original list of tables */
+ nNotReady = pWInfo->nLevel - iLevel - 1;
+ pOrTab = sqlite3StackAllocRaw(db,
+ sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0]));
+ if( pOrTab==0 ) return notReady;
+ pOrTab->nAlloc = (u8)(nNotReady + 1);
+ pOrTab->nSrc = pOrTab->nAlloc;
+ memcpy(pOrTab->a, pTabItem, sizeof(*pTabItem));
+ origSrc = pWInfo->pTabList->a;
+ for(k=1; k<=nNotReady; k++){
+ memcpy(&pOrTab->a[k], &origSrc[pLevel[k].iFrom], sizeof(pOrTab->a[k]));
+ }
+ }else{
+ pOrTab = pWInfo->pTabList;
+ }
+
+ /* Initialize the rowset register to contain NULL. An SQL NULL is
+ ** equivalent to an empty rowset. Or, create an ephemeral index
+ ** capable of holding primary keys in the case of a WITHOUT ROWID.
+ **
+ ** Also initialize regReturn to contain the address of the instruction
+ ** immediately following the OP_Return at the bottom of the loop. This
+ ** is required in a few obscure LEFT JOIN cases where control jumps
+ ** over the top of the loop into the body of it. In this case the
+ ** correct response for the end-of-loop code (the OP_Return) is to
+ ** fall through to the next instruction, just as an OP_Next does if
+ ** called on an uninitialized cursor.
+ */
+ if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
+ if( HasRowid(pTab) ){
+ regRowset = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset);
+ }else{
+ Index *pPk = sqlite3PrimaryKeyIndex(pTab);
+ regRowset = pParse->nTab++;
+ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, regRowset, pPk->nKeyCol);
+ sqlite3VdbeSetP4KeyInfo(pParse, pPk);
+ }
+ regRowid = ++pParse->nMem;
+ }
+ iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn);
+
+ /* If the original WHERE clause is z of the form: (x1 OR x2 OR ...) AND y
+ ** Then for every term xN, evaluate as the subexpression: xN AND z
+ ** That way, terms in y that are factored into the disjunction will
+ ** be picked up by the recursive calls to sqlite3WhereBegin() below.
+ **
+ ** Actually, each subexpression is converted to "xN AND w" where w is
+ ** the "interesting" terms of z - terms that did not originate in the
+ ** ON or USING clause of a LEFT JOIN, and terms that are usable as
+ ** indices.
+ **
+ ** This optimization also only applies if the (x1 OR x2 OR ...) term
+ ** is not contained in the ON clause of a LEFT JOIN.
+ ** See ticket http://www.sqlite.org/src/info/f2369304e4
+ */
+ if( pWC->nTerm>1 ){
+ int iTerm;
+ for(iTerm=0; iTerm<pWC->nTerm; iTerm++){
+ Expr *pExpr = pWC->a[iTerm].pExpr;
+ if( &pWC->a[iTerm] == pTerm ) continue;
+ if( ExprHasProperty(pExpr, EP_FromJoin) ) continue;
+ if( (pWC->a[iTerm].wtFlags & TERM_VIRTUAL)!=0 ) continue;
+ if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
+ testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO );
+ pExpr = sqlite3ExprDup(db, pExpr, 0);
+ pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr);
+ }
+ if( pAndExpr ){
+ pAndExpr = sqlite3PExpr(pParse, TK_AND, 0, pAndExpr, 0);
+ }
+ }
+
+ /* Run a separate WHERE clause for each term of the OR clause. After
+ ** eliminating duplicates from other WHERE clauses, the action for each
+ ** sub-WHERE clause is to to invoke the main loop body as a subroutine.
+ */
+ wctrlFlags = WHERE_OMIT_OPEN_CLOSE
+ | WHERE_FORCE_TABLE
+ | WHERE_ONETABLE_ONLY
+ | WHERE_NO_AUTOINDEX;
+ for(ii=0; ii<pOrWc->nTerm; ii++){
+ WhereTerm *pOrTerm = &pOrWc->a[ii];
+ if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
+ WhereInfo *pSubWInfo; /* Info for single OR-term scan */
+ Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */
+ int j1 = 0; /* Address of jump operation */
+ if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){
+ pAndExpr->pLeft = pOrExpr;
+ pOrExpr = pAndExpr;
+ }
+ /* Loop through table entries that match term pOrTerm. */
+ WHERETRACE(0xffff, ("Subplan for OR-clause:\n"));
+ pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0,
+ wctrlFlags, iCovCur);
+ assert( pSubWInfo || pParse->nErr || db->mallocFailed );
+ if( pSubWInfo ){
+ WhereLoop *pSubLoop;
+ int addrExplain = explainOneScan(
+ pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
+ );
+ addScanStatus(v, pOrTab, &pSubWInfo->a[0], addrExplain);
+
+ /* This is the sub-WHERE clause body. First skip over
+ ** duplicate rows from prior sub-WHERE clauses, and record the
+ ** rowid (or PRIMARY KEY) for the current row so that the same
+ ** row will be skipped in subsequent sub-WHERE clauses.
+ */
+ if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
+ int r;
+ int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
+ if( HasRowid(pTab) ){
+ r = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, regRowid, 0);
+ j1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0, r,iSet);
+ VdbeCoverage(v);
+ }else{
+ Index *pPk = sqlite3PrimaryKeyIndex(pTab);
+ int nPk = pPk->nKeyCol;
+ int iPk;
+
+ /* Read the PK into an array of temp registers. */
+ r = sqlite3GetTempRange(pParse, nPk);
+ for(iPk=0; iPk<nPk; iPk++){
+ int iCol = pPk->aiColumn[iPk];
+ sqlite3ExprCodeGetColumn(pParse, pTab, iCol, iCur, r+iPk, 0);
+ }
+
+ /* Check if the temp table already contains this key. If so,
+ ** the row has already been included in the result set and
+ ** can be ignored (by jumping past the Gosub below). Otherwise,
+ ** insert the key into the temp table and proceed with processing
+ ** the row.
+ **
+ ** Use some of the same optimizations as OP_RowSetTest: If iSet
+ ** is zero, assume that the key cannot already be present in
+ ** the temp table. And if iSet is -1, assume that there is no
+ ** need to insert the key into the temp table, as it will never
+ ** be tested for. */
+ if( iSet ){
+ j1 = sqlite3VdbeAddOp4Int(v, OP_Found, regRowset, 0, r, nPk);
+ VdbeCoverage(v);
+ }
+ if( iSet>=0 ){
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, r, nPk, regRowid);
+ sqlite3VdbeAddOp3(v, OP_IdxInsert, regRowset, regRowid, 0);
+ if( iSet ) sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
+ }
+
+ /* Release the array of temp registers */
+ sqlite3ReleaseTempRange(pParse, r, nPk);
+ }
+ }
+
+ /* Invoke the main loop body as a subroutine */
+ sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, iLoopBody);
+
+ /* Jump here (skipping the main loop body subroutine) if the
+ ** current sub-WHERE row is a duplicate from prior sub-WHEREs. */
+ if( j1 ) sqlite3VdbeJumpHere(v, j1);
+
+ /* The pSubWInfo->untestedTerms flag means that this OR term
+ ** contained one or more AND term from a notReady table. The
+ ** terms from the notReady table could not be tested and will
+ ** need to be tested later.
+ */
+ if( pSubWInfo->untestedTerms ) untestedTerms = 1;
+
+ /* If all of the OR-connected terms are optimized using the same
+ ** index, and the index is opened using the same cursor number
+ ** by each call to sqlite3WhereBegin() made by this loop, it may
+ ** be possible to use that index as a covering index.
+ **
+ ** If the call to sqlite3WhereBegin() above resulted in a scan that
+ ** uses an index, and this is either the first OR-connected term
+ ** processed or the index is the same as that used by all previous
+ ** terms, set pCov to the candidate covering index. Otherwise, set
+ ** pCov to NULL to indicate that no candidate covering index will
+ ** be available.
+ */
+ pSubLoop = pSubWInfo->a[0].pWLoop;
+ assert( (pSubLoop->wsFlags & WHERE_AUTO_INDEX)==0 );
+ if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0
+ && (ii==0 || pSubLoop->u.btree.pIndex==pCov)
+ && (HasRowid(pTab) || !IsPrimaryKeyIndex(pSubLoop->u.btree.pIndex))
+ ){
+ assert( pSubWInfo->a[0].iIdxCur==iCovCur );
+ pCov = pSubLoop->u.btree.pIndex;
+ wctrlFlags |= WHERE_REOPEN_IDX;
+ }else{
+ pCov = 0;
+ }
+
+ /* Finish the loop through table entries that match term pOrTerm. */
+ sqlite3WhereEnd(pSubWInfo);
+ }
+ }
+ }
+ pLevel->u.pCovidx = pCov;
+ if( pCov ) pLevel->iIdxCur = iCovCur;
+ if( pAndExpr ){
+ pAndExpr->pLeft = 0;
+ sqlite3ExprDelete(db, pAndExpr);
+ }
+ sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v));
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk);
+ sqlite3VdbeResolveLabel(v, iLoopBody);
+
+ if( pWInfo->nLevel>1 ) sqlite3StackFree(db, pOrTab);
+ if( !untestedTerms ) disableTerm(pLevel, pTerm);
+ }else
+#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
+
+ {
+ /* Case 6: There is no usable index. We must do a complete
+ ** scan of the entire table.
+ */
+ static const u8 aStep[] = { OP_Next, OP_Prev };
+ static const u8 aStart[] = { OP_Rewind, OP_Last };
+ assert( bRev==0 || bRev==1 );
+ if( pTabItem->isRecursive ){
+ /* Tables marked isRecursive have only a single row that is stored in
+ ** a pseudo-cursor. No need to Rewind or Next such cursors. */
+ pLevel->op = OP_Noop;
+ }else{
+ pLevel->op = aStep[bRev];
+ pLevel->p1 = iCur;
+ pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);
+ VdbeCoverageIf(v, bRev==0);
+ VdbeCoverageIf(v, bRev!=0);
+ pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
+ }
+ }
+
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ pLevel->addrVisit = sqlite3VdbeCurrentAddr(v);
+#endif
+
+ /* Insert code to test every subexpression that can be completely
+ ** computed using the current set of tables.
+ */
+ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
+ Expr *pE;
+ int skipLikeAddr = 0;
+ testcase( pTerm->wtFlags & TERM_VIRTUAL );
+ testcase( pTerm->wtFlags & TERM_CODED );
+ if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
+ if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
+ testcase( pWInfo->untestedTerms==0
+ && (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 );
+ pWInfo->untestedTerms = 1;
+ continue;
+ }
+ pE = pTerm->pExpr;
+ assert( pE!=0 );
+ if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
+ continue;
+ }
+ if( pTerm->wtFlags & TERM_LIKECOND ){
+ assert( pLevel->iLikeRepCntr>0 );
+ skipLikeAddr = sqlite3VdbeAddOp1(v, OP_IfNot, pLevel->iLikeRepCntr);
+ VdbeCoverage(v);
+ }
+ sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
+ if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
+ pTerm->wtFlags |= TERM_CODED;
+ }
+
+ /* Insert code to test for implied constraints based on transitivity
+ ** of the "==" operator.
+ **
+ ** Example: If the WHERE clause contains "t1.a=t2.b" and "t2.b=123"
+ ** and we are coding the t1 loop and the t2 loop has not yet coded,
+ ** then we cannot use the "t1.a=t2.b" constraint, but we can code
+ ** the implied "t1.a=123" constraint.
+ */
+ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
+ Expr *pE, *pEAlt;
+ WhereTerm *pAlt;
+ if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
+ if( pTerm->eOperator!=(WO_EQUIV|WO_EQ) ) continue;
+ if( pTerm->leftCursor!=iCur ) continue;
+ if( pLevel->iLeftJoin ) continue;
+ pE = pTerm->pExpr;
+ assert( !ExprHasProperty(pE, EP_FromJoin) );
+ assert( (pTerm->prereqRight & pLevel->notReady)!=0 );
+ pAlt = findTerm(pWC, iCur, pTerm->u.leftColumn, notReady, WO_EQ|WO_IN, 0);
+ if( pAlt==0 ) continue;
+ if( pAlt->wtFlags & (TERM_CODED) ) continue;
+ testcase( pAlt->eOperator & WO_EQ );
+ testcase( pAlt->eOperator & WO_IN );
+ VdbeModuleComment((v, "begin transitive constraint"));
+ pEAlt = sqlite3StackAllocRaw(db, sizeof(*pEAlt));
+ if( pEAlt ){
+ *pEAlt = *pAlt->pExpr;
+ pEAlt->pLeft = pE->pLeft;
+ sqlite3ExprIfFalse(pParse, pEAlt, addrCont, SQLITE_JUMPIFNULL);
+ sqlite3StackFree(db, pEAlt);
+ }
+ }
+
+ /* For a LEFT OUTER JOIN, generate code that will record the fact that
+ ** at least one row of the right table has matched the left table.
+ */
+ if( pLevel->iLeftJoin ){
+ pLevel->addrFirst = sqlite3VdbeCurrentAddr(v);
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin);
+ VdbeComment((v, "record LEFT JOIN hit"));
+ sqlite3ExprCacheClear(pParse);
+ for(pTerm=pWC->a, j=0; j<pWC->nTerm; j++, pTerm++){
+ testcase( pTerm->wtFlags & TERM_VIRTUAL );
+ testcase( pTerm->wtFlags & TERM_CODED );
+ if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
+ if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
+ assert( pWInfo->untestedTerms );
+ continue;
+ }
+ assert( pTerm->pExpr );
+ sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
+ pTerm->wtFlags |= TERM_CODED;
+ }
+ }
+
+ return pLevel->notReady;
+}
#ifdef WHERETRACE_ENABLED
/*
@@ -127606,10 +120332,9 @@ static void whereTermPrint(WhereTerm *pTerm, int iTerm){
if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V';
if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E';
if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L';
- sqlite3DebugPrintf(
- "TERM-%-3d %p %s cursor=%-3d prob=%-3d op=0x%03x wtFlags=0x%04x\n",
- iTerm, pTerm, zType, pTerm->leftCursor, pTerm->truthProb,
- pTerm->eOperator, pTerm->wtFlags);
+ sqlite3DebugPrintf("TERM-%-3d %p %s cursor=%-3d prob=%-3d op=0x%03x\n",
+ iTerm, pTerm, zType, pTerm->leftCursor, pTerm->truthProb,
+ pTerm->eOperator);
sqlite3TreeViewExpr(0, pTerm->pExpr, 0);
}
}
@@ -127621,12 +120346,11 @@ static void whereTermPrint(WhereTerm *pTerm, int iTerm){
*/
static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
WhereInfo *pWInfo = pWC->pWInfo;
- int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
+ int nb = 1+(pWInfo->pTabList->nSrc+7)/8;
struct SrcList_item *pItem = pWInfo->pTabList->a + p->iTab;
Table *pTab = pItem->pTab;
- Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
- p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
+ p->iTab, nb, p->maskSelf, nb, p->prereq);
sqlite3DebugPrintf(" %12s",
pItem->zAlias ? pItem->zAlias : pTab->zName);
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
@@ -127711,8 +120435,8 @@ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){
WhereTerm **paNew;
if( p->nLSlot>=n ) return SQLITE_OK;
n = (n+7)&~7;
- paNew = sqlite3DbMallocRawNN(db, sizeof(p->aLTerm[0])*n);
- if( paNew==0 ) return SQLITE_NOMEM_BKPT;
+ paNew = sqlite3DbMallocRaw(db, sizeof(p->aLTerm[0])*n);
+ if( paNew==0 ) return SQLITE_NOMEM;
memcpy(paNew, p->aLTerm, sizeof(p->aLTerm[0])*p->nLSlot);
if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm);
p->aLTerm = paNew;
@@ -127727,7 +120451,7 @@ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
whereLoopClearUnion(db, pTo);
if( whereLoopResize(db, pTo, pFrom->nLTerm) ){
memset(&pTo->u, 0, sizeof(pTo->u));
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
memcpy(pTo, pFrom, WHERE_LOOP_XFER_SZ);
memcpy(pTo->aLTerm, pFrom->aLTerm, pTo->nLTerm*sizeof(pTo->aLTerm[0]));
@@ -127759,7 +120483,7 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
sqlite3DbFree(db, pLevel->u.in.aInLoop);
}
}
- sqlite3WhereClauseClear(&pWInfo->sWC);
+ whereClauseClear(&pWInfo->sWC);
while( pWInfo->pLoops ){
WhereLoop *p = pWInfo->pLoops;
pWInfo->pLoops = p->pNextLoop;
@@ -127951,26 +120675,23 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
WhereLoop **ppPrev, *p;
WhereInfo *pWInfo = pBuilder->pWInfo;
sqlite3 *db = pWInfo->pParse->db;
- int rc;
/* If pBuilder->pOrSet is defined, then only keep track of the costs
** and prereqs.
*/
if( pBuilder->pOrSet!=0 ){
- if( pTemplate->nLTerm ){
#if WHERETRACE_ENABLED
- u16 n = pBuilder->pOrSet->n;
- int x =
+ u16 n = pBuilder->pOrSet->n;
+ int x =
#endif
- whereOrInsert(pBuilder->pOrSet, pTemplate->prereq, pTemplate->rRun,
+ whereOrInsert(pBuilder->pOrSet, pTemplate->prereq, pTemplate->rRun,
pTemplate->nOut);
#if WHERETRACE_ENABLED /* 0x8 */
- if( sqlite3WhereTrace & 0x8 ){
- sqlite3DebugPrintf(x?" or-%d: ":" or-X: ", n);
- whereLoopPrint(pTemplate, pBuilder->pWC);
- }
-#endif
+ if( sqlite3WhereTrace & 0x8 ){
+ sqlite3DebugPrintf(x?" or-%d: ":" or-X: ", n);
+ whereLoopPrint(pTemplate, pBuilder->pWC);
}
+#endif
return SQLITE_OK;
}
@@ -128009,8 +120730,8 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
#endif
if( p==0 ){
/* Allocate a new WhereLoop to add to the end of the list */
- *ppPrev = p = sqlite3DbMallocRawNN(db, sizeof(WhereLoop));
- if( p==0 ) return SQLITE_NOMEM_BKPT;
+ *ppPrev = p = sqlite3DbMallocRaw(db, sizeof(WhereLoop));
+ if( p==0 ) return SQLITE_NOMEM;
whereLoopInit(p);
p->pNextLoop = 0;
}else{
@@ -128034,14 +120755,14 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
whereLoopDelete(db, pToDel);
}
}
- rc = whereLoopXfer(db, p, pTemplate);
+ whereLoopXfer(db, p, pTemplate);
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
Index *pIndex = p->u.btree.pIndex;
if( pIndex && pIndex->tnum==0 ){
p->u.btree.pIndex = 0;
}
}
- return rc;
+ return SQLITE_OK;
}
/*
@@ -128103,9 +120824,8 @@ static void whereLoopOutputAdjust(
/* In the absence of explicit truth probabilities, use heuristics to
** guess a reasonable truth probability. */
pLoop->nOut--;
- if( pTerm->eOperator&(WO_EQ|WO_IS) ){
+ if( pTerm->eOperator&WO_EQ ){
Expr *pRight = pTerm->pExpr->pRight;
- testcase( pTerm->pExpr->op==TK_IS );
if( sqlite3ExprIsInteger(pRight, &k) && k>=(-1) && k<=1 ){
k = 10;
}else{
@@ -128160,33 +120880,37 @@ static int whereLoopAddBtreeIndex(
u16 saved_nSkip; /* Original value of pNew->nSkip */
u32 saved_wsFlags; /* Original value of pNew->wsFlags */
LogEst saved_nOut; /* Original value of pNew->nOut */
+ int iCol; /* Index of the column in the table */
int rc = SQLITE_OK; /* Return code */
LogEst rSize; /* Number of rows in the table */
LogEst rLogSize; /* Logarithm of table size */
WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */
pNew = pBuilder->pNew;
- if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
+ if( db->mallocFailed ) return SQLITE_NOMEM;
assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 );
assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 );
if( pNew->wsFlags & WHERE_BTM_LIMIT ){
opMask = WO_LT|WO_LE;
+ }else if( pProbe->tnum<=0 || (pSrc->jointype & JT_LEFT)!=0 ){
+ opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE;
}else{
- opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS;
+ opMask = WO_EQ|WO_IN|WO_ISNULL|WO_GT|WO_GE|WO_LT|WO_LE;
}
if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
assert( pNew->u.btree.nEq<pProbe->nColumn );
+ iCol = pProbe->aiColumn[pNew->u.btree.nEq];
+ pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol,
+ opMask, pProbe);
saved_nEq = pNew->u.btree.nEq;
saved_nSkip = pNew->nSkip;
saved_nLTerm = pNew->nLTerm;
saved_wsFlags = pNew->wsFlags;
saved_prereq = pNew->prereq;
saved_nOut = pNew->nOut;
- pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, saved_nEq,
- opMask, pProbe);
pNew->rSetup = 0;
rSize = pProbe->aiRowLogEst[0];
rLogSize = estLog(rSize);
@@ -128199,7 +120923,7 @@ static int whereLoopAddBtreeIndex(
int nRecValid = pBuilder->nRecValid;
#endif
if( (eOp==WO_ISNULL || (pTerm->wtFlags&TERM_VNULL)!=0)
- && indexColumnNotNull(pProbe, saved_nEq)
+ && (iCol<0 || pSrc->pTab->aCol[iCol].notNull)
){
continue; /* ignore IS [NOT] NULL constraints on NOT NULL columns */
}
@@ -128209,18 +120933,6 @@ static int whereLoopAddBtreeIndex(
** to mix with a lower range bound from some other source */
if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;
- /* Do not allow IS constraints from the WHERE clause to be used by the
- ** right table of a LEFT JOIN. Only constraints in the ON clause are
- ** allowed */
- if( (pSrc->fg.jointype & JT_LEFT)!=0
- && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
- && (eOp & (WO_IS|WO_ISNULL))!=0
- ){
- testcase( eOp & WO_IS );
- testcase( eOp & WO_ISNULL );
- continue;
- }
-
pNew->wsFlags = saved_wsFlags;
pNew->u.btree.nEq = saved_nEq;
pNew->nLTerm = saved_nLTerm;
@@ -128247,13 +120959,9 @@ static int whereLoopAddBtreeIndex(
assert( nIn>0 ); /* RHS always has 2 or more terms... The parser
** changes "x IN (?)" into "x=?". */
- }else if( eOp & (WO_EQ|WO_IS) ){
- int iCol = pProbe->aiColumn[saved_nEq];
+ }else if( eOp & (WO_EQ) ){
pNew->wsFlags |= WHERE_COLUMN_EQ;
- assert( saved_nEq==pNew->u.btree.nEq );
- if( iCol==XN_ROWID
- || (iCol>0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1)
- ){
+ if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1) ){
if( iCol>=0 && pProbe->uniqNotNull==0 ){
pNew->wsFlags |= WHERE_UNQ_WANTED;
}else{
@@ -128301,10 +121009,10 @@ static int whereLoopAddBtreeIndex(
whereRangeScanEst(pParse, pBuilder, pBtm, pTop, pNew);
}else{
int nEq = ++pNew->u.btree.nEq;
- assert( eOp & (WO_ISNULL|WO_EQ|WO_IN|WO_IS) );
+ assert( eOp & (WO_ISNULL|WO_EQ|WO_IN) );
assert( pNew->nOut==saved_nOut );
- if( pTerm->truthProb<=0 && pProbe->aiColumn[saved_nEq]>=0 ){
+ if( pTerm->truthProb<=0 && iCol>=0 ){
assert( (eOp & WO_IN) || nIn==0 );
testcase( eOp & WO_IN );
pNew->nOut += pTerm->truthProb;
@@ -128318,9 +121026,8 @@ static int whereLoopAddBtreeIndex(
&& ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect))
){
Expr *pExpr = pTerm->pExpr;
- if( (eOp & (WO_EQ|WO_ISNULL|WO_IS))!=0 ){
+ if( (eOp & (WO_EQ|WO_ISNULL))!=0 ){
testcase( eOp & WO_EQ );
- testcase( eOp & WO_IS );
testcase( eOp & WO_ISNULL );
rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut);
}else{
@@ -128439,25 +121146,18 @@ static int indexMightHelpWithOrderBy(
int iCursor
){
ExprList *pOB;
- ExprList *aColExpr;
int ii, jj;
if( pIndex->bUnordered ) return 0;
if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0;
for(ii=0; ii<pOB->nExpr; ii++){
Expr *pExpr = sqlite3ExprSkipCollate(pOB->a[ii].pExpr);
- if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){
+ if( pExpr->op!=TK_COLUMN ) return 0;
+ if( pExpr->iTable==iCursor ){
if( pExpr->iColumn<0 ) return 1;
for(jj=0; jj<pIndex->nKeyCol; jj++){
if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1;
}
- }else if( (aColExpr = pIndex->aColExpr)!=0 ){
- for(jj=0; jj<pIndex->nKeyCol; jj++){
- if( pIndex->aiColumn[jj]!=XN_EXPR ) continue;
- if( sqlite3ExprCompare(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){
- return 1;
- }
- }
}
}
return 0;
@@ -128487,10 +121187,6 @@ static Bitmask columnsInIndex(Index *pIdx){
static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
int i;
WhereTerm *pTerm;
- while( pWhere->op==TK_AND ){
- if( !whereUsablePartialIndex(iTab,pWC,pWhere->pLeft) ) return 0;
- pWhere = pWhere->pRight;
- }
for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
Expr *pExpr = pTerm->pExpr;
if( sqlite3ExprImpliesExpr(pExpr, pWhere, iTab)
@@ -128540,7 +121236,7 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
*/
static int whereLoopAddBtree(
WhereLoopBuilder *pBuilder, /* WHERE clause information */
- Bitmask mPrereq /* Extra prerequesites for using this table */
+ Bitmask mExtra /* Extra prerequesites for using this table */
){
WhereInfo *pWInfo; /* WHERE analysis context */
Index *pProbe; /* An index we are evaluating */
@@ -128566,9 +121262,9 @@ static int whereLoopAddBtree(
pWC = pBuilder->pWC;
assert( !IsVirtual(pSrc->pTab) );
- if( pSrc->pIBIndex ){
+ if( pSrc->pIndex ){
/* An INDEXED BY clause specifies a particular index to use */
- pProbe = pSrc->pIBIndex;
+ pProbe = pSrc->pIndex;
}else if( !HasRowid(pTab) ){
pProbe = pTab->pIndex;
}else{
@@ -128588,7 +121284,7 @@ static int whereLoopAddBtree(
aiRowEstPk[0] = pTab->nRowLogEst;
aiRowEstPk[1] = 0;
pFirst = pSrc->pTab->pIndex;
- if( pSrc->fg.notIndexed==0 ){
+ if( pSrc->notIndexed==0 ){
/* The real indices of the table are only considered if the
** NOT INDEXED qualifier is omitted from the FROM clause */
sPk.pNext = pFirst;
@@ -128600,14 +121296,15 @@ static int whereLoopAddBtree(
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
/* Automatic indexes */
- if( !pBuilder->pOrSet /* Not part of an OR optimization */
+ if( !pBuilder->pOrSet
&& (pWInfo->wctrlFlags & WHERE_NO_AUTOINDEX)==0
&& (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
- && pSrc->pIBIndex==0 /* Has no INDEXED BY clause */
- && !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */
- && HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */
- && !pSrc->fg.isCorrelated /* Not a correlated subquery */
- && !pSrc->fg.isRecursive /* Not a recursive common table expression. */
+ && pSrc->pIndex==0
+ && !pSrc->viaCoroutine
+ && !pSrc->notIndexed
+ && HasRowid(pTab)
+ && !pSrc->isCorrelated
+ && !pSrc->isRecursive
){
/* Generate auto-index WhereLoops */
WhereTerm *pTerm;
@@ -128640,7 +121337,7 @@ static int whereLoopAddBtree(
pNew->nOut = 43; assert( 43==sqlite3LogEst(20) );
pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut);
pNew->wsFlags = WHERE_AUTO_INDEX;
- pNew->prereq = mPrereq | pTerm->prereqRight;
+ pNew->prereq = mExtra | pTerm->prereqRight;
rc = whereLoopInsert(pBuilder, pNew);
}
}
@@ -128661,7 +121358,7 @@ static int whereLoopAddBtree(
pNew->nLTerm = 0;
pNew->iSortIdx = 0;
pNew->rSetup = 0;
- pNew->prereq = mPrereq;
+ pNew->prereq = mExtra;
pNew->nOut = rSize;
pNew->u.btree.pIndex = pProbe;
b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor);
@@ -128728,292 +121425,176 @@ static int whereLoopAddBtree(
/* If there was an INDEXED BY clause, then only that one index is
** considered. */
- if( pSrc->pIBIndex ) break;
+ if( pSrc->pIndex ) break;
}
return rc;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
-
-/*
-** Argument pIdxInfo is already populated with all constraints that may
-** be used by the virtual table identified by pBuilder->pNew->iTab. This
-** function marks a subset of those constraints usable, invokes the
-** xBestIndex method and adds the returned plan to pBuilder.
-**
-** A constraint is marked usable if:
-**
-** * Argument mUsable indicates that its prerequisites are available, and
-**
-** * It is not one of the operators specified in the mExclude mask passed
-** as the fourth argument (which in practice is either WO_IN or 0).
-**
-** Argument mPrereq is a mask of tables that must be scanned before the
-** virtual table in question. These are added to the plans prerequisites
-** before it is added to pBuilder.
-**
-** Output parameter *pbIn is set to true if the plan added to pBuilder
-** uses one or more WO_IN terms, or false otherwise.
-*/
-static int whereLoopAddVirtualOne(
- WhereLoopBuilder *pBuilder,
- Bitmask mPrereq, /* Mask of tables that must be used. */
- Bitmask mUsable, /* Mask of usable tables */
- u16 mExclude, /* Exclude terms using these operators */
- sqlite3_index_info *pIdxInfo, /* Populated object for xBestIndex */
- int *pbIn /* OUT: True if plan uses an IN(...) op */
-){
- WhereClause *pWC = pBuilder->pWC;
- struct sqlite3_index_constraint *pIdxCons;
- struct sqlite3_index_constraint_usage *pUsage = pIdxInfo->aConstraintUsage;
- int i;
- int mxTerm;
- int rc = SQLITE_OK;
- WhereLoop *pNew = pBuilder->pNew;
- Parse *pParse = pBuilder->pWInfo->pParse;
- struct SrcList_item *pSrc = &pBuilder->pWInfo->pTabList->a[pNew->iTab];
- int nConstraint = pIdxInfo->nConstraint;
-
- assert( (mUsable & mPrereq)==mPrereq );
- *pbIn = 0;
- pNew->prereq = mPrereq;
-
- /* Set the usable flag on the subset of constraints identified by
- ** arguments mUsable and mExclude. */
- pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
- for(i=0; i<nConstraint; i++, pIdxCons++){
- WhereTerm *pTerm = &pWC->a[pIdxCons->iTermOffset];
- pIdxCons->usable = 0;
- if( (pTerm->prereqRight & mUsable)==pTerm->prereqRight
- && (pTerm->eOperator & mExclude)==0
- ){
- pIdxCons->usable = 1;
- }
- }
-
- /* Initialize the output fields of the sqlite3_index_info structure */
- memset(pUsage, 0, sizeof(pUsage[0])*nConstraint);
- assert( pIdxInfo->needToFreeIdxStr==0 );
- pIdxInfo->idxStr = 0;
- pIdxInfo->idxNum = 0;
- pIdxInfo->orderByConsumed = 0;
- pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2;
- pIdxInfo->estimatedRows = 25;
- pIdxInfo->idxFlags = 0;
- pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed;
-
- /* Invoke the virtual table xBestIndex() method */
- rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo);
- if( rc ) return rc;
-
- mxTerm = -1;
- assert( pNew->nLSlot>=nConstraint );
- for(i=0; i<nConstraint; i++) pNew->aLTerm[i] = 0;
- pNew->u.vtab.omitMask = 0;
- pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
- for(i=0; i<nConstraint; i++, pIdxCons++){
- int iTerm;
- if( (iTerm = pUsage[i].argvIndex - 1)>=0 ){
- WhereTerm *pTerm;
- int j = pIdxCons->iTermOffset;
- if( iTerm>=nConstraint
- || j<0
- || j>=pWC->nTerm
- || pNew->aLTerm[iTerm]!=0
- || pIdxCons->usable==0
- ){
- rc = SQLITE_ERROR;
- sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName);
- return rc;
- }
- testcase( iTerm==nConstraint-1 );
- testcase( j==0 );
- testcase( j==pWC->nTerm-1 );
- pTerm = &pWC->a[j];
- pNew->prereq |= pTerm->prereqRight;
- assert( iTerm<pNew->nLSlot );
- pNew->aLTerm[iTerm] = pTerm;
- if( iTerm>mxTerm ) mxTerm = iTerm;
- testcase( iTerm==15 );
- testcase( iTerm==16 );
- if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<<iTerm;
- if( (pTerm->eOperator & WO_IN)!=0 ){
- /* A virtual table that is constrained by an IN clause may not
- ** consume the ORDER BY clause because (1) the order of IN terms
- ** is not necessarily related to the order of output terms and
- ** (2) Multiple outputs from a single IN value will not merge
- ** together. */
- pIdxInfo->orderByConsumed = 0;
- pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE;
- *pbIn = 1; assert( (mExclude & WO_IN)==0 );
- }
- }
- }
-
- pNew->nLTerm = mxTerm+1;
- assert( pNew->nLTerm<=pNew->nLSlot );
- pNew->u.vtab.idxNum = pIdxInfo->idxNum;
- pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
- pIdxInfo->needToFreeIdxStr = 0;
- pNew->u.vtab.idxStr = pIdxInfo->idxStr;
- pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ?
- pIdxInfo->nOrderBy : 0);
- pNew->rSetup = 0;
- pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
- pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
-
- /* Set the WHERE_ONEROW flag if the xBestIndex() method indicated
- ** that the scan will visit at most one row. Clear it otherwise. */
- if( pIdxInfo->idxFlags & SQLITE_INDEX_SCAN_UNIQUE ){
- pNew->wsFlags |= WHERE_ONEROW;
- }else{
- pNew->wsFlags &= ~WHERE_ONEROW;
- }
- rc = whereLoopInsert(pBuilder, pNew);
- if( pNew->u.vtab.needFree ){
- sqlite3_free(pNew->u.vtab.idxStr);
- pNew->u.vtab.needFree = 0;
- }
- WHERETRACE(0xffff, (" bIn=%d prereqIn=%04llx prereqOut=%04llx\n",
- *pbIn, (sqlite3_uint64)mPrereq,
- (sqlite3_uint64)(pNew->prereq & ~mPrereq)));
-
- return rc;
-}
-
-
/*
** Add all WhereLoop objects for a table of the join identified by
** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table.
-**
-** If there are no LEFT or CROSS JOIN joins in the query, both mPrereq and
-** mUnusable are set to 0. Otherwise, mPrereq is a mask of all FROM clause
-** entries that occur before the virtual table in the FROM clause and are
-** separated from it by at least one LEFT or CROSS JOIN. Similarly, the
-** mUnusable mask contains all FROM clause entries that occur after the
-** virtual table and are separated from it by at least one LEFT or
-** CROSS JOIN.
-**
-** For example, if the query were:
-**
-** ... FROM t1, t2 LEFT JOIN t3, t4, vt CROSS JOIN t5, t6;
-**
-** then mPrereq corresponds to (t1, t2) and mUnusable to (t5, t6).
-**
-** All the tables in mPrereq must be scanned before the current virtual
-** table. So any terms for which all prerequisites are satisfied by
-** mPrereq may be specified as "usable" in all calls to xBestIndex.
-** Conversely, all tables in mUnusable must be scanned after the current
-** virtual table, so any terms for which the prerequisites overlap with
-** mUnusable should always be configured as "not-usable" for xBestIndex.
*/
static int whereLoopAddVirtual(
WhereLoopBuilder *pBuilder, /* WHERE clause information */
- Bitmask mPrereq, /* Tables that must be scanned before this one */
- Bitmask mUnusable /* Tables that must be scanned after this one */
+ Bitmask mExtra
){
- int rc = SQLITE_OK; /* Return code */
WhereInfo *pWInfo; /* WHERE analysis context */
Parse *pParse; /* The parsing context */
WhereClause *pWC; /* The WHERE clause */
struct SrcList_item *pSrc; /* The FROM clause term to search */
- sqlite3_index_info *p; /* Object to pass to xBestIndex() */
- int nConstraint; /* Number of constraints in p */
- int bIn; /* True if plan uses IN(...) operator */
+ Table *pTab;
+ sqlite3 *db;
+ sqlite3_index_info *pIdxInfo;
+ struct sqlite3_index_constraint *pIdxCons;
+ struct sqlite3_index_constraint_usage *pUsage;
+ WhereTerm *pTerm;
+ int i, j;
+ int iTerm, mxTerm;
+ int nConstraint;
+ int seenIn = 0; /* True if an IN operator is seen */
+ int seenVar = 0; /* True if a non-constant constraint is seen */
+ int iPhase; /* 0: const w/o IN, 1: const, 2: no IN, 2: IN */
WhereLoop *pNew;
- Bitmask mBest; /* Tables used by best possible plan */
+ int rc = SQLITE_OK;
- assert( (mPrereq & mUnusable)==0 );
pWInfo = pBuilder->pWInfo;
pParse = pWInfo->pParse;
+ db = pParse->db;
pWC = pBuilder->pWC;
pNew = pBuilder->pNew;
pSrc = &pWInfo->pTabList->a[pNew->iTab];
- assert( IsVirtual(pSrc->pTab) );
- p = allocateIndexInfo(pParse, pWC, mUnusable, pSrc, pBuilder->pOrderBy);
- if( p==0 ) return SQLITE_NOMEM_BKPT;
+ pTab = pSrc->pTab;
+ assert( IsVirtual(pTab) );
+ pIdxInfo = allocateIndexInfo(pParse, pWC, pSrc, pBuilder->pOrderBy);
+ if( pIdxInfo==0 ) return SQLITE_NOMEM;
+ pNew->prereq = 0;
pNew->rSetup = 0;
pNew->wsFlags = WHERE_VIRTUALTABLE;
pNew->nLTerm = 0;
pNew->u.vtab.needFree = 0;
- nConstraint = p->nConstraint;
- if( whereLoopResize(pParse->db, pNew, nConstraint) ){
- sqlite3DbFree(pParse->db, p);
- return SQLITE_NOMEM_BKPT;
- }
-
- /* First call xBestIndex() with all constraints usable. */
- WHERETRACE(0x40, (" VirtualOne: all usable\n"));
- rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, &bIn);
-
- /* If the call to xBestIndex() with all terms enabled produced a plan
- ** that does not require any source tables (IOW: a plan with mBest==0),
- ** then there is no point in making any further calls to xBestIndex()
- ** since they will all return the same result (if the xBestIndex()
- ** implementation is sane). */
- if( rc==SQLITE_OK && (mBest = (pNew->prereq & ~mPrereq))!=0 ){
- int seenZero = 0; /* True if a plan with no prereqs seen */
- int seenZeroNoIN = 0; /* Plan with no prereqs and no IN(...) seen */
- Bitmask mPrev = 0;
- Bitmask mBestNoIn = 0;
-
- /* If the plan produced by the earlier call uses an IN(...) term, call
- ** xBestIndex again, this time with IN(...) terms disabled. */
- if( bIn ){
- WHERETRACE(0x40, (" VirtualOne: all usable w/o IN\n"));
- rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, WO_IN, p, &bIn);
- assert( bIn==0 );
- mBestNoIn = pNew->prereq & ~mPrereq;
- if( mBestNoIn==0 ){
- seenZero = 1;
- seenZeroNoIN = 1;
- }
- }
-
- /* Call xBestIndex once for each distinct value of (prereqRight & ~mPrereq)
- ** in the set of terms that apply to the current virtual table. */
- while( rc==SQLITE_OK ){
- int i;
- Bitmask mNext = ALLBITS;
- assert( mNext>0 );
- for(i=0; i<nConstraint; i++){
- Bitmask mThis = (
- pWC->a[p->aConstraint[i].iTermOffset].prereqRight & ~mPrereq
- );
- if( mThis>mPrev && mThis<mNext ) mNext = mThis;
- }
- mPrev = mNext;
- if( mNext==ALLBITS ) break;
- if( mNext==mBest || mNext==mBestNoIn ) continue;
- WHERETRACE(0x40, (" VirtualOne: mPrev=%04llx mNext=%04llx\n",
- (sqlite3_uint64)mPrev, (sqlite3_uint64)mNext));
- rc = whereLoopAddVirtualOne(pBuilder, mPrereq, mNext|mPrereq, 0, p, &bIn);
- if( pNew->prereq==mPrereq ){
- seenZero = 1;
- if( bIn==0 ) seenZeroNoIN = 1;
- }
- }
+ pUsage = pIdxInfo->aConstraintUsage;
+ nConstraint = pIdxInfo->nConstraint;
+ if( whereLoopResize(db, pNew, nConstraint) ){
+ sqlite3DbFree(db, pIdxInfo);
+ return SQLITE_NOMEM;
+ }
- /* If the calls to xBestIndex() in the above loop did not find a plan
- ** that requires no source tables at all (i.e. one guaranteed to be
- ** usable), make a call here with all source tables disabled */
- if( rc==SQLITE_OK && seenZero==0 ){
- WHERETRACE(0x40, (" VirtualOne: all disabled\n"));
- rc = whereLoopAddVirtualOne(pBuilder, mPrereq, mPrereq, 0, p, &bIn);
- if( bIn==0 ) seenZeroNoIN = 1;
+ for(iPhase=0; iPhase<=3; iPhase++){
+ if( !seenIn && (iPhase&1)!=0 ){
+ iPhase++;
+ if( iPhase>3 ) break;
}
-
- /* If the calls to xBestIndex() have so far failed to find a plan
- ** that requires no source tables at all and does not use an IN(...)
- ** operator, make a final call to obtain one here. */
- if( rc==SQLITE_OK && seenZeroNoIN==0 ){
- WHERETRACE(0x40, (" VirtualOne: all disabled and w/o IN\n"));
- rc = whereLoopAddVirtualOne(pBuilder, mPrereq, mPrereq, WO_IN, p, &bIn);
+ if( !seenVar && iPhase>1 ) break;
+ pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
+ j = pIdxCons->iTermOffset;
+ pTerm = &pWC->a[j];
+ switch( iPhase ){
+ case 0: /* Constants without IN operator */
+ pIdxCons->usable = 0;
+ if( (pTerm->eOperator & WO_IN)!=0 ){
+ seenIn = 1;
+ }
+ if( pTerm->prereqRight!=0 ){
+ seenVar = 1;
+ }else if( (pTerm->eOperator & WO_IN)==0 ){
+ pIdxCons->usable = 1;
+ }
+ break;
+ case 1: /* Constants with IN operators */
+ assert( seenIn );
+ pIdxCons->usable = (pTerm->prereqRight==0);
+ break;
+ case 2: /* Variables without IN */
+ assert( seenVar );
+ pIdxCons->usable = (pTerm->eOperator & WO_IN)==0;
+ break;
+ default: /* Variables with IN */
+ assert( seenVar && seenIn );
+ pIdxCons->usable = 1;
+ break;
+ }
}
- }
+ memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint);
+ if( pIdxInfo->needToFreeIdxStr ) sqlite3_free(pIdxInfo->idxStr);
+ pIdxInfo->idxStr = 0;
+ pIdxInfo->idxNum = 0;
+ pIdxInfo->needToFreeIdxStr = 0;
+ pIdxInfo->orderByConsumed = 0;
+ pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2;
+ pIdxInfo->estimatedRows = 25;
+ rc = vtabBestIndex(pParse, pTab, pIdxInfo);
+ if( rc ) goto whereLoopAddVtab_exit;
+ pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
+ pNew->prereq = mExtra;
+ mxTerm = -1;
+ assert( pNew->nLSlot>=nConstraint );
+ for(i=0; i<nConstraint; i++) pNew->aLTerm[i] = 0;
+ pNew->u.vtab.omitMask = 0;
+ for(i=0; i<nConstraint; i++, pIdxCons++){
+ if( (iTerm = pUsage[i].argvIndex - 1)>=0 ){
+ j = pIdxCons->iTermOffset;
+ if( iTerm>=nConstraint
+ || j<0
+ || j>=pWC->nTerm
+ || pNew->aLTerm[iTerm]!=0
+ ){
+ rc = SQLITE_ERROR;
+ sqlite3ErrorMsg(pParse, "%s.xBestIndex() malfunction", pTab->zName);
+ goto whereLoopAddVtab_exit;
+ }
+ testcase( iTerm==nConstraint-1 );
+ testcase( j==0 );
+ testcase( j==pWC->nTerm-1 );
+ pTerm = &pWC->a[j];
+ pNew->prereq |= pTerm->prereqRight;
+ assert( iTerm<pNew->nLSlot );
+ pNew->aLTerm[iTerm] = pTerm;
+ if( iTerm>mxTerm ) mxTerm = iTerm;
+ testcase( iTerm==15 );
+ testcase( iTerm==16 );
+ if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<<iTerm;
+ if( (pTerm->eOperator & WO_IN)!=0 ){
+ if( pUsage[i].omit==0 ){
+ /* Do not attempt to use an IN constraint if the virtual table
+ ** says that the equivalent EQ constraint cannot be safely omitted.
+ ** If we do attempt to use such a constraint, some rows might be
+ ** repeated in the output. */
+ break;
+ }
+ /* A virtual table that is constrained by an IN clause may not
+ ** consume the ORDER BY clause because (1) the order of IN terms
+ ** is not necessarily related to the order of output terms and
+ ** (2) Multiple outputs from a single IN value will not merge
+ ** together. */
+ pIdxInfo->orderByConsumed = 0;
+ }
+ }
+ }
+ if( i>=nConstraint ){
+ pNew->nLTerm = mxTerm+1;
+ assert( pNew->nLTerm<=pNew->nLSlot );
+ pNew->u.vtab.idxNum = pIdxInfo->idxNum;
+ pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
+ pIdxInfo->needToFreeIdxStr = 0;
+ pNew->u.vtab.idxStr = pIdxInfo->idxStr;
+ pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ?
+ pIdxInfo->nOrderBy : 0);
+ pNew->rSetup = 0;
+ pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
+ pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
+ whereLoopInsert(pBuilder, pNew);
+ if( pNew->u.vtab.needFree ){
+ sqlite3_free(pNew->u.vtab.idxStr);
+ pNew->u.vtab.needFree = 0;
+ }
+ }
+ }
- if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr);
- sqlite3DbFree(pParse->db, p);
+whereLoopAddVtab_exit:
+ if( pIdxInfo->needToFreeIdxStr ) sqlite3_free(pIdxInfo->idxStr);
+ sqlite3DbFree(db, pIdxInfo);
return rc;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -129022,11 +121603,7 @@ static int whereLoopAddVirtual(
** Add WhereLoop entries to handle OR terms. This works for either
** btrees or virtual tables.
*/
-static int whereLoopAddOr(
- WhereLoopBuilder *pBuilder,
- Bitmask mPrereq,
- Bitmask mUnusable
-){
+static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
WhereInfo *pWInfo = pBuilder->pWInfo;
WhereClause *pWC;
WhereLoop *pNew;
@@ -129085,14 +121662,14 @@ static int whereLoopAddOr(
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pItem->pTab) ){
- rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable);
+ rc = whereLoopAddVirtual(&sSubBuild, mExtra);
}else
#endif
{
- rc = whereLoopAddBtree(&sSubBuild, mPrereq);
+ rc = whereLoopAddBtree(&sSubBuild, mExtra);
}
if( rc==SQLITE_OK ){
- rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable);
+ rc = whereLoopAddOr(&sSubBuild, mExtra);
}
assert( rc==SQLITE_OK || sCur.n==0 );
if( sCur.n==0 ){
@@ -129149,48 +121726,38 @@ static int whereLoopAddOr(
*/
static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
WhereInfo *pWInfo = pBuilder->pWInfo;
- Bitmask mPrereq = 0;
+ Bitmask mExtra = 0;
Bitmask mPrior = 0;
int iTab;
SrcList *pTabList = pWInfo->pTabList;
struct SrcList_item *pItem;
- struct SrcList_item *pEnd = &pTabList->a[pWInfo->nLevel];
sqlite3 *db = pWInfo->pParse->db;
+ int nTabList = pWInfo->nLevel;
int rc = SQLITE_OK;
+ u8 priorJoinType = 0;
WhereLoop *pNew;
- u8 priorJointype = 0;
/* Loop over the tables in the join, from left to right */
pNew = pBuilder->pNew;
whereLoopInit(pNew);
- for(iTab=0, pItem=pTabList->a; pItem<pEnd; iTab++, pItem++){
- Bitmask mUnusable = 0;
+ for(iTab=0, pItem=pTabList->a; iTab<nTabList; iTab++, pItem++){
pNew->iTab = iTab;
- pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor);
- if( ((pItem->fg.jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){
- /* This condition is true when pItem is the FROM clause term on the
- ** right-hand-side of a LEFT or CROSS JOIN. */
- mPrereq = mPrior;
+ pNew->maskSelf = getMask(&pWInfo->sMaskSet, pItem->iCursor);
+ if( ((pItem->jointype|priorJoinType) & (JT_LEFT|JT_CROSS))!=0 ){
+ mExtra = mPrior;
}
- priorJointype = pItem->fg.jointype;
+ priorJoinType = pItem->jointype;
if( IsVirtual(pItem->pTab) ){
- struct SrcList_item *p;
- for(p=&pItem[1]; p<pEnd; p++){
- if( mUnusable || (p->fg.jointype & (JT_LEFT|JT_CROSS)) ){
- mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor);
- }
- }
- rc = whereLoopAddVirtual(pBuilder, mPrereq, mUnusable);
+ rc = whereLoopAddVirtual(pBuilder, mExtra);
}else{
- rc = whereLoopAddBtree(pBuilder, mPrereq);
+ rc = whereLoopAddBtree(pBuilder, mExtra);
}
if( rc==SQLITE_OK ){
- rc = whereLoopAddOr(pBuilder, mPrereq, mUnusable);
+ rc = whereLoopAddOr(pBuilder, mExtra);
}
mPrior |= pNew->maskSelf;
if( rc || db->mallocFailed ) break;
}
-
whereLoopClear(db, pNew);
return rc;
}
@@ -129296,10 +121863,10 @@ static i8 wherePathSatisfiesOrderBy(
pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[i].pExpr);
if( pOBExpr->op!=TK_COLUMN ) continue;
if( pOBExpr->iTable!=iCur ) continue;
- pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn,
- ~ready, WO_EQ|WO_ISNULL|WO_IS, 0);
+ pTerm = findTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn,
+ ~ready, WO_EQ|WO_ISNULL, 0);
if( pTerm==0 ) continue;
- if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){
+ if( (pTerm->eOperator&WO_EQ)!=0 && pOBExpr->iColumn>=0 ){
const char *z1, *z2;
pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
if( !pColl ) pColl = db->pDfltColl;
@@ -129308,7 +121875,6 @@ static i8 wherePathSatisfiesOrderBy(
if( !pColl ) pColl = db->pDfltColl;
z2 = pColl->zName;
if( sqlite3StrICmp(z1, z2)!=0 ) continue;
- testcase( pTerm->pExpr->op==TK_IS );
}
obSat |= MASKBIT(i);
}
@@ -129324,8 +121890,7 @@ static i8 wherePathSatisfiesOrderBy(
nKeyCol = pIndex->nKeyCol;
nColumn = pIndex->nColumn;
assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) );
- assert( pIndex->aiColumn[nColumn-1]==XN_ROWID
- || !HasRowid(pIndex->pTable));
+ assert( pIndex->aiColumn[nColumn-1]==(-1) || !HasRowid(pIndex->pTable));
isOrderDistinct = IsUniqueIndex(pIndex);
}
@@ -129340,7 +121905,7 @@ static i8 wherePathSatisfiesOrderBy(
/* Skip over == and IS NULL terms */
if( j<pLoop->u.btree.nEq
&& pLoop->nSkip==0
- && ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL|WO_IS))!=0
+ && ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL))!=0
){
if( i & WO_ISNULL ){
testcase( isOrderDistinct );
@@ -129357,7 +121922,7 @@ static i8 wherePathSatisfiesOrderBy(
revIdx = pIndex->aSortOrder[j];
if( iColumn==pIndex->pTable->iPKey ) iColumn = -1;
}else{
- iColumn = XN_ROWID;
+ iColumn = -1;
revIdx = 0;
}
@@ -129383,15 +121948,9 @@ static i8 wherePathSatisfiesOrderBy(
testcase( wctrlFlags & WHERE_GROUPBY );
testcase( wctrlFlags & WHERE_DISTINCTBY );
if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0;
- if( iColumn>=(-1) ){
- if( pOBExpr->op!=TK_COLUMN ) continue;
- if( pOBExpr->iTable!=iCur ) continue;
- if( pOBExpr->iColumn!=iColumn ) continue;
- }else{
- if( sqlite3ExprCompare(pOBExpr,pIndex->aColExpr->a[j].pExpr,iCur) ){
- continue;
- }
- }
+ if( pOBExpr->op!=TK_COLUMN ) continue;
+ if( pOBExpr->iTable!=iCur ) continue;
+ if( pOBExpr->iColumn!=iColumn ) continue;
if( iColumn>=0 ){
pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
if( !pColl ) pColl = db->pDfltColl;
@@ -129440,7 +121999,7 @@ static i8 wherePathSatisfiesOrderBy(
Bitmask mTerm;
if( MASKBIT(i) & obSat ) continue;
p = pOrderBy->a[i].pExpr;
- mTerm = sqlite3WhereExprUsage(&pWInfo->sMaskSet,p);
+ mTerm = exprTableUsage(&pWInfo->sMaskSet,p);
if( mTerm==0 && !sqlite3ExprIsConstant(p) ) continue;
if( (mTerm&~orderDistinctMask)==0 ){
obSat |= MASKBIT(i);
@@ -129528,14 +122087,15 @@ static LogEst whereSortingCost(
LogEst rScale, rSortCost;
assert( nOrderBy>0 && 66==sqlite3LogEst(100) );
rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66;
- rSortCost = nRow + rScale + 16;
+ rSortCost = nRow + estLog(nRow) + rScale + 16;
- /* Multiple by log(M) where M is the number of output rows.
- ** Use the LIMIT for M if it is smaller */
- if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 && pWInfo->iLimit<nRow ){
- nRow = pWInfo->iLimit;
+ /* TUNING: The cost of implementing DISTINCT using a B-TREE is
+ ** similar but with a larger constant of proportionality.
+ ** Multiply by an additional factor of 3.0. */
+ if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
+ rSortCost += 16;
}
- rSortCost += estLog(nRow);
+
return rSortCost;
}
@@ -129597,8 +122157,8 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
/* Allocate and initialize space for aTo, aFrom and aSortCost[] */
nSpace = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2;
nSpace += sizeof(LogEst) * nOrderBy;
- pSpace = sqlite3DbMallocRawNN(db, nSpace);
- if( pSpace==0 ) return SQLITE_NOMEM_BKPT;
+ pSpace = sqlite3DbMallocRaw(db, nSpace);
+ if( pSpace==0 ) return SQLITE_NOMEM;
aTo = (WherePath*)pSpace;
aFrom = aTo+mxChoice;
memset(aFrom, 0, sizeof(aFrom[0]));
@@ -129653,12 +122213,6 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
- if( (pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 && pFrom->nRow<10 ){
- /* Do not use an automatic index if the this loop is expected
- ** to run less than 2 times. */
- assert( 10==sqlite3LogEst(2) );
- continue;
- }
/* At this point, pWLoop is a candidate to be the next loop.
** Compute its cost */
rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
@@ -129851,9 +122405,9 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
&& nRowEst
){
Bitmask notUsed;
- int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pDistinctSet, pFrom,
+ int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom,
WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], &notUsed);
- if( rc==pWInfo->pDistinctSet->nExpr ){
+ if( rc==pWInfo->pResultSet->nExpr ){
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
}
}
@@ -129911,22 +122465,21 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
int j;
Table *pTab;
Index *pIdx;
-
+
pWInfo = pBuilder->pWInfo;
if( pWInfo->wctrlFlags & WHERE_FORCE_TABLE ) return 0;
assert( pWInfo->pTabList->nSrc>=1 );
pItem = pWInfo->pTabList->a;
pTab = pItem->pTab;
if( IsVirtual(pTab) ) return 0;
- if( pItem->fg.isIndexedBy ) return 0;
+ if( pItem->zIndex ) return 0;
iCur = pItem->iCursor;
pWC = &pWInfo->sWC;
pLoop = pBuilder->pNew;
pLoop->wsFlags = 0;
pLoop->nSkip = 0;
- pTerm = sqlite3WhereFindTerm(pWC, iCur, -1, 0, WO_EQ|WO_IS, 0);
+ pTerm = findTerm(pWC, iCur, -1, 0, WO_EQ, 0);
if( pTerm ){
- testcase( pTerm->eOperator & WO_IS );
pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW;
pLoop->aLTerm[0] = pTerm;
pLoop->nLTerm = 1;
@@ -129935,17 +122488,14 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
pLoop->rRun = 33; /* 33==sqlite3LogEst(10) */
}else{
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- int opMask;
assert( pLoop->aLTermSpace==pLoop->aLTerm );
if( !IsUniqueIndex(pIdx)
|| pIdx->pPartIdxWhere!=0
|| pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace)
) continue;
- opMask = pIdx->uniqNotNull ? (WO_EQ|WO_IS) : WO_EQ;
for(j=0; j<pIdx->nKeyCol; j++){
- pTerm = sqlite3WhereFindTerm(pWC, iCur, j, 0, opMask, pIdx);
+ pTerm = findTerm(pWC, iCur, pIdx->aiColumn[j], 0, WO_EQ, pIdx);
if( pTerm==0 ) break;
- testcase( pTerm->eOperator & WO_IS );
pLoop->aLTerm[j] = pTerm;
}
if( j!=pIdx->nKeyCol ) continue;
@@ -129964,7 +122514,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
if( pLoop->wsFlags ){
pLoop->nOut = (LogEst)1;
pWInfo->a[0].pWLoop = pLoop;
- pLoop->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
+ pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur);
pWInfo->a[0].iTabCur = iCur;
pWInfo->nRowOut = 1;
if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr;
@@ -130068,14 +122618,13 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
** used.
*/
SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
- Parse *pParse, /* The parser context */
- SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */
- Expr *pWhere, /* The WHERE clause */
- ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */
- ExprList *pDistinctSet, /* Try not to output two rows that duplicate these */
- u16 wctrlFlags, /* The WHERE_* flags defined in sqliteInt.h */
- int iAuxArg /* If WHERE_ONETABLE_ONLY is set, index cursor number
- ** If WHERE_USE_LIMIT, then the limit amount */
+ Parse *pParse, /* The parser context */
+ SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */
+ Expr *pWhere, /* The WHERE clause */
+ ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */
+ ExprList *pResultSet, /* Result set of the query */
+ u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
+ int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */
){
int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */
int nTabList; /* Number of elements in pTabList */
@@ -130089,16 +122638,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
int ii; /* Loop counter */
sqlite3 *db; /* Database connection */
int rc; /* Return code */
- u8 bFordelete = 0; /* OPFLAG_FORDELETE or zero, as appropriate */
- assert( (wctrlFlags & WHERE_ONEPASS_MULTIROW)==0 || (
- (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0
- && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0
- ));
-
- /* Only one of WHERE_ONETABLE_ONLY or WHERE_USE_LIMIT */
- assert( (wctrlFlags & WHERE_ONETABLE_ONLY)==0
- || (wctrlFlags & WHERE_USE_LIMIT)==0 );
/* Variable initialization */
db = pParse->db;
@@ -130150,12 +122690,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList;
pWInfo->pOrderBy = pOrderBy;
- pWInfo->pDistinctSet = pDistinctSet;
+ pWInfo->pResultSet = pResultSet;
pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(v);
pWInfo->wctrlFlags = wctrlFlags;
- pWInfo->iLimit = iAuxArg;
pWInfo->savedNQueryLoop = pParse->nQueryLoop;
- assert( pWInfo->eOnePass==ONEPASS_OFF ); /* ONEPASS defaults to OFF */
pMaskSet = &pWInfo->sMaskSet;
sWLB.pWInfo = pWInfo;
sWLB.pWC = &pWInfo->sWC;
@@ -130170,8 +122708,8 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
** subexpression is separated by an AND operator.
*/
initMaskSet(pMaskSet);
- sqlite3WhereClauseInit(&pWInfo->sWC, pWInfo);
- sqlite3WhereSplit(&pWInfo->sWC, pWhere, TK_AND);
+ whereClauseInit(&pWInfo->sWC, pWInfo);
+ whereSplit(&pWInfo->sWC, pWhere, TK_AND);
/* Special case: a WHERE clause that is constant. Evaluate the
** expression and either jump over all of the code or fall thru.
@@ -130195,12 +122733,14 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
/* Assign a bit from the bitmask to every term in the FROM clause.
**
- ** The N-th term of the FROM clause is assigned a bitmask of 1<<N.
- **
- ** The rule of the previous sentence ensures thta if X is the bitmask for
- ** a table T, then X-1 is the bitmask for all other tables to the left of T.
- ** Knowing the bitmask for all tables to the left of a left join is
- ** important. Ticket #3015.
+ ** When assigning bitmask values to FROM clause cursors, it must be
+ ** the case that if X is the bitmask for the N-th FROM clause term then
+ ** the bitmask for all FROM clause terms to the left of the N-th term
+ ** is (X-1). An expression from the ON clause of a LEFT JOIN can use
+ ** its Expr.iRightJoinTable value to find the bitmask of the right table
+ ** of the join. Subtracting one from the right table bitmask gives a
+ ** bitmask for all tables to the left of the join. Knowing the bitmask
+ ** for all tables to the left of a left join is important. Ticket #3015.
**
** Note that bitmasks are created for all pTabList->nSrc tables in
** pTabList, not just the first nTabList tables. nTabList is normally
@@ -130209,40 +122749,44 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
*/
for(ii=0; ii<pTabList->nSrc; ii++){
createMask(pMaskSet, pTabList->a[ii].iCursor);
- sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC);
}
-#ifdef SQLITE_DEBUG
- for(ii=0; ii<pTabList->nSrc; ii++){
- Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor);
- assert( m==MASKBIT(ii) );
+#ifndef NDEBUG
+ {
+ Bitmask toTheLeft = 0;
+ for(ii=0; ii<pTabList->nSrc; ii++){
+ Bitmask m = getMask(pMaskSet, pTabList->a[ii].iCursor);
+ assert( (m-1)==toTheLeft );
+ toTheLeft |= m;
+ }
}
#endif
- /* Analyze all of the subexpressions. */
- sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
- if( db->mallocFailed ) goto whereBeginError;
+ /* Analyze all of the subexpressions. Note that exprAnalyze() might
+ ** add new virtual terms onto the end of the WHERE clause. We do not
+ ** want to analyze these virtual terms, so start analyzing at the end
+ ** and work forward so that the added virtual terms are never processed.
+ */
+ exprAnalyzeAll(pTabList, &pWInfo->sWC);
+ if( db->mallocFailed ){
+ goto whereBeginError;
+ }
if( wctrlFlags & WHERE_WANT_DISTINCT ){
- if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pDistinctSet) ){
+ if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){
/* The DISTINCT marking is pointless. Ignore it. */
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}else if( pOrderBy==0 ){
/* Try to ORDER BY the result set to make distinct processing easier */
pWInfo->wctrlFlags |= WHERE_DISTINCTBY;
- pWInfo->pOrderBy = pDistinctSet;
+ pWInfo->pOrderBy = pResultSet;
}
}
/* Construct the WhereLoop objects */
+ WHERETRACE(0xffff,("*** Optimizer Start ***\n"));
#if defined(WHERETRACE_ENABLED)
- if( sqlite3WhereTrace & 0xffff ){
- sqlite3DebugPrintf("*** Optimizer Start *** (wctrlFlags: 0x%x",wctrlFlags);
- if( wctrlFlags & WHERE_USE_LIMIT ){
- sqlite3DebugPrintf(", limit: %d", iAuxArg);
- }
- sqlite3DebugPrintf(")\n");
- }
- if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
+ /* Display all terms of the WHERE clause */
+ if( sqlite3WhereTrace & 0x100 ){
int i;
for(i=0; i<sWLB.pWC->nTerm; i++){
whereTermPrint(&sWLB.pWC->a[i], i);
@@ -130254,12 +122798,13 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
rc = whereLoopAddAll(&sWLB);
if( rc ) goto whereBeginError;
-#ifdef WHERETRACE_ENABLED
- if( sqlite3WhereTrace ){ /* Display all of the WhereLoop objects */
+ /* Display all of the WhereLoop objects if wheretrace is enabled */
+#ifdef WHERETRACE_ENABLED /* !=0 */
+ if( sqlite3WhereTrace ){
WhereLoop *p;
int i;
- static const char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz"
- "ABCDEFGHIJKLMNOPQRSTUVWYXZ";
+ static char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz"
+ "ABCDEFGHIJKLMNOPQRSTUVWYXZ";
for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){
p->cId = zLabel[i%sizeof(zLabel)];
whereLoopPrint(p, sWLB.pWC);
@@ -130275,12 +122820,12 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
}
}
if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){
- pWInfo->revMask = ALLBITS;
+ pWInfo->revMask = (Bitmask)(-1);
}
if( pParse->nErr || NEVER(db->mallocFailed) ){
goto whereBeginError;
}
-#ifdef WHERETRACE_ENABLED
+#ifdef WHERETRACE_ENABLED /* !=0 */
if( sqlite3WhereTrace ){
sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut);
if( pWInfo->nOBSat>0 ){
@@ -130308,17 +122853,15 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
#endif
/* Attempt to omit tables from the join that do not effect the result */
if( pWInfo->nLevel>=2
- && pDistinctSet!=0
+ && pResultSet!=0
&& OptimizationEnabled(db, SQLITE_OmitNoopJoin)
){
- Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pDistinctSet);
- if( sWLB.pOrderBy ){
- tabUsed |= sqlite3WhereExprListUsage(pMaskSet, sWLB.pOrderBy);
- }
+ Bitmask tabUsed = exprListTableUsage(pMaskSet, pResultSet);
+ if( sWLB.pOrderBy ) tabUsed |= exprListTableUsage(pMaskSet, sWLB.pOrderBy);
while( pWInfo->nLevel>=2 ){
WhereTerm *pTerm, *pEnd;
pLoop = pWInfo->a[pWInfo->nLevel-1].pWLoop;
- if( (pWInfo->pTabList->a[pLoop->iTab].fg.jointype & JT_LEFT)==0 ) break;
+ if( (pWInfo->pTabList->a[pLoop->iTab].jointype & JT_LEFT)==0 ) break;
if( (wctrlFlags & WHERE_WANT_DISTINCT)==0
&& (pLoop->wsFlags & WHERE_ONEROW)==0
){
@@ -130344,28 +122887,22 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
/* If the caller is an UPDATE or DELETE statement that is requesting
** to use a one-pass algorithm, determine if this is appropriate.
+ ** The one-pass algorithm only works if the WHERE clause constrains
+ ** the statement to update a single row.
*/
assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 );
- if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){
- int wsFlags = pWInfo->a[0].pWLoop->wsFlags;
- int bOnerow = (wsFlags & WHERE_ONEROW)!=0;
- if( bOnerow
- || ((wctrlFlags & WHERE_ONEPASS_MULTIROW)!=0
- && 0==(wsFlags & WHERE_VIRTUALTABLE))
- ){
- pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI;
- if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){
- if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){
- bFordelete = OPFLAG_FORDELETE;
- }
- pWInfo->a[0].pWLoop->wsFlags = (wsFlags & ~WHERE_IDX_ONLY);
- }
+ if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0
+ && (pWInfo->a[0].pWLoop->wsFlags & WHERE_ONEROW)!=0 ){
+ pWInfo->okOnePass = 1;
+ if( HasRowid(pTabList->a[0].pTab) ){
+ pWInfo->a[0].pWLoop->wsFlags &= ~WHERE_IDX_ONLY;
}
}
/* Open all tables in the pTabList and any indices selected for
** searching those tables.
*/
+ notReady = ~(Bitmask)0;
for(ii=0, pLevel=pWInfo->a; ii<nTabList; ii++, pLevel++){
Table *pTab; /* Table to open */
int iDb; /* Index of database containing table/index */
@@ -130390,33 +122927,22 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
&& (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){
int op = OP_OpenRead;
- if( pWInfo->eOnePass!=ONEPASS_OFF ){
+ if( pWInfo->okOnePass ){
op = OP_OpenWrite;
pWInfo->aiCurOnePass[0] = pTabItem->iCursor;
};
sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op);
assert( pTabItem->iCursor==pLevel->iTabCur );
- testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS-1 );
- testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS );
- if( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol<BMS && HasRowid(pTab) ){
+ testcase( !pWInfo->okOnePass && pTab->nCol==BMS-1 );
+ testcase( !pWInfo->okOnePass && pTab->nCol==BMS );
+ if( !pWInfo->okOnePass && pTab->nCol<BMS && HasRowid(pTab) ){
Bitmask b = pTabItem->colUsed;
int n = 0;
for(; b; b=b>>1, n++){}
- sqlite3VdbeChangeP4(v, -1, SQLITE_INT_TO_PTR(n), P4_INT32);
+ sqlite3VdbeChangeP4(v, sqlite3VdbeCurrentAddr(v)-1,
+ SQLITE_INT_TO_PTR(n), P4_INT32);
assert( n<=pTab->nCol );
}
-#ifdef SQLITE_ENABLE_CURSOR_HINTS
- if( pLoop->u.btree.pIndex!=0 ){
- sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ|bFordelete);
- }else
-#endif
- {
- sqlite3VdbeChangeP5(v, bFordelete);
- }
-#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
- sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, pTabItem->iCursor, 0, 0,
- (const u8*)&pTabItem->colUsed, P4_INT64);
-#endif
}else{
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
}
@@ -130424,8 +122950,8 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
Index *pIx = pLoop->u.btree.pIndex;
int iIndexCur;
int op = OP_OpenRead;
- /* iAuxArg is always set if to a positive value if ONEPASS is possible */
- assert( iAuxArg!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 );
+ /* iIdxCur is always set if to a positive value if ONEPASS is possible */
+ assert( iIdxCur!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 );
if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIx)
&& (wctrlFlags & WHERE_ONETABLE_ONLY)!=0
){
@@ -130433,9 +122959,9 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
** WITHOUT ROWID table. No need for a separate index */
iIndexCur = pLevel->iTabCur;
op = 0;
- }else if( pWInfo->eOnePass!=ONEPASS_OFF ){
+ }else if( pWInfo->okOnePass ){
Index *pJ = pTabItem->pTab->pIndex;
- iIndexCur = iAuxArg;
+ iIndexCur = iIdxCur;
assert( wctrlFlags & WHERE_ONEPASS_DESIRED );
while( ALWAYS(pJ) && pJ!=pIx ){
iIndexCur++;
@@ -130443,8 +122969,8 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
}
op = OP_OpenWrite;
pWInfo->aiCurOnePass[1] = iIndexCur;
- }else if( iAuxArg && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ){
- iIndexCur = iAuxArg;
+ }else if( iIdxCur && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ){
+ iIndexCur = iIdxCur;
if( wctrlFlags & WHERE_REOPEN_IDX ) op = OP_ReopenIdx;
}else{
iIndexCur = pParse->nTab++;
@@ -130462,24 +122988,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */
}
VdbeComment((v, "%s", pIx->zName));
-#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
- {
- u64 colUsed = 0;
- int ii, jj;
- for(ii=0; ii<pIx->nColumn; ii++){
- jj = pIx->aiColumn[ii];
- if( jj<0 ) continue;
- if( jj>63 ) jj = 63;
- if( (pTabItem->colUsed & MASKBIT(jj))==0 ) continue;
- colUsed |= ((u64)1)<<(ii<63 ? ii : 63);
- }
- sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, iIndexCur, 0, 0,
- (u8*)&colUsed, P4_INT64);
- }
-#endif /* SQLITE_ENABLE_COLUMN_USED_MASK */
}
}
if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb);
+ notReady &= ~getMask(&pWInfo->sMaskSet, pTabItem->iCursor);
}
pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
if( db->mallocFailed ) goto whereBeginError;
@@ -130501,14 +123013,14 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
if( db->mallocFailed ) goto whereBeginError;
}
#endif
- addrExplain = sqlite3WhereExplainOneScan(
+ addrExplain = explainOneScan(
pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags
);
pLevel->addrBody = sqlite3VdbeCurrentAddr(v);
- notReady = sqlite3WhereCodeOneLoopStart(pWInfo, ii, notReady);
+ notReady = codeOneLoopStart(pWInfo, ii, notReady);
pWInfo->iContinue = pLevel->addrCont;
if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_ONETABLE_ONLY)==0 ){
- sqlite3WhereAddScanStatus(v, pTabList, pLevel, addrExplain);
+ addScanStatus(v, pTabList, pLevel, addrExplain);
}
}
@@ -130570,18 +123082,21 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
}
sqlite3VdbeResolveLabel(v, pLevel->addrBrk);
if( pLevel->addrSkip ){
- sqlite3VdbeGoto(v, pLevel->addrSkip);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrSkip);
VdbeComment((v, "next skip-scan on %s", pLoop->u.btree.pIndex->zName));
sqlite3VdbeJumpHere(v, pLevel->addrSkip);
sqlite3VdbeJumpHere(v, pLevel->addrSkip-2);
}
-#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
if( pLevel->addrLikeRep ){
- sqlite3VdbeAddOp2(v, OP_DecrJumpZero, (int)(pLevel->iLikeRepCntr>>1),
- pLevel->addrLikeRep);
+ int op;
+ if( sqlite3VdbeGetOp(v, pLevel->addrLikeRep-1)->p1 ){
+ op = OP_DecrJumpZero;
+ }else{
+ op = OP_JumpZeroIncr;
+ }
+ sqlite3VdbeAddOp2(v, op, pLevel->iLikeRepCntr, pLevel->addrLikeRep);
VdbeCoverage(v);
}
-#endif
if( pLevel->iLeftJoin ){
addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v);
assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
@@ -130595,7 +123110,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
if( pLevel->op==OP_Return ){
sqlite3VdbeAddOp2(v, OP_Gosub, pLevel->p1, pLevel->addrFirst);
}else{
- sqlite3VdbeGoto(v, pLevel->addrFirst);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrFirst);
}
sqlite3VdbeJumpHere(v, addr);
}
@@ -130619,12 +123134,26 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
pLoop = pLevel->pWLoop;
/* For a co-routine, change all OP_Column references to the table of
- ** the co-routine into OP_Copy of result contained in a register.
+ ** the co-routine into OP_SCopy of result contained in a register.
** OP_Rowid becomes OP_Null.
*/
- if( pTabItem->fg.viaCoroutine && !db->mallocFailed ){
- translateColumnToCopy(v, pLevel->addrBody, pLevel->iTabCur,
- pTabItem->regResult, 0);
+ if( pTabItem->viaCoroutine && !db->mallocFailed ){
+ last = sqlite3VdbeCurrentAddr(v);
+ k = pLevel->addrBody;
+ pOp = sqlite3VdbeGetOp(v, k);
+ for(; k<last; k++, pOp++){
+ if( pOp->p1!=pLevel->iTabCur ) continue;
+ if( pOp->opcode==OP_Column ){
+ pOp->opcode = OP_Copy;
+ pOp->p1 = pOp->p2 + pTabItem->regResult;
+ pOp->p2 = pOp->p3;
+ pOp->p3 = 0;
+ }else if( pOp->opcode==OP_Rowid ){
+ pOp->opcode = OP_Null;
+ pOp->p1 = 0;
+ pOp->p3 = 0;
+ }
+ }
continue;
}
@@ -130638,7 +123167,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
&& (pWInfo->wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0
){
int ws = pLoop->wsFlags;
- if( pWInfo->eOnePass==ONEPASS_OFF && (ws & WHERE_IDX_ONLY)==0 ){
+ if( !pWInfo->okOnePass && (ws & WHERE_IDX_ONLY)==0 ){
sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
}
if( (ws & WHERE_INDEXED)!=0
@@ -130665,10 +123194,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
}else if( pLoop->wsFlags & WHERE_MULTI_OR ){
pIdx = pLevel->u.pCovidx;
}
- if( pIdx
- && (pWInfo->eOnePass==ONEPASS_OFF || !HasRowid(pIdx->pTable))
- && !db->mallocFailed
- ){
+ if( pIdx && !db->mallocFailed ){
last = sqlite3VdbeCurrentAddr(v);
k = pLevel->addrBody;
pOp = sqlite3VdbeGetOp(v, k);
@@ -130680,7 +123206,6 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
if( !HasRowid(pTab) ){
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
x = pPk->aiColumn[x];
- assert( x>=0 );
}
x = sqlite3ColumnOfIndex(pIdx, x);
if( x>=0 ){
@@ -130705,34 +123230,19 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
/************** End of where.c ***********************************************/
/************** Begin file parse.c *******************************************/
-/*
-** 2000-05-29
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** Driver template for the LEMON parser generator.
-**
-** The "lemon" program processes an LALR(1) input grammar file, then uses
-** this template to construct a parser. The "lemon" program inserts text
-** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the
-** interstitial "-" characters) contained in this template is changed into
-** the value of the %name directive from the grammar. Otherwise, the content
-** of this template is copied straight through into the generate parser
-** source file.
+/* Driver template for the LEMON parser generator.
+** The author disclaims copyright to this source code.
**
-** The following is the concatenation of all %include directives from the
-** input grammar file:
+** This version of "lempar.c" is modified, slightly, for use by SQLite.
+** The only modifications are the addition of a couple of NEVER()
+** macros to disable tests that are needed in the case of a general
+** LALR(1) grammar but which are always false in the
+** specific grammar used by SQLite.
*/
+/* First off, code is included that follows the "include" declaration
+** in the input grammar file. */
/* #include <stdio.h> */
-/************ Begin %include sections from the grammar ************************/
-/* #include "sqliteInt.h" */
/*
** Disable all error recovery processing in the parser push-down
@@ -130746,18 +123256,6 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
#define yytestcase(X) testcase(X)
/*
-** Indicate that sqlite3ParserFree() will never be called with a null
-** pointer.
-*/
-#define YYPARSEFREENEVERNULL 1
-
-/*
-** Alternative datatype for the argument to the malloc() routine passed
-** into sqlite3ParserAlloc(). The default is size_t.
-*/
-#define YYMALLOCARGTYPE u64
-
-/*
** An instance of this structure holds information about the
** LIMIT clause of a SELECT statement.
*/
@@ -130791,15 +123289,6 @@ struct TrigEvent { int a; IdList * b; };
*/
struct AttachKey { int type; Token key; };
-/*
-** Disable lookaside memory allocation for objects that might be
-** shared across database connections.
-*/
-static void disableLookaside(Parse *pParse){
- pParse->disableLookaside++;
- pParse->db->lookaside.bDisable++;
-}
-
/*
** For a compound SELECT statement, make sure p->pPrior->pNext==p for
@@ -130836,51 +123325,46 @@ static void disableLookaside(Parse *pParse){
** new Expr to populate pOut. Set the span of pOut to be the identifier
** that created the expression.
*/
- static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token t){
- pOut->pExpr = sqlite3PExpr(pParse, op, 0, 0, &t);
- pOut->zStart = t.z;
- pOut->zEnd = &t.z[t.n];
+ static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token *pValue){
+ pOut->pExpr = sqlite3PExpr(pParse, op, 0, 0, pValue);
+ pOut->zStart = pValue->z;
+ pOut->zEnd = &pValue->z[pValue->n];
}
/* This routine constructs a binary expression node out of two ExprSpan
** objects and uses the result to populate a new ExprSpan object.
*/
static void spanBinaryExpr(
+ ExprSpan *pOut, /* Write the result here */
Parse *pParse, /* The parsing context. Errors accumulate here */
int op, /* The binary operation */
- ExprSpan *pLeft, /* The left operand, and output */
+ ExprSpan *pLeft, /* The left operand */
ExprSpan *pRight /* The right operand */
){
- pLeft->pExpr = sqlite3PExpr(pParse, op, pLeft->pExpr, pRight->pExpr, 0);
- pLeft->zEnd = pRight->zEnd;
- }
-
- /* If doNot is true, then add a TK_NOT Expr-node wrapper around the
- ** outside of *ppExpr.
- */
- static void exprNot(Parse *pParse, int doNot, ExprSpan *pSpan){
- if( doNot ){
- pSpan->pExpr = sqlite3PExpr(pParse, TK_NOT, pSpan->pExpr, 0, 0);
- }
+ pOut->pExpr = sqlite3PExpr(pParse, op, pLeft->pExpr, pRight->pExpr, 0);
+ pOut->zStart = pLeft->zStart;
+ pOut->zEnd = pRight->zEnd;
}
/* Construct an expression node for a unary postfix operator
*/
static void spanUnaryPostfix(
+ ExprSpan *pOut, /* Write the new expression node here */
Parse *pParse, /* Parsing context to record errors */
int op, /* The operator */
- ExprSpan *pOperand, /* The operand, and output */
+ ExprSpan *pOperand, /* The operand */
Token *pPostOp /* The operand token for setting the span */
){
- pOperand->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
- pOperand->zEnd = &pPostOp->z[pPostOp->n];
+ pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
+ pOut->zStart = pOperand->zStart;
+ pOut->zEnd = &pPostOp->z[pPostOp->n];
}
/* A routine to convert a binary TK_IS or TK_ISNOT expression into a
** unary TK_ISNULL or TK_NOTNULL expression. */
static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){
sqlite3 *db = pParse->db;
- if( pA && pY && pY->op==TK_NULL ){
+ if( pY && pA && pY->op==TK_NULL ){
pA->op = (u8)op;
sqlite3ExprDelete(db, pA->pRight);
pA->pRight = 0;
@@ -130896,112 +123380,82 @@ static void disableLookaside(Parse *pParse){
ExprSpan *pOperand, /* The operand */
Token *pPreOp /* The operand token for setting the span */
){
- pOut->zStart = pPreOp->z;
pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
+ pOut->zStart = pPreOp->z;
pOut->zEnd = pOperand->zEnd;
}
-
- /* Add a single new term to an ExprList that is used to store a
- ** list of identifiers. Report an error if the ID list contains
- ** a COLLATE clause or an ASC or DESC keyword, except ignore the
- ** error while parsing a legacy schema.
- */
- static ExprList *parserAddExprIdListTerm(
- Parse *pParse,
- ExprList *pPrior,
- Token *pIdToken,
- int hasCollate,
- int sortOrder
- ){
- ExprList *p = sqlite3ExprListAppend(pParse, pPrior, 0);
- if( (hasCollate || sortOrder!=SQLITE_SO_UNDEFINED)
- && pParse->db->init.busy==0
- ){
- sqlite3ErrorMsg(pParse, "syntax error after column name \"%.*s\"",
- pIdToken->n, pIdToken->z);
- }
- sqlite3ExprListSetName(pParse, p, pIdToken, 1);
- return p;
- }
-/**************** End of %include directives **********************************/
-/* These constants specify the various numeric values for terminal symbols
-** in a format understandable to "makeheaders". This section is blank unless
-** "lemon" is run with the "-m" command-line option.
-***************** Begin makeheaders token definitions *************************/
-/**************** End makeheaders token definitions ***************************/
-
-/* The next sections is a series of control #defines.
+/* Next is all token values, in a form suitable for use by makeheaders.
+** This section will be null unless lemon is run with the -m switch.
+*/
+/*
+** These constants (all generated automatically by the parser generator)
+** specify the various kinds of tokens (terminals) that the parser
+** understands.
+**
+** Each symbol here is a terminal symbol in the grammar.
+*/
+/* Make sure the INTERFACE macro is defined.
+*/
+#ifndef INTERFACE
+# define INTERFACE 1
+#endif
+/* The next thing included is series of defines which control
** various aspects of the generated parser.
-** YYCODETYPE is the data type used to store the integer codes
-** that represent terminal and non-terminal symbols.
-** "unsigned char" is used if there are fewer than
-** 256 symbols. Larger types otherwise.
-** YYNOCODE is a number of type YYCODETYPE that is not used for
-** any terminal or nonterminal symbol.
+** YYCODETYPE is the data type used for storing terminal
+** and nonterminal numbers. "unsigned char" is
+** used if there are fewer than 250 terminals
+** and nonterminals. "int" is used otherwise.
+** YYNOCODE is a number of type YYCODETYPE which corresponds
+** to no legal terminal or nonterminal number. This
+** number is used to fill in empty slots of the hash
+** table.
** YYFALLBACK If defined, this indicates that one or more tokens
-** (also known as: "terminal symbols") have fall-back
-** values which should be used if the original symbol
-** would not parse. This permits keywords to sometimes
-** be used as identifiers, for example.
-** YYACTIONTYPE is the data type used for "action codes" - numbers
-** that indicate what to do in response to the next
-** token.
-** sqlite3ParserTOKENTYPE is the data type used for minor type for terminal
-** symbols. Background: A "minor type" is a semantic
-** value associated with a terminal or non-terminal
-** symbols. For example, for an "ID" terminal symbol,
-** the minor type might be the name of the identifier.
-** Each non-terminal can have a different minor type.
-** Terminal symbols all have the same minor type, though.
-** This macros defines the minor type for terminal
-** symbols.
-** YYMINORTYPE is the data type used for all minor types.
+** have fall-back values which should be used if the
+** original value of the token will not parse.
+** YYACTIONTYPE is the data type used for storing terminal
+** and nonterminal numbers. "unsigned char" is
+** used if there are fewer than 250 rules and
+** states combined. "int" is used otherwise.
+** sqlite3ParserTOKENTYPE is the data type used for minor tokens given
+** directly to the parser from the tokenizer.
+** YYMINORTYPE is the data type used for all minor tokens.
** This is typically a union of many types, one of
** which is sqlite3ParserTOKENTYPE. The entry in the union
-** for terminal symbols is called "yy0".
+** for base tokens is called "yy0".
** YYSTACKDEPTH is the maximum depth of the parser's stack. If
** zero the stack is dynamically sized using realloc()
** sqlite3ParserARG_SDECL A static variable declaration for the %extra_argument
** sqlite3ParserARG_PDECL A parameter declaration for the %extra_argument
** sqlite3ParserARG_STORE Code to store %extra_argument into yypParser
** sqlite3ParserARG_FETCH Code to extract %extra_argument from yypParser
-** YYERRORSYMBOL is the code number of the error symbol. If not
-** defined, then do no error processing.
** YYNSTATE the combined number of states.
** YYNRULE the number of rules in the grammar
-** YY_MAX_SHIFT Maximum value for shift actions
-** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
-** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
-** YY_MIN_REDUCE Maximum value for reduce actions
-** YY_ERROR_ACTION The yy_action[] code for syntax error
-** YY_ACCEPT_ACTION The yy_action[] code for accept
-** YY_NO_ACTION The yy_action[] code for no-op
+** YYERRORSYMBOL is the code number of the error symbol. If not
+** defined, then do no error processing.
*/
-#ifndef INTERFACE
-# define INTERFACE 1
-#endif
-/************* Begin control #defines *****************************************/
#define YYCODETYPE unsigned char
-#define YYNOCODE 251
+#define YYNOCODE 254
#define YYACTIONTYPE unsigned short int
-#define YYWILDCARD 96
+#define YYWILDCARD 70
#define sqlite3ParserTOKENTYPE Token
typedef union {
int yyinit;
sqlite3ParserTOKENTYPE yy0;
- struct LimitVal yy64;
- Expr* yy122;
- Select* yy159;
- IdList* yy180;
- struct {int value; int mask;} yy207;
- struct LikeOp yy318;
- TriggerStep* yy327;
- With* yy331;
- ExprSpan yy342;
- SrcList* yy347;
- int yy392;
- struct TrigEvent yy410;
- ExprList* yy442;
+ Select* yy3;
+ ExprList* yy14;
+ With* yy59;
+ SrcList* yy65;
+ struct LikeOp yy96;
+ Expr* yy132;
+ u8 yy186;
+ int yy328;
+ ExprSpan yy346;
+ struct TrigEvent yy378;
+ u16 yy381;
+ IdList* yy408;
+ struct {int value; int mask;} yy429;
+ TriggerStep* yy473;
+ struct LimitVal yy476;
} YYMINORTYPE;
#ifndef YYSTACKDEPTH
#define YYSTACKDEPTH 100
@@ -131010,18 +123464,16 @@ typedef union {
#define sqlite3ParserARG_PDECL ,Parse *pParse
#define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse
#define sqlite3ParserARG_STORE yypParser->pParse = pParse
+#define YYNSTATE 642
+#define YYNRULE 327
#define YYFALLBACK 1
-#define YYNSTATE 440
-#define YYNRULE 326
-#define YY_MAX_SHIFT 439
-#define YY_MIN_SHIFTREDUCE 649
-#define YY_MAX_SHIFTREDUCE 974
-#define YY_MIN_REDUCE 975
-#define YY_MAX_REDUCE 1300
-#define YY_ERROR_ACTION 1301
-#define YY_ACCEPT_ACTION 1302
-#define YY_NO_ACTION 1303
-/************* End control #defines *******************************************/
+#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
+#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
+#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
+
+/* The yyzerominor constant is used to initialize instances of
+** YYMINORTYPE objects to zero. */
+static const YYMINORTYPE yyzerominor = { 0 };
/* Define the yytestcase() macro to be a no-op if is not already defined
** otherwise.
@@ -131044,20 +123496,16 @@ typedef union {
** Suppose the action integer is N. Then the action is determined as
** follows
**
-** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead
+** 0 <= N < YYNSTATE Shift N. That is, push the lookahead
** token onto the stack and goto state N.
**
-** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then
-** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE.
+** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE.
**
-** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE
-** and YY_MAX_REDUCE
-
-** N == YY_ERROR_ACTION A syntax error has occurred.
+** N == YYNSTATE+YYNRULE A syntax error has occurred.
**
-** N == YY_ACCEPT_ACTION The parser accepts its input.
+** N == YYNSTATE+YYNRULE+1 The parser accepts its input.
**
-** N == YY_NO_ACTION No such action. Denotes unused
+** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused
** slots in the yy_action[] table.
**
** The action table is constructed as a single large table named yy_action[].
@@ -131086,453 +123534,468 @@ typedef union {
** yy_reduce_ofst[] For each state, the offset into yy_action for
** shifting non-terminals after a reduce.
** yy_default[] Default action for each state.
-**
-*********** Begin parsing tables **********************************************/
-#define YY_ACTTAB_COUNT (1501)
+*/
+#define YY_ACTTAB_COUNT (1497)
static const YYACTIONTYPE yy_action[] = {
- /* 0 */ 315, 810, 339, 804, 5, 194, 194, 798, 92, 93,
- /* 10 */ 83, 819, 819, 831, 834, 823, 823, 90, 90, 91,
- /* 20 */ 91, 91, 91, 290, 89, 89, 89, 89, 88, 88,
- /* 30 */ 87, 87, 87, 86, 339, 315, 952, 952, 803, 803,
- /* 40 */ 803, 922, 342, 92, 93, 83, 819, 819, 831, 834,
- /* 50 */ 823, 823, 90, 90, 91, 91, 91, 91, 123, 89,
- /* 60 */ 89, 89, 89, 88, 88, 87, 87, 87, 86, 339,
- /* 70 */ 88, 88, 87, 87, 87, 86, 339, 772, 952, 952,
- /* 80 */ 315, 87, 87, 87, 86, 339, 773, 68, 92, 93,
- /* 90 */ 83, 819, 819, 831, 834, 823, 823, 90, 90, 91,
- /* 100 */ 91, 91, 91, 434, 89, 89, 89, 89, 88, 88,
- /* 110 */ 87, 87, 87, 86, 339, 1302, 146, 921, 2, 315,
- /* 120 */ 427, 24, 679, 953, 48, 86, 339, 92, 93, 83,
- /* 130 */ 819, 819, 831, 834, 823, 823, 90, 90, 91, 91,
- /* 140 */ 91, 91, 94, 89, 89, 89, 89, 88, 88, 87,
- /* 150 */ 87, 87, 86, 339, 933, 933, 315, 259, 412, 398,
- /* 160 */ 396, 57, 733, 733, 92, 93, 83, 819, 819, 831,
- /* 170 */ 834, 823, 823, 90, 90, 91, 91, 91, 91, 56,
- /* 180 */ 89, 89, 89, 89, 88, 88, 87, 87, 87, 86,
- /* 190 */ 339, 315, 1245, 922, 342, 268, 934, 935, 241, 92,
- /* 200 */ 93, 83, 819, 819, 831, 834, 823, 823, 90, 90,
- /* 210 */ 91, 91, 91, 91, 291, 89, 89, 89, 89, 88,
- /* 220 */ 88, 87, 87, 87, 86, 339, 315, 913, 1295, 682,
- /* 230 */ 687, 1295, 233, 397, 92, 93, 83, 819, 819, 831,
- /* 240 */ 834, 823, 823, 90, 90, 91, 91, 91, 91, 326,
- /* 250 */ 89, 89, 89, 89, 88, 88, 87, 87, 87, 86,
- /* 260 */ 339, 315, 85, 82, 168, 680, 431, 938, 939, 92,
- /* 270 */ 93, 83, 819, 819, 831, 834, 823, 823, 90, 90,
- /* 280 */ 91, 91, 91, 91, 291, 89, 89, 89, 89, 88,
- /* 290 */ 88, 87, 87, 87, 86, 339, 315, 319, 913, 1296,
- /* 300 */ 797, 911, 1296, 681, 92, 93, 83, 819, 819, 831,
- /* 310 */ 834, 823, 823, 90, 90, 91, 91, 91, 91, 335,
- /* 320 */ 89, 89, 89, 89, 88, 88, 87, 87, 87, 86,
- /* 330 */ 339, 315, 876, 876, 373, 85, 82, 168, 944, 92,
- /* 340 */ 93, 83, 819, 819, 831, 834, 823, 823, 90, 90,
- /* 350 */ 91, 91, 91, 91, 896, 89, 89, 89, 89, 88,
- /* 360 */ 88, 87, 87, 87, 86, 339, 315, 370, 307, 973,
- /* 370 */ 367, 1, 911, 433, 92, 93, 83, 819, 819, 831,
- /* 380 */ 834, 823, 823, 90, 90, 91, 91, 91, 91, 189,
- /* 390 */ 89, 89, 89, 89, 88, 88, 87, 87, 87, 86,
- /* 400 */ 339, 315, 720, 948, 933, 933, 149, 718, 948, 92,
- /* 410 */ 93, 83, 819, 819, 831, 834, 823, 823, 90, 90,
- /* 420 */ 91, 91, 91, 91, 434, 89, 89, 89, 89, 88,
- /* 430 */ 88, 87, 87, 87, 86, 339, 338, 938, 939, 947,
- /* 440 */ 694, 940, 974, 315, 953, 48, 934, 935, 715, 689,
- /* 450 */ 71, 92, 93, 83, 819, 819, 831, 834, 823, 823,
- /* 460 */ 90, 90, 91, 91, 91, 91, 320, 89, 89, 89,
- /* 470 */ 89, 88, 88, 87, 87, 87, 86, 339, 315, 412,
- /* 480 */ 403, 820, 820, 832, 835, 74, 92, 81, 83, 819,
- /* 490 */ 819, 831, 834, 823, 823, 90, 90, 91, 91, 91,
- /* 500 */ 91, 698, 89, 89, 89, 89, 88, 88, 87, 87,
- /* 510 */ 87, 86, 339, 315, 259, 654, 655, 656, 393, 111,
- /* 520 */ 331, 153, 93, 83, 819, 819, 831, 834, 823, 823,
- /* 530 */ 90, 90, 91, 91, 91, 91, 434, 89, 89, 89,
- /* 540 */ 89, 88, 88, 87, 87, 87, 86, 339, 315, 188,
- /* 550 */ 187, 186, 824, 937, 328, 219, 953, 48, 83, 819,
- /* 560 */ 819, 831, 834, 823, 823, 90, 90, 91, 91, 91,
- /* 570 */ 91, 956, 89, 89, 89, 89, 88, 88, 87, 87,
- /* 580 */ 87, 86, 339, 79, 429, 738, 3, 1174, 955, 348,
- /* 590 */ 737, 332, 792, 933, 933, 937, 79, 429, 730, 3,
- /* 600 */ 203, 160, 278, 391, 273, 390, 190, 892, 434, 400,
- /* 610 */ 741, 76, 77, 271, 287, 253, 353, 242, 78, 340,
- /* 620 */ 340, 85, 82, 168, 76, 77, 233, 397, 953, 48,
- /* 630 */ 432, 78, 340, 340, 277, 934, 935, 185, 439, 651,
- /* 640 */ 388, 385, 384, 432, 234, 276, 107, 418, 349, 337,
- /* 650 */ 336, 383, 893, 728, 215, 949, 123, 971, 308, 810,
- /* 660 */ 418, 436, 435, 412, 394, 798, 400, 873, 894, 123,
- /* 670 */ 721, 872, 810, 889, 436, 435, 215, 949, 798, 351,
- /* 680 */ 722, 697, 380, 434, 771, 371, 22, 434, 400, 79,
- /* 690 */ 429, 232, 3, 189, 413, 870, 803, 803, 803, 805,
- /* 700 */ 18, 54, 148, 953, 48, 956, 113, 953, 9, 803,
- /* 710 */ 803, 803, 805, 18, 310, 123, 748, 76, 77, 742,
- /* 720 */ 123, 325, 955, 866, 78, 340, 340, 113, 350, 359,
- /* 730 */ 85, 82, 168, 343, 960, 960, 432, 770, 412, 414,
- /* 740 */ 407, 23, 1240, 1240, 79, 429, 357, 3, 166, 91,
- /* 750 */ 91, 91, 91, 418, 89, 89, 89, 89, 88, 88,
- /* 760 */ 87, 87, 87, 86, 339, 810, 434, 436, 435, 792,
- /* 770 */ 320, 798, 76, 77, 789, 271, 123, 434, 360, 78,
- /* 780 */ 340, 340, 864, 85, 82, 168, 953, 9, 395, 743,
- /* 790 */ 360, 432, 253, 358, 252, 933, 933, 953, 30, 889,
- /* 800 */ 327, 216, 803, 803, 803, 805, 18, 113, 418, 89,
- /* 810 */ 89, 89, 89, 88, 88, 87, 87, 87, 86, 339,
- /* 820 */ 810, 113, 436, 435, 792, 185, 798, 288, 388, 385,
- /* 830 */ 384, 123, 113, 920, 2, 796, 696, 934, 935, 383,
- /* 840 */ 69, 429, 434, 3, 218, 110, 738, 253, 358, 252,
- /* 850 */ 434, 737, 933, 933, 892, 359, 222, 803, 803, 803,
- /* 860 */ 805, 18, 953, 47, 933, 933, 933, 933, 76, 77,
- /* 870 */ 953, 9, 366, 904, 217, 78, 340, 340, 677, 305,
- /* 880 */ 304, 303, 206, 301, 224, 259, 664, 432, 337, 336,
- /* 890 */ 434, 228, 247, 144, 934, 935, 933, 933, 667, 893,
- /* 900 */ 324, 1259, 96, 434, 418, 796, 934, 935, 934, 935,
- /* 910 */ 953, 48, 401, 148, 289, 894, 810, 417, 436, 435,
- /* 920 */ 677, 759, 798, 953, 9, 314, 220, 162, 161, 170,
- /* 930 */ 402, 239, 953, 8, 194, 683, 683, 410, 934, 935,
- /* 940 */ 238, 959, 933, 933, 225, 408, 945, 365, 957, 212,
- /* 950 */ 958, 172, 757, 803, 803, 803, 805, 18, 173, 365,
- /* 960 */ 176, 123, 171, 113, 244, 952, 246, 434, 356, 796,
- /* 970 */ 372, 365, 236, 960, 960, 810, 290, 804, 191, 165,
- /* 980 */ 852, 798, 259, 316, 934, 935, 237, 953, 34, 404,
- /* 990 */ 91, 91, 91, 91, 84, 89, 89, 89, 89, 88,
- /* 1000 */ 88, 87, 87, 87, 86, 339, 701, 952, 434, 240,
- /* 1010 */ 347, 758, 803, 803, 803, 434, 245, 1179, 434, 389,
- /* 1020 */ 434, 376, 434, 895, 167, 434, 405, 702, 953, 35,
- /* 1030 */ 673, 321, 221, 434, 333, 953, 11, 434, 953, 26,
- /* 1040 */ 953, 36, 953, 37, 251, 953, 38, 434, 259, 434,
- /* 1050 */ 757, 434, 329, 953, 27, 434, 223, 953, 28, 434,
- /* 1060 */ 690, 434, 67, 434, 65, 434, 862, 953, 39, 953,
- /* 1070 */ 40, 953, 41, 423, 434, 953, 10, 434, 772, 953,
- /* 1080 */ 42, 953, 98, 953, 43, 953, 44, 773, 434, 346,
- /* 1090 */ 434, 75, 434, 73, 953, 31, 434, 953, 45, 434,
- /* 1100 */ 259, 434, 690, 434, 757, 434, 887, 434, 953, 46,
- /* 1110 */ 953, 32, 953, 115, 434, 266, 953, 116, 951, 953,
- /* 1120 */ 117, 953, 52, 953, 33, 953, 99, 953, 49, 726,
- /* 1130 */ 434, 909, 434, 19, 953, 100, 434, 344, 434, 113,
- /* 1140 */ 434, 258, 692, 434, 259, 434, 670, 434, 20, 434,
- /* 1150 */ 953, 101, 953, 97, 434, 259, 953, 114, 953, 112,
- /* 1160 */ 953, 105, 113, 953, 104, 953, 102, 953, 103, 953,
- /* 1170 */ 51, 434, 148, 434, 953, 53, 167, 434, 259, 113,
- /* 1180 */ 300, 307, 912, 363, 311, 860, 248, 261, 209, 264,
- /* 1190 */ 416, 953, 50, 953, 25, 420, 727, 953, 29, 430,
- /* 1200 */ 321, 424, 757, 428, 322, 124, 1269, 214, 165, 710,
- /* 1210 */ 859, 908, 806, 794, 309, 158, 193, 361, 254, 723,
- /* 1220 */ 364, 67, 381, 269, 735, 199, 67, 70, 113, 700,
- /* 1230 */ 699, 707, 708, 884, 113, 766, 113, 855, 193, 883,
- /* 1240 */ 199, 869, 869, 675, 868, 868, 109, 368, 255, 260,
- /* 1250 */ 263, 280, 859, 265, 806, 974, 267, 711, 695, 272,
- /* 1260 */ 764, 282, 795, 284, 150, 744, 755, 415, 292, 293,
- /* 1270 */ 802, 678, 672, 661, 660, 662, 927, 6, 306, 386,
- /* 1280 */ 352, 786, 243, 250, 886, 362, 163, 286, 419, 298,
- /* 1290 */ 930, 159, 968, 196, 126, 903, 901, 965, 55, 58,
- /* 1300 */ 323, 275, 857, 136, 147, 694, 856, 121, 65, 354,
- /* 1310 */ 355, 379, 175, 61, 151, 369, 180, 871, 375, 129,
- /* 1320 */ 257, 756, 210, 181, 145, 131, 132, 377, 262, 663,
- /* 1330 */ 133, 134, 139, 783, 791, 182, 392, 183, 312, 330,
- /* 1340 */ 714, 888, 713, 851, 692, 195, 712, 406, 686, 705,
- /* 1350 */ 313, 685, 64, 839, 274, 72, 684, 334, 942, 95,
- /* 1360 */ 752, 279, 281, 704, 753, 751, 422, 283, 411, 750,
- /* 1370 */ 426, 66, 204, 409, 21, 285, 928, 669, 437, 205,
- /* 1380 */ 207, 208, 438, 658, 657, 652, 118, 108, 119, 226,
- /* 1390 */ 650, 341, 157, 235, 169, 345, 106, 734, 790, 296,
- /* 1400 */ 294, 295, 120, 297, 867, 865, 127, 128, 130, 724,
- /* 1410 */ 229, 174, 249, 882, 137, 230, 138, 135, 885, 231,
- /* 1420 */ 59, 60, 177, 881, 7, 178, 12, 179, 256, 874,
- /* 1430 */ 140, 193, 962, 374, 141, 152, 666, 378, 276, 184,
- /* 1440 */ 270, 122, 142, 382, 387, 62, 13, 14, 703, 63,
- /* 1450 */ 125, 317, 318, 227, 809, 808, 837, 732, 15, 164,
- /* 1460 */ 736, 4, 765, 211, 399, 213, 192, 143, 760, 70,
- /* 1470 */ 67, 16, 17, 838, 836, 891, 841, 890, 198, 197,
- /* 1480 */ 917, 154, 421, 923, 918, 155, 200, 977, 425, 840,
- /* 1490 */ 156, 201, 807, 676, 80, 302, 299, 977, 202, 1261,
- /* 1500 */ 1260,
+ /* 0 */ 306, 212, 432, 955, 639, 191, 955, 295, 559, 88,
+ /* 10 */ 88, 88, 88, 81, 86, 86, 86, 86, 85, 85,
+ /* 20 */ 84, 84, 84, 83, 330, 185, 184, 183, 635, 635,
+ /* 30 */ 292, 606, 606, 88, 88, 88, 88, 683, 86, 86,
+ /* 40 */ 86, 86, 85, 85, 84, 84, 84, 83, 330, 16,
+ /* 50 */ 436, 597, 89, 90, 80, 600, 599, 601, 601, 87,
+ /* 60 */ 87, 88, 88, 88, 88, 684, 86, 86, 86, 86,
+ /* 70 */ 85, 85, 84, 84, 84, 83, 330, 306, 559, 84,
+ /* 80 */ 84, 84, 83, 330, 65, 86, 86, 86, 86, 85,
+ /* 90 */ 85, 84, 84, 84, 83, 330, 635, 635, 634, 633,
+ /* 100 */ 182, 682, 550, 379, 376, 375, 17, 322, 606, 606,
+ /* 110 */ 371, 198, 479, 91, 374, 82, 79, 165, 85, 85,
+ /* 120 */ 84, 84, 84, 83, 330, 598, 635, 635, 107, 89,
+ /* 130 */ 90, 80, 600, 599, 601, 601, 87, 87, 88, 88,
+ /* 140 */ 88, 88, 186, 86, 86, 86, 86, 85, 85, 84,
+ /* 150 */ 84, 84, 83, 330, 306, 594, 594, 142, 328, 327,
+ /* 160 */ 484, 249, 344, 238, 635, 635, 634, 633, 585, 448,
+ /* 170 */ 526, 525, 229, 388, 1, 394, 450, 584, 449, 635,
+ /* 180 */ 635, 635, 635, 319, 395, 606, 606, 199, 157, 273,
+ /* 190 */ 382, 268, 381, 187, 635, 635, 634, 633, 311, 555,
+ /* 200 */ 266, 593, 593, 266, 347, 588, 89, 90, 80, 600,
+ /* 210 */ 599, 601, 601, 87, 87, 88, 88, 88, 88, 478,
+ /* 220 */ 86, 86, 86, 86, 85, 85, 84, 84, 84, 83,
+ /* 230 */ 330, 306, 272, 536, 634, 633, 146, 610, 197, 310,
+ /* 240 */ 575, 182, 482, 271, 379, 376, 375, 506, 21, 634,
+ /* 250 */ 633, 634, 633, 635, 635, 374, 611, 574, 548, 440,
+ /* 260 */ 111, 563, 606, 606, 634, 633, 324, 479, 608, 608,
+ /* 270 */ 608, 300, 435, 573, 119, 407, 210, 162, 562, 883,
+ /* 280 */ 592, 592, 306, 89, 90, 80, 600, 599, 601, 601,
+ /* 290 */ 87, 87, 88, 88, 88, 88, 506, 86, 86, 86,
+ /* 300 */ 86, 85, 85, 84, 84, 84, 83, 330, 620, 111,
+ /* 310 */ 635, 635, 361, 606, 606, 358, 249, 349, 248, 433,
+ /* 320 */ 243, 479, 586, 634, 633, 195, 611, 93, 119, 221,
+ /* 330 */ 575, 497, 534, 534, 89, 90, 80, 600, 599, 601,
+ /* 340 */ 601, 87, 87, 88, 88, 88, 88, 574, 86, 86,
+ /* 350 */ 86, 86, 85, 85, 84, 84, 84, 83, 330, 306,
+ /* 360 */ 77, 429, 638, 573, 589, 530, 240, 230, 242, 105,
+ /* 370 */ 249, 349, 248, 515, 588, 208, 460, 529, 564, 173,
+ /* 380 */ 634, 633, 970, 144, 430, 2, 424, 228, 380, 557,
+ /* 390 */ 606, 606, 190, 153, 159, 158, 514, 51, 632, 631,
+ /* 400 */ 630, 71, 536, 432, 954, 196, 610, 954, 614, 45,
+ /* 410 */ 18, 89, 90, 80, 600, 599, 601, 601, 87, 87,
+ /* 420 */ 88, 88, 88, 88, 261, 86, 86, 86, 86, 85,
+ /* 430 */ 85, 84, 84, 84, 83, 330, 306, 608, 608, 608,
+ /* 440 */ 542, 424, 402, 385, 241, 506, 451, 320, 211, 543,
+ /* 450 */ 164, 436, 386, 293, 451, 587, 108, 496, 111, 334,
+ /* 460 */ 391, 591, 424, 614, 27, 452, 453, 606, 606, 72,
+ /* 470 */ 257, 70, 259, 452, 339, 342, 564, 582, 68, 415,
+ /* 480 */ 469, 328, 327, 62, 614, 45, 110, 393, 89, 90,
+ /* 490 */ 80, 600, 599, 601, 601, 87, 87, 88, 88, 88,
+ /* 500 */ 88, 152, 86, 86, 86, 86, 85, 85, 84, 84,
+ /* 510 */ 84, 83, 330, 306, 110, 499, 520, 538, 402, 389,
+ /* 520 */ 424, 110, 566, 500, 593, 593, 454, 82, 79, 165,
+ /* 530 */ 424, 591, 384, 564, 340, 615, 188, 162, 424, 350,
+ /* 540 */ 616, 424, 614, 44, 606, 606, 445, 582, 300, 434,
+ /* 550 */ 151, 19, 614, 9, 568, 580, 348, 615, 469, 567,
+ /* 560 */ 614, 26, 616, 614, 45, 89, 90, 80, 600, 599,
+ /* 570 */ 601, 601, 87, 87, 88, 88, 88, 88, 411, 86,
+ /* 580 */ 86, 86, 86, 85, 85, 84, 84, 84, 83, 330,
+ /* 590 */ 306, 579, 110, 578, 521, 282, 433, 398, 400, 255,
+ /* 600 */ 486, 82, 79, 165, 487, 164, 82, 79, 165, 488,
+ /* 610 */ 488, 364, 387, 424, 544, 544, 509, 350, 362, 155,
+ /* 620 */ 191, 606, 606, 559, 642, 640, 333, 82, 79, 165,
+ /* 630 */ 305, 564, 507, 312, 357, 614, 45, 329, 596, 595,
+ /* 640 */ 194, 337, 89, 90, 80, 600, 599, 601, 601, 87,
+ /* 650 */ 87, 88, 88, 88, 88, 424, 86, 86, 86, 86,
+ /* 660 */ 85, 85, 84, 84, 84, 83, 330, 306, 20, 323,
+ /* 670 */ 150, 263, 211, 543, 421, 596, 595, 614, 22, 424,
+ /* 680 */ 193, 424, 284, 424, 391, 424, 509, 424, 577, 424,
+ /* 690 */ 186, 335, 424, 559, 424, 313, 120, 546, 606, 606,
+ /* 700 */ 67, 614, 47, 614, 50, 614, 48, 614, 100, 614,
+ /* 710 */ 99, 614, 101, 576, 614, 102, 614, 109, 326, 89,
+ /* 720 */ 90, 80, 600, 599, 601, 601, 87, 87, 88, 88,
+ /* 730 */ 88, 88, 424, 86, 86, 86, 86, 85, 85, 84,
+ /* 740 */ 84, 84, 83, 330, 306, 424, 311, 424, 585, 54,
+ /* 750 */ 424, 516, 517, 590, 614, 112, 424, 584, 424, 572,
+ /* 760 */ 424, 195, 424, 571, 424, 67, 424, 614, 94, 614,
+ /* 770 */ 98, 424, 614, 97, 264, 606, 606, 195, 614, 46,
+ /* 780 */ 614, 96, 614, 30, 614, 49, 614, 115, 614, 114,
+ /* 790 */ 418, 229, 388, 614, 113, 306, 89, 90, 80, 600,
+ /* 800 */ 599, 601, 601, 87, 87, 88, 88, 88, 88, 424,
+ /* 810 */ 86, 86, 86, 86, 85, 85, 84, 84, 84, 83,
+ /* 820 */ 330, 119, 424, 590, 110, 372, 606, 606, 195, 53,
+ /* 830 */ 250, 614, 29, 195, 472, 438, 729, 190, 302, 498,
+ /* 840 */ 14, 523, 641, 2, 614, 43, 306, 89, 90, 80,
+ /* 850 */ 600, 599, 601, 601, 87, 87, 88, 88, 88, 88,
+ /* 860 */ 424, 86, 86, 86, 86, 85, 85, 84, 84, 84,
+ /* 870 */ 83, 330, 424, 613, 964, 964, 354, 606, 606, 420,
+ /* 880 */ 312, 64, 614, 42, 391, 355, 283, 437, 301, 255,
+ /* 890 */ 414, 410, 495, 492, 614, 28, 471, 306, 89, 90,
+ /* 900 */ 80, 600, 599, 601, 601, 87, 87, 88, 88, 88,
+ /* 910 */ 88, 424, 86, 86, 86, 86, 85, 85, 84, 84,
+ /* 920 */ 84, 83, 330, 424, 110, 110, 110, 110, 606, 606,
+ /* 930 */ 110, 254, 13, 614, 41, 532, 531, 283, 481, 531,
+ /* 940 */ 457, 284, 119, 561, 356, 614, 40, 284, 306, 89,
+ /* 950 */ 78, 80, 600, 599, 601, 601, 87, 87, 88, 88,
+ /* 960 */ 88, 88, 424, 86, 86, 86, 86, 85, 85, 84,
+ /* 970 */ 84, 84, 83, 330, 110, 424, 341, 220, 555, 606,
+ /* 980 */ 606, 351, 555, 318, 614, 95, 413, 255, 83, 330,
+ /* 990 */ 284, 284, 255, 640, 333, 356, 255, 614, 39, 306,
+ /* 1000 */ 356, 90, 80, 600, 599, 601, 601, 87, 87, 88,
+ /* 1010 */ 88, 88, 88, 424, 86, 86, 86, 86, 85, 85,
+ /* 1020 */ 84, 84, 84, 83, 330, 424, 317, 316, 141, 465,
+ /* 1030 */ 606, 606, 219, 619, 463, 614, 10, 417, 462, 255,
+ /* 1040 */ 189, 510, 553, 351, 207, 363, 161, 614, 38, 315,
+ /* 1050 */ 218, 255, 255, 80, 600, 599, 601, 601, 87, 87,
+ /* 1060 */ 88, 88, 88, 88, 424, 86, 86, 86, 86, 85,
+ /* 1070 */ 85, 84, 84, 84, 83, 330, 76, 419, 255, 3,
+ /* 1080 */ 878, 461, 424, 247, 331, 331, 614, 37, 217, 76,
+ /* 1090 */ 419, 390, 3, 216, 215, 422, 4, 331, 331, 424,
+ /* 1100 */ 547, 12, 424, 545, 614, 36, 424, 541, 422, 424,
+ /* 1110 */ 540, 424, 214, 424, 408, 424, 539, 403, 605, 605,
+ /* 1120 */ 237, 614, 25, 119, 614, 24, 588, 408, 614, 45,
+ /* 1130 */ 118, 614, 35, 614, 34, 614, 33, 614, 23, 588,
+ /* 1140 */ 60, 223, 603, 602, 513, 378, 73, 74, 140, 139,
+ /* 1150 */ 424, 110, 265, 75, 426, 425, 59, 424, 610, 73,
+ /* 1160 */ 74, 549, 402, 404, 424, 373, 75, 426, 425, 604,
+ /* 1170 */ 138, 610, 614, 11, 392, 76, 419, 181, 3, 614,
+ /* 1180 */ 32, 271, 369, 331, 331, 493, 614, 31, 149, 608,
+ /* 1190 */ 608, 608, 607, 15, 422, 365, 614, 8, 137, 489,
+ /* 1200 */ 136, 190, 608, 608, 608, 607, 15, 485, 176, 135,
+ /* 1210 */ 7, 252, 477, 408, 174, 133, 175, 474, 57, 56,
+ /* 1220 */ 132, 130, 119, 76, 419, 588, 3, 468, 245, 464,
+ /* 1230 */ 171, 331, 331, 125, 123, 456, 447, 122, 446, 104,
+ /* 1240 */ 336, 231, 422, 166, 154, 73, 74, 332, 116, 431,
+ /* 1250 */ 121, 309, 75, 426, 425, 222, 106, 610, 308, 637,
+ /* 1260 */ 204, 408, 629, 627, 628, 6, 200, 428, 427, 290,
+ /* 1270 */ 203, 622, 201, 588, 62, 63, 289, 66, 419, 399,
+ /* 1280 */ 3, 401, 288, 92, 143, 331, 331, 287, 608, 608,
+ /* 1290 */ 608, 607, 15, 73, 74, 227, 422, 325, 69, 416,
+ /* 1300 */ 75, 426, 425, 612, 412, 610, 192, 61, 569, 209,
+ /* 1310 */ 396, 226, 278, 225, 383, 408, 527, 558, 276, 533,
+ /* 1320 */ 552, 528, 321, 523, 370, 508, 180, 588, 494, 179,
+ /* 1330 */ 366, 117, 253, 269, 522, 503, 608, 608, 608, 607,
+ /* 1340 */ 15, 551, 502, 58, 274, 524, 178, 73, 74, 304,
+ /* 1350 */ 501, 368, 303, 206, 75, 426, 425, 491, 360, 610,
+ /* 1360 */ 213, 177, 483, 131, 345, 298, 297, 296, 202, 294,
+ /* 1370 */ 480, 490, 466, 134, 172, 129, 444, 346, 470, 128,
+ /* 1380 */ 314, 459, 103, 127, 126, 148, 124, 167, 443, 235,
+ /* 1390 */ 608, 608, 608, 607, 15, 442, 439, 623, 234, 299,
+ /* 1400 */ 145, 583, 291, 377, 581, 160, 119, 156, 270, 636,
+ /* 1410 */ 971, 169, 279, 626, 520, 625, 473, 624, 170, 621,
+ /* 1420 */ 618, 119, 168, 55, 409, 423, 537, 609, 286, 285,
+ /* 1430 */ 405, 570, 560, 556, 5, 52, 458, 554, 147, 267,
+ /* 1440 */ 519, 504, 518, 406, 262, 239, 260, 512, 343, 511,
+ /* 1450 */ 258, 353, 565, 256, 224, 251, 359, 277, 275, 476,
+ /* 1460 */ 475, 246, 352, 244, 467, 455, 236, 233, 232, 307,
+ /* 1470 */ 441, 281, 205, 163, 397, 280, 535, 505, 330, 617,
+ /* 1480 */ 971, 971, 971, 971, 367, 971, 971, 971, 971, 971,
+ /* 1490 */ 971, 971, 971, 971, 971, 971, 338,
};
static const YYCODETYPE yy_lookahead[] = {
- /* 0 */ 19, 95, 53, 97, 22, 24, 24, 101, 27, 28,
- /* 10 */ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
- /* 20 */ 39, 40, 41, 152, 43, 44, 45, 46, 47, 48,
- /* 30 */ 49, 50, 51, 52, 53, 19, 55, 55, 132, 133,
- /* 40 */ 134, 1, 2, 27, 28, 29, 30, 31, 32, 33,
- /* 50 */ 34, 35, 36, 37, 38, 39, 40, 41, 92, 43,
- /* 60 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
- /* 70 */ 47, 48, 49, 50, 51, 52, 53, 61, 97, 97,
- /* 80 */ 19, 49, 50, 51, 52, 53, 70, 26, 27, 28,
- /* 90 */ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
- /* 100 */ 39, 40, 41, 152, 43, 44, 45, 46, 47, 48,
- /* 110 */ 49, 50, 51, 52, 53, 144, 145, 146, 147, 19,
- /* 120 */ 249, 22, 172, 172, 173, 52, 53, 27, 28, 29,
- /* 130 */ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
- /* 140 */ 40, 41, 81, 43, 44, 45, 46, 47, 48, 49,
- /* 150 */ 50, 51, 52, 53, 55, 56, 19, 152, 207, 208,
- /* 160 */ 115, 24, 117, 118, 27, 28, 29, 30, 31, 32,
- /* 170 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 79,
- /* 180 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- /* 190 */ 53, 19, 0, 1, 2, 23, 97, 98, 193, 27,
- /* 200 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- /* 210 */ 38, 39, 40, 41, 152, 43, 44, 45, 46, 47,
- /* 220 */ 48, 49, 50, 51, 52, 53, 19, 22, 23, 172,
- /* 230 */ 23, 26, 119, 120, 27, 28, 29, 30, 31, 32,
- /* 240 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 187,
- /* 250 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- /* 260 */ 53, 19, 221, 222, 223, 23, 168, 169, 170, 27,
- /* 270 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- /* 280 */ 38, 39, 40, 41, 152, 43, 44, 45, 46, 47,
- /* 290 */ 48, 49, 50, 51, 52, 53, 19, 157, 22, 23,
- /* 300 */ 23, 96, 26, 172, 27, 28, 29, 30, 31, 32,
- /* 310 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 187,
- /* 320 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- /* 330 */ 53, 19, 108, 109, 110, 221, 222, 223, 185, 27,
- /* 340 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- /* 350 */ 38, 39, 40, 41, 240, 43, 44, 45, 46, 47,
- /* 360 */ 48, 49, 50, 51, 52, 53, 19, 227, 22, 23,
- /* 370 */ 230, 22, 96, 152, 27, 28, 29, 30, 31, 32,
- /* 380 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 30,
- /* 390 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- /* 400 */ 53, 19, 190, 191, 55, 56, 24, 190, 191, 27,
- /* 410 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- /* 420 */ 38, 39, 40, 41, 152, 43, 44, 45, 46, 47,
- /* 430 */ 48, 49, 50, 51, 52, 53, 168, 169, 170, 179,
- /* 440 */ 180, 171, 96, 19, 172, 173, 97, 98, 188, 179,
- /* 450 */ 138, 27, 28, 29, 30, 31, 32, 33, 34, 35,
- /* 460 */ 36, 37, 38, 39, 40, 41, 107, 43, 44, 45,
- /* 470 */ 46, 47, 48, 49, 50, 51, 52, 53, 19, 207,
- /* 480 */ 208, 30, 31, 32, 33, 138, 27, 28, 29, 30,
- /* 490 */ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- /* 500 */ 41, 181, 43, 44, 45, 46, 47, 48, 49, 50,
- /* 510 */ 51, 52, 53, 19, 152, 7, 8, 9, 49, 22,
- /* 520 */ 19, 24, 28, 29, 30, 31, 32, 33, 34, 35,
- /* 530 */ 36, 37, 38, 39, 40, 41, 152, 43, 44, 45,
- /* 540 */ 46, 47, 48, 49, 50, 51, 52, 53, 19, 108,
- /* 550 */ 109, 110, 101, 55, 53, 193, 172, 173, 29, 30,
- /* 560 */ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- /* 570 */ 41, 152, 43, 44, 45, 46, 47, 48, 49, 50,
- /* 580 */ 51, 52, 53, 19, 20, 116, 22, 23, 169, 170,
- /* 590 */ 121, 207, 85, 55, 56, 97, 19, 20, 195, 22,
- /* 600 */ 99, 100, 101, 102, 103, 104, 105, 12, 152, 206,
- /* 610 */ 210, 47, 48, 112, 152, 108, 109, 110, 54, 55,
- /* 620 */ 56, 221, 222, 223, 47, 48, 119, 120, 172, 173,
- /* 630 */ 66, 54, 55, 56, 101, 97, 98, 99, 148, 149,
- /* 640 */ 102, 103, 104, 66, 154, 112, 156, 83, 229, 47,
- /* 650 */ 48, 113, 57, 163, 194, 195, 92, 246, 247, 95,
- /* 660 */ 83, 97, 98, 207, 208, 101, 206, 59, 73, 92,
- /* 670 */ 75, 63, 95, 163, 97, 98, 194, 195, 101, 219,
- /* 680 */ 85, 181, 19, 152, 175, 77, 196, 152, 206, 19,
- /* 690 */ 20, 199, 22, 30, 163, 11, 132, 133, 134, 135,
- /* 700 */ 136, 209, 152, 172, 173, 152, 196, 172, 173, 132,
- /* 710 */ 133, 134, 135, 136, 164, 92, 213, 47, 48, 49,
- /* 720 */ 92, 186, 169, 170, 54, 55, 56, 196, 100, 219,
- /* 730 */ 221, 222, 223, 243, 132, 133, 66, 175, 207, 208,
- /* 740 */ 152, 231, 119, 120, 19, 20, 236, 22, 152, 38,
- /* 750 */ 39, 40, 41, 83, 43, 44, 45, 46, 47, 48,
- /* 760 */ 49, 50, 51, 52, 53, 95, 152, 97, 98, 85,
- /* 770 */ 107, 101, 47, 48, 163, 112, 92, 152, 152, 54,
- /* 780 */ 55, 56, 229, 221, 222, 223, 172, 173, 163, 49,
- /* 790 */ 152, 66, 108, 109, 110, 55, 56, 172, 173, 163,
- /* 800 */ 186, 22, 132, 133, 134, 135, 136, 196, 83, 43,
- /* 810 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
- /* 820 */ 95, 196, 97, 98, 85, 99, 101, 152, 102, 103,
- /* 830 */ 104, 92, 196, 146, 147, 152, 181, 97, 98, 113,
- /* 840 */ 19, 20, 152, 22, 218, 22, 116, 108, 109, 110,
- /* 850 */ 152, 121, 55, 56, 12, 219, 218, 132, 133, 134,
- /* 860 */ 135, 136, 172, 173, 55, 56, 55, 56, 47, 48,
- /* 870 */ 172, 173, 236, 152, 5, 54, 55, 56, 55, 10,
- /* 880 */ 11, 12, 13, 14, 186, 152, 17, 66, 47, 48,
- /* 890 */ 152, 210, 16, 84, 97, 98, 55, 56, 21, 57,
- /* 900 */ 217, 122, 22, 152, 83, 152, 97, 98, 97, 98,
- /* 910 */ 172, 173, 152, 152, 224, 73, 95, 75, 97, 98,
- /* 920 */ 97, 124, 101, 172, 173, 164, 193, 47, 48, 60,
- /* 930 */ 163, 62, 172, 173, 24, 55, 56, 186, 97, 98,
- /* 940 */ 71, 100, 55, 56, 183, 207, 185, 152, 107, 23,
- /* 950 */ 109, 82, 26, 132, 133, 134, 135, 136, 89, 152,
- /* 960 */ 26, 92, 93, 196, 88, 55, 90, 152, 91, 152,
- /* 970 */ 217, 152, 152, 132, 133, 95, 152, 97, 211, 212,
- /* 980 */ 103, 101, 152, 114, 97, 98, 152, 172, 173, 19,
- /* 990 */ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- /* 1000 */ 48, 49, 50, 51, 52, 53, 65, 97, 152, 152,
- /* 1010 */ 141, 124, 132, 133, 134, 152, 140, 140, 152, 78,
- /* 1020 */ 152, 233, 152, 193, 98, 152, 56, 86, 172, 173,
- /* 1030 */ 166, 167, 237, 152, 217, 172, 173, 152, 172, 173,
- /* 1040 */ 172, 173, 172, 173, 237, 172, 173, 152, 152, 152,
- /* 1050 */ 124, 152, 111, 172, 173, 152, 237, 172, 173, 152,
- /* 1060 */ 55, 152, 26, 152, 130, 152, 152, 172, 173, 172,
- /* 1070 */ 173, 172, 173, 249, 152, 172, 173, 152, 61, 172,
- /* 1080 */ 173, 172, 173, 172, 173, 172, 173, 70, 152, 193,
- /* 1090 */ 152, 137, 152, 139, 172, 173, 152, 172, 173, 152,
- /* 1100 */ 152, 152, 97, 152, 26, 152, 163, 152, 172, 173,
- /* 1110 */ 172, 173, 172, 173, 152, 16, 172, 173, 26, 172,
- /* 1120 */ 173, 172, 173, 172, 173, 172, 173, 172, 173, 163,
- /* 1130 */ 152, 152, 152, 22, 172, 173, 152, 241, 152, 196,
- /* 1140 */ 152, 193, 106, 152, 152, 152, 163, 152, 37, 152,
- /* 1150 */ 172, 173, 172, 173, 152, 152, 172, 173, 172, 173,
- /* 1160 */ 172, 173, 196, 172, 173, 172, 173, 172, 173, 172,
- /* 1170 */ 173, 152, 152, 152, 172, 173, 98, 152, 152, 196,
- /* 1180 */ 160, 22, 23, 19, 164, 193, 152, 88, 232, 90,
- /* 1190 */ 191, 172, 173, 172, 173, 163, 193, 172, 173, 166,
- /* 1200 */ 167, 163, 124, 163, 244, 245, 23, 211, 212, 26,
- /* 1210 */ 55, 23, 55, 23, 26, 123, 26, 152, 23, 193,
- /* 1220 */ 56, 26, 23, 23, 23, 26, 26, 26, 196, 100,
- /* 1230 */ 101, 7, 8, 152, 196, 23, 196, 23, 26, 152,
- /* 1240 */ 26, 132, 133, 23, 132, 133, 26, 152, 152, 152,
- /* 1250 */ 152, 210, 97, 152, 97, 96, 152, 152, 152, 152,
- /* 1260 */ 152, 210, 152, 210, 197, 152, 152, 152, 152, 152,
- /* 1270 */ 152, 152, 152, 152, 152, 152, 152, 198, 150, 176,
- /* 1280 */ 214, 201, 214, 238, 201, 238, 184, 214, 226, 200,
- /* 1290 */ 155, 198, 67, 122, 242, 159, 159, 69, 239, 239,
- /* 1300 */ 159, 175, 175, 22, 220, 180, 175, 27, 130, 18,
- /* 1310 */ 159, 18, 158, 137, 220, 159, 158, 235, 74, 189,
- /* 1320 */ 234, 159, 159, 158, 22, 192, 192, 177, 159, 159,
- /* 1330 */ 192, 192, 189, 201, 189, 158, 107, 158, 177, 76,
- /* 1340 */ 174, 201, 174, 201, 106, 159, 174, 125, 174, 182,
- /* 1350 */ 177, 176, 107, 159, 174, 137, 174, 53, 174, 129,
- /* 1360 */ 216, 215, 215, 182, 216, 216, 177, 215, 126, 216,
- /* 1370 */ 177, 128, 25, 127, 26, 215, 13, 162, 161, 153,
- /* 1380 */ 153, 6, 151, 151, 151, 151, 165, 178, 165, 178,
- /* 1390 */ 4, 3, 22, 142, 15, 94, 16, 205, 120, 202,
- /* 1400 */ 204, 203, 165, 201, 23, 23, 131, 111, 123, 20,
- /* 1410 */ 225, 125, 16, 1, 131, 228, 111, 123, 56, 228,
- /* 1420 */ 37, 37, 64, 1, 5, 122, 22, 107, 140, 80,
- /* 1430 */ 80, 26, 87, 72, 107, 24, 20, 19, 112, 105,
- /* 1440 */ 23, 68, 22, 79, 79, 22, 22, 22, 58, 22,
- /* 1450 */ 245, 248, 248, 79, 23, 23, 23, 116, 22, 122,
- /* 1460 */ 23, 22, 56, 23, 26, 23, 64, 22, 124, 26,
- /* 1470 */ 26, 64, 64, 23, 23, 23, 11, 23, 22, 26,
- /* 1480 */ 23, 22, 24, 1, 23, 22, 26, 250, 24, 23,
- /* 1490 */ 22, 122, 23, 23, 22, 15, 23, 250, 122, 122,
- /* 1500 */ 122,
+ /* 0 */ 19, 22, 22, 23, 1, 24, 26, 15, 27, 80,
+ /* 10 */ 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+ /* 20 */ 91, 92, 93, 94, 95, 108, 109, 110, 27, 28,
+ /* 30 */ 23, 50, 51, 80, 81, 82, 83, 122, 85, 86,
+ /* 40 */ 87, 88, 89, 90, 91, 92, 93, 94, 95, 22,
+ /* 50 */ 70, 23, 71, 72, 73, 74, 75, 76, 77, 78,
+ /* 60 */ 79, 80, 81, 82, 83, 122, 85, 86, 87, 88,
+ /* 70 */ 89, 90, 91, 92, 93, 94, 95, 19, 97, 91,
+ /* 80 */ 92, 93, 94, 95, 26, 85, 86, 87, 88, 89,
+ /* 90 */ 90, 91, 92, 93, 94, 95, 27, 28, 97, 98,
+ /* 100 */ 99, 122, 211, 102, 103, 104, 79, 19, 50, 51,
+ /* 110 */ 19, 122, 59, 55, 113, 224, 225, 226, 89, 90,
+ /* 120 */ 91, 92, 93, 94, 95, 23, 27, 28, 26, 71,
+ /* 130 */ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+ /* 140 */ 82, 83, 51, 85, 86, 87, 88, 89, 90, 91,
+ /* 150 */ 92, 93, 94, 95, 19, 132, 133, 58, 89, 90,
+ /* 160 */ 21, 108, 109, 110, 27, 28, 97, 98, 33, 100,
+ /* 170 */ 7, 8, 119, 120, 22, 19, 107, 42, 109, 27,
+ /* 180 */ 28, 27, 28, 95, 28, 50, 51, 99, 100, 101,
+ /* 190 */ 102, 103, 104, 105, 27, 28, 97, 98, 107, 152,
+ /* 200 */ 112, 132, 133, 112, 65, 69, 71, 72, 73, 74,
+ /* 210 */ 75, 76, 77, 78, 79, 80, 81, 82, 83, 11,
+ /* 220 */ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ /* 230 */ 95, 19, 101, 97, 97, 98, 24, 101, 122, 157,
+ /* 240 */ 12, 99, 103, 112, 102, 103, 104, 152, 22, 97,
+ /* 250 */ 98, 97, 98, 27, 28, 113, 27, 29, 91, 164,
+ /* 260 */ 165, 124, 50, 51, 97, 98, 219, 59, 132, 133,
+ /* 270 */ 134, 22, 23, 45, 66, 47, 212, 213, 124, 140,
+ /* 280 */ 132, 133, 19, 71, 72, 73, 74, 75, 76, 77,
+ /* 290 */ 78, 79, 80, 81, 82, 83, 152, 85, 86, 87,
+ /* 300 */ 88, 89, 90, 91, 92, 93, 94, 95, 164, 165,
+ /* 310 */ 27, 28, 230, 50, 51, 233, 108, 109, 110, 70,
+ /* 320 */ 16, 59, 23, 97, 98, 26, 97, 22, 66, 185,
+ /* 330 */ 12, 187, 27, 28, 71, 72, 73, 74, 75, 76,
+ /* 340 */ 77, 78, 79, 80, 81, 82, 83, 29, 85, 86,
+ /* 350 */ 87, 88, 89, 90, 91, 92, 93, 94, 95, 19,
+ /* 360 */ 22, 148, 149, 45, 23, 47, 62, 154, 64, 156,
+ /* 370 */ 108, 109, 110, 37, 69, 23, 163, 59, 26, 26,
+ /* 380 */ 97, 98, 144, 145, 146, 147, 152, 200, 52, 23,
+ /* 390 */ 50, 51, 26, 22, 89, 90, 60, 210, 7, 8,
+ /* 400 */ 9, 138, 97, 22, 23, 26, 101, 26, 174, 175,
+ /* 410 */ 197, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ /* 420 */ 80, 81, 82, 83, 16, 85, 86, 87, 88, 89,
+ /* 430 */ 90, 91, 92, 93, 94, 95, 19, 132, 133, 134,
+ /* 440 */ 23, 152, 208, 209, 140, 152, 152, 111, 195, 196,
+ /* 450 */ 98, 70, 163, 160, 152, 23, 22, 164, 165, 246,
+ /* 460 */ 207, 27, 152, 174, 175, 171, 172, 50, 51, 137,
+ /* 470 */ 62, 139, 64, 171, 172, 222, 124, 27, 138, 24,
+ /* 480 */ 163, 89, 90, 130, 174, 175, 197, 163, 71, 72,
+ /* 490 */ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ /* 500 */ 83, 22, 85, 86, 87, 88, 89, 90, 91, 92,
+ /* 510 */ 93, 94, 95, 19, 197, 181, 182, 23, 208, 209,
+ /* 520 */ 152, 197, 26, 189, 132, 133, 232, 224, 225, 226,
+ /* 530 */ 152, 97, 91, 26, 232, 116, 212, 213, 152, 222,
+ /* 540 */ 121, 152, 174, 175, 50, 51, 243, 97, 22, 23,
+ /* 550 */ 22, 234, 174, 175, 177, 23, 239, 116, 163, 177,
+ /* 560 */ 174, 175, 121, 174, 175, 71, 72, 73, 74, 75,
+ /* 570 */ 76, 77, 78, 79, 80, 81, 82, 83, 24, 85,
+ /* 580 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ /* 590 */ 19, 23, 197, 11, 23, 227, 70, 208, 220, 152,
+ /* 600 */ 31, 224, 225, 226, 35, 98, 224, 225, 226, 108,
+ /* 610 */ 109, 110, 115, 152, 117, 118, 27, 222, 49, 123,
+ /* 620 */ 24, 50, 51, 27, 0, 1, 2, 224, 225, 226,
+ /* 630 */ 166, 124, 168, 169, 239, 174, 175, 170, 171, 172,
+ /* 640 */ 22, 194, 71, 72, 73, 74, 75, 76, 77, 78,
+ /* 650 */ 79, 80, 81, 82, 83, 152, 85, 86, 87, 88,
+ /* 660 */ 89, 90, 91, 92, 93, 94, 95, 19, 22, 208,
+ /* 670 */ 24, 23, 195, 196, 170, 171, 172, 174, 175, 152,
+ /* 680 */ 26, 152, 152, 152, 207, 152, 97, 152, 23, 152,
+ /* 690 */ 51, 244, 152, 97, 152, 247, 248, 23, 50, 51,
+ /* 700 */ 26, 174, 175, 174, 175, 174, 175, 174, 175, 174,
+ /* 710 */ 175, 174, 175, 23, 174, 175, 174, 175, 188, 71,
+ /* 720 */ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+ /* 730 */ 82, 83, 152, 85, 86, 87, 88, 89, 90, 91,
+ /* 740 */ 92, 93, 94, 95, 19, 152, 107, 152, 33, 24,
+ /* 750 */ 152, 100, 101, 27, 174, 175, 152, 42, 152, 23,
+ /* 760 */ 152, 26, 152, 23, 152, 26, 152, 174, 175, 174,
+ /* 770 */ 175, 152, 174, 175, 23, 50, 51, 26, 174, 175,
+ /* 780 */ 174, 175, 174, 175, 174, 175, 174, 175, 174, 175,
+ /* 790 */ 163, 119, 120, 174, 175, 19, 71, 72, 73, 74,
+ /* 800 */ 75, 76, 77, 78, 79, 80, 81, 82, 83, 152,
+ /* 810 */ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ /* 820 */ 95, 66, 152, 97, 197, 23, 50, 51, 26, 53,
+ /* 830 */ 23, 174, 175, 26, 23, 23, 23, 26, 26, 26,
+ /* 840 */ 36, 106, 146, 147, 174, 175, 19, 71, 72, 73,
+ /* 850 */ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ /* 860 */ 152, 85, 86, 87, 88, 89, 90, 91, 92, 93,
+ /* 870 */ 94, 95, 152, 196, 119, 120, 19, 50, 51, 168,
+ /* 880 */ 169, 26, 174, 175, 207, 28, 152, 249, 250, 152,
+ /* 890 */ 163, 163, 163, 163, 174, 175, 163, 19, 71, 72,
+ /* 900 */ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ /* 910 */ 83, 152, 85, 86, 87, 88, 89, 90, 91, 92,
+ /* 920 */ 93, 94, 95, 152, 197, 197, 197, 197, 50, 51,
+ /* 930 */ 197, 194, 36, 174, 175, 191, 192, 152, 191, 192,
+ /* 940 */ 163, 152, 66, 124, 152, 174, 175, 152, 19, 71,
+ /* 950 */ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+ /* 960 */ 82, 83, 152, 85, 86, 87, 88, 89, 90, 91,
+ /* 970 */ 92, 93, 94, 95, 197, 152, 100, 188, 152, 50,
+ /* 980 */ 51, 152, 152, 188, 174, 175, 252, 152, 94, 95,
+ /* 990 */ 152, 152, 152, 1, 2, 152, 152, 174, 175, 19,
+ /* 1000 */ 152, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+ /* 1010 */ 81, 82, 83, 152, 85, 86, 87, 88, 89, 90,
+ /* 1020 */ 91, 92, 93, 94, 95, 152, 188, 188, 22, 194,
+ /* 1030 */ 50, 51, 240, 173, 194, 174, 175, 252, 194, 152,
+ /* 1040 */ 36, 181, 28, 152, 23, 219, 122, 174, 175, 219,
+ /* 1050 */ 221, 152, 152, 73, 74, 75, 76, 77, 78, 79,
+ /* 1060 */ 80, 81, 82, 83, 152, 85, 86, 87, 88, 89,
+ /* 1070 */ 90, 91, 92, 93, 94, 95, 19, 20, 152, 22,
+ /* 1080 */ 23, 194, 152, 240, 27, 28, 174, 175, 240, 19,
+ /* 1090 */ 20, 26, 22, 194, 194, 38, 22, 27, 28, 152,
+ /* 1100 */ 23, 22, 152, 116, 174, 175, 152, 23, 38, 152,
+ /* 1110 */ 23, 152, 221, 152, 57, 152, 23, 163, 50, 51,
+ /* 1120 */ 194, 174, 175, 66, 174, 175, 69, 57, 174, 175,
+ /* 1130 */ 40, 174, 175, 174, 175, 174, 175, 174, 175, 69,
+ /* 1140 */ 22, 53, 74, 75, 30, 53, 89, 90, 22, 22,
+ /* 1150 */ 152, 197, 23, 96, 97, 98, 22, 152, 101, 89,
+ /* 1160 */ 90, 91, 208, 209, 152, 53, 96, 97, 98, 101,
+ /* 1170 */ 22, 101, 174, 175, 152, 19, 20, 105, 22, 174,
+ /* 1180 */ 175, 112, 19, 27, 28, 20, 174, 175, 24, 132,
+ /* 1190 */ 133, 134, 135, 136, 38, 44, 174, 175, 107, 61,
+ /* 1200 */ 54, 26, 132, 133, 134, 135, 136, 54, 107, 22,
+ /* 1210 */ 5, 140, 1, 57, 36, 111, 122, 28, 79, 79,
+ /* 1220 */ 131, 123, 66, 19, 20, 69, 22, 1, 16, 20,
+ /* 1230 */ 125, 27, 28, 123, 111, 120, 23, 131, 23, 16,
+ /* 1240 */ 68, 142, 38, 15, 22, 89, 90, 3, 167, 4,
+ /* 1250 */ 248, 251, 96, 97, 98, 180, 180, 101, 251, 151,
+ /* 1260 */ 6, 57, 151, 13, 151, 26, 25, 151, 161, 202,
+ /* 1270 */ 153, 162, 153, 69, 130, 128, 203, 19, 20, 127,
+ /* 1280 */ 22, 126, 204, 129, 22, 27, 28, 205, 132, 133,
+ /* 1290 */ 134, 135, 136, 89, 90, 231, 38, 95, 137, 179,
+ /* 1300 */ 96, 97, 98, 206, 179, 101, 122, 107, 159, 159,
+ /* 1310 */ 125, 231, 216, 228, 107, 57, 184, 217, 216, 176,
+ /* 1320 */ 217, 176, 48, 106, 18, 184, 158, 69, 159, 158,
+ /* 1330 */ 46, 71, 237, 176, 176, 176, 132, 133, 134, 135,
+ /* 1340 */ 136, 217, 176, 137, 216, 178, 158, 89, 90, 179,
+ /* 1350 */ 176, 159, 179, 159, 96, 97, 98, 159, 159, 101,
+ /* 1360 */ 5, 158, 202, 22, 18, 10, 11, 12, 13, 14,
+ /* 1370 */ 190, 238, 17, 190, 158, 193, 41, 159, 202, 193,
+ /* 1380 */ 159, 202, 245, 193, 193, 223, 190, 32, 159, 34,
+ /* 1390 */ 132, 133, 134, 135, 136, 159, 39, 155, 43, 150,
+ /* 1400 */ 223, 177, 201, 178, 177, 186, 66, 199, 177, 152,
+ /* 1410 */ 253, 56, 215, 152, 182, 152, 202, 152, 63, 152,
+ /* 1420 */ 152, 66, 67, 242, 229, 152, 174, 152, 152, 152,
+ /* 1430 */ 152, 152, 152, 152, 199, 242, 202, 152, 198, 152,
+ /* 1440 */ 152, 152, 183, 192, 152, 215, 152, 183, 215, 183,
+ /* 1450 */ 152, 241, 214, 152, 211, 152, 152, 211, 211, 152,
+ /* 1460 */ 152, 241, 152, 152, 152, 152, 152, 152, 152, 114,
+ /* 1470 */ 152, 152, 235, 152, 152, 152, 174, 187, 95, 174,
+ /* 1480 */ 253, 253, 253, 253, 236, 253, 253, 253, 253, 253,
+ /* 1490 */ 253, 253, 253, 253, 253, 253, 141,
};
-#define YY_SHIFT_USE_DFLT (-95)
-#define YY_SHIFT_COUNT (439)
-#define YY_SHIFT_MIN (-94)
-#define YY_SHIFT_MAX (1482)
+#define YY_SHIFT_USE_DFLT (-86)
+#define YY_SHIFT_COUNT (429)
+#define YY_SHIFT_MIN (-85)
+#define YY_SHIFT_MAX (1383)
static const short yy_shift_ofst[] = {
- /* 0 */ 40, 564, 869, 577, 725, 725, 725, 739, -19, 16,
- /* 10 */ 16, 100, 725, 725, 725, 725, 725, 725, 725, 841,
- /* 20 */ 841, 538, 507, 684, 623, 61, 137, 172, 207, 242,
- /* 30 */ 277, 312, 347, 382, 424, 424, 424, 424, 424, 424,
- /* 40 */ 424, 424, 424, 424, 424, 424, 424, 424, 424, 459,
- /* 50 */ 424, 494, 529, 529, 670, 725, 725, 725, 725, 725,
- /* 60 */ 725, 725, 725, 725, 725, 725, 725, 725, 725, 725,
- /* 70 */ 725, 725, 725, 725, 725, 725, 725, 725, 725, 725,
- /* 80 */ 725, 725, 725, 821, 725, 725, 725, 725, 725, 725,
- /* 90 */ 725, 725, 725, 725, 725, 725, 725, 952, 711, 711,
- /* 100 */ 711, 711, 711, 766, 23, 32, 811, 877, 663, 602,
- /* 110 */ 602, 811, 73, 113, -51, -95, -95, -95, 501, 501,
- /* 120 */ 501, 595, 595, 809, 205, 276, 811, 811, 811, 811,
- /* 130 */ 811, 811, 811, 811, 811, 811, 811, 811, 811, 811,
- /* 140 */ 811, 811, 811, 811, 811, 811, 192, 628, 498, 498,
- /* 150 */ 113, -34, -34, -34, -34, -34, -34, -95, -95, -95,
- /* 160 */ 880, -94, -94, 726, 740, 99, 797, 887, 349, 811,
- /* 170 */ 811, 811, 811, 811, 811, 811, 811, 811, 811, 811,
- /* 180 */ 811, 811, 811, 811, 811, 811, 941, 941, 941, 811,
- /* 190 */ 811, 926, 811, 811, 811, -18, 811, 811, 842, 811,
- /* 200 */ 811, 811, 811, 811, 811, 811, 811, 811, 811, 224,
- /* 210 */ 608, 910, 910, 910, 1078, 45, 469, 508, 934, 970,
- /* 220 */ 970, 1164, 934, 1164, 1036, 1183, 359, 1017, 970, 954,
- /* 230 */ 1017, 1017, 1092, 730, 497, 1225, 1171, 1171, 1228, 1228,
- /* 240 */ 1171, 1281, 1280, 1178, 1291, 1291, 1291, 1291, 1171, 1293,
- /* 250 */ 1178, 1281, 1280, 1280, 1178, 1171, 1293, 1176, 1244, 1171,
- /* 260 */ 1171, 1293, 1302, 1171, 1293, 1171, 1293, 1302, 1229, 1229,
- /* 270 */ 1229, 1263, 1302, 1229, 1238, 1229, 1263, 1229, 1229, 1222,
- /* 280 */ 1245, 1222, 1245, 1222, 1245, 1222, 1245, 1171, 1171, 1218,
- /* 290 */ 1302, 1304, 1304, 1302, 1230, 1242, 1243, 1246, 1178, 1347,
- /* 300 */ 1348, 1363, 1363, 1375, 1375, 1375, 1375, -95, -95, -95,
- /* 310 */ -95, -95, -95, -95, -95, 451, 876, 346, 1159, 1099,
- /* 320 */ 441, 823, 1188, 1111, 1190, 1195, 1199, 1200, 1005, 1129,
- /* 330 */ 1224, 533, 1201, 1212, 1155, 1214, 1109, 1112, 1220, 1157,
- /* 340 */ 779, 1386, 1388, 1370, 1251, 1379, 1301, 1380, 1381, 1382,
- /* 350 */ 1278, 1275, 1296, 1285, 1389, 1286, 1396, 1412, 1294, 1283,
- /* 360 */ 1383, 1384, 1305, 1362, 1358, 1303, 1422, 1419, 1404, 1320,
- /* 370 */ 1288, 1349, 1405, 1350, 1345, 1361, 1327, 1411, 1416, 1418,
- /* 380 */ 1326, 1334, 1420, 1364, 1423, 1424, 1417, 1425, 1365, 1390,
- /* 390 */ 1427, 1374, 1373, 1431, 1432, 1433, 1341, 1436, 1437, 1439,
- /* 400 */ 1438, 1337, 1440, 1442, 1406, 1402, 1445, 1344, 1443, 1407,
- /* 410 */ 1444, 1408, 1443, 1450, 1451, 1452, 1453, 1454, 1456, 1465,
- /* 420 */ 1457, 1459, 1458, 1460, 1461, 1463, 1464, 1460, 1466, 1468,
- /* 430 */ 1469, 1470, 1472, 1369, 1376, 1377, 1378, 1473, 1480, 1482,
+ /* 0 */ 992, 1057, 1355, 1156, 1204, 1204, 1, 262, -19, 135,
+ /* 10 */ 135, 776, 1204, 1204, 1204, 1204, 69, 69, 53, 208,
+ /* 20 */ 283, 755, 58, 725, 648, 571, 494, 417, 340, 263,
+ /* 30 */ 212, 827, 827, 827, 827, 827, 827, 827, 827, 827,
+ /* 40 */ 827, 827, 827, 827, 827, 827, 878, 827, 929, 980,
+ /* 50 */ 980, 1070, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204,
+ /* 60 */ 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204,
+ /* 70 */ 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204,
+ /* 80 */ 1258, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204,
+ /* 90 */ 1204, 1204, 1204, 1204, -71, -47, -47, -47, -47, -47,
+ /* 100 */ 0, 29, -12, 283, 283, 139, 91, 392, 392, 894,
+ /* 110 */ 672, 726, 1383, -86, -86, -86, 88, 318, 318, 99,
+ /* 120 */ 381, -20, 283, 283, 283, 283, 283, 283, 283, 283,
+ /* 130 */ 283, 283, 283, 283, 283, 283, 283, 283, 283, 283,
+ /* 140 */ 283, 283, 283, 283, 624, 876, 726, 672, 1340, 1340,
+ /* 150 */ 1340, 1340, 1340, 1340, -86, -86, -86, 305, 136, 136,
+ /* 160 */ 142, 167, 226, 154, 137, 152, 283, 283, 283, 283,
+ /* 170 */ 283, 283, 283, 283, 283, 283, 283, 283, 283, 283,
+ /* 180 */ 283, 283, 283, 336, 336, 336, 283, 283, 352, 283,
+ /* 190 */ 283, 283, 283, 283, 228, 283, 283, 283, 283, 283,
+ /* 200 */ 283, 283, 283, 283, 283, 501, 569, 596, 596, 596,
+ /* 210 */ 507, 497, 441, 391, 353, 156, 156, 857, 353, 857,
+ /* 220 */ 735, 813, 639, 715, 156, 332, 715, 715, 496, 419,
+ /* 230 */ 646, 1357, 1184, 1184, 1335, 1335, 1184, 1341, 1260, 1144,
+ /* 240 */ 1346, 1346, 1346, 1346, 1184, 1306, 1144, 1341, 1260, 1260,
+ /* 250 */ 1144, 1184, 1306, 1206, 1284, 1184, 1184, 1306, 1184, 1306,
+ /* 260 */ 1184, 1306, 1262, 1207, 1207, 1207, 1274, 1262, 1207, 1217,
+ /* 270 */ 1207, 1274, 1207, 1207, 1185, 1200, 1185, 1200, 1185, 1200,
+ /* 280 */ 1184, 1184, 1161, 1262, 1202, 1202, 1262, 1154, 1155, 1147,
+ /* 290 */ 1152, 1144, 1241, 1239, 1250, 1250, 1254, 1254, 1254, 1254,
+ /* 300 */ -86, -86, -86, -86, -86, -86, 1068, 304, 526, 249,
+ /* 310 */ 408, -83, 434, 812, 27, 811, 807, 802, 751, 589,
+ /* 320 */ 651, 163, 131, 674, 366, 450, 299, 148, 23, 102,
+ /* 330 */ 229, -21, 1245, 1244, 1222, 1099, 1228, 1172, 1223, 1215,
+ /* 340 */ 1213, 1115, 1106, 1123, 1110, 1209, 1105, 1212, 1226, 1098,
+ /* 350 */ 1089, 1140, 1139, 1104, 1189, 1178, 1094, 1211, 1205, 1187,
+ /* 360 */ 1101, 1071, 1153, 1175, 1146, 1138, 1151, 1091, 1164, 1165,
+ /* 370 */ 1163, 1069, 1072, 1148, 1112, 1134, 1127, 1129, 1126, 1092,
+ /* 380 */ 1114, 1118, 1088, 1090, 1093, 1087, 1084, 987, 1079, 1077,
+ /* 390 */ 1074, 1065, 924, 1021, 1014, 1004, 1006, 819, 739, 896,
+ /* 400 */ 855, 804, 739, 740, 736, 690, 654, 665, 618, 582,
+ /* 410 */ 568, 528, 554, 379, 532, 479, 455, 379, 432, 371,
+ /* 420 */ 341, 28, 338, 116, -11, -57, -85, 7, -8, 3,
};
-#define YY_REDUCE_USE_DFLT (-130)
-#define YY_REDUCE_COUNT (314)
-#define YY_REDUCE_MIN (-129)
-#define YY_REDUCE_MAX (1237)
+#define YY_REDUCE_USE_DFLT (-110)
+#define YY_REDUCE_COUNT (305)
+#define YY_REDUCE_MIN (-109)
+#define YY_REDUCE_MAX (1323)
static const short yy_reduce_ofst[] = {
- /* 0 */ -29, 531, 490, 625, -49, 272, 456, 510, 400, 509,
- /* 10 */ 562, 114, 535, 614, 698, 384, 738, 751, 690, 419,
- /* 20 */ 553, 761, 460, 636, 767, 41, 41, 41, 41, 41,
- /* 30 */ 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
- /* 40 */ 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
- /* 50 */ 41, 41, 41, 41, 760, 815, 856, 863, 866, 868,
- /* 60 */ 870, 873, 881, 885, 895, 897, 899, 903, 907, 909,
- /* 70 */ 911, 913, 922, 925, 936, 938, 940, 944, 947, 949,
- /* 80 */ 951, 953, 955, 962, 978, 980, 984, 986, 988, 991,
- /* 90 */ 993, 995, 997, 1002, 1019, 1021, 1025, 41, 41, 41,
- /* 100 */ 41, 41, 41, 41, 41, 41, 896, 140, 260, 98,
- /* 110 */ 268, 1020, 41, 482, 41, 41, 41, 41, 270, 270,
- /* 120 */ 270, 212, 217, -129, 411, 411, 550, 5, 626, 362,
- /* 130 */ 733, 830, 992, 1003, 1026, 795, 683, 807, 638, 819,
- /* 140 */ 753, 948, 62, 817, 824, 132, 687, 611, 864, 1033,
- /* 150 */ 403, 943, 966, 983, 1032, 1038, 1040, 960, 996, 492,
- /* 160 */ -50, 57, 131, 153, 221, 462, 588, 596, 675, 721,
- /* 170 */ 820, 834, 857, 914, 979, 1034, 1065, 1081, 1087, 1095,
- /* 180 */ 1096, 1097, 1098, 1101, 1104, 1105, 320, 500, 655, 1106,
- /* 190 */ 1107, 503, 1108, 1110, 1113, 681, 1114, 1115, 999, 1116,
- /* 200 */ 1117, 1118, 221, 1119, 1120, 1121, 1122, 1123, 1124, 788,
- /* 210 */ 956, 1041, 1051, 1053, 503, 1067, 1079, 1128, 1080, 1066,
- /* 220 */ 1068, 1045, 1083, 1047, 1103, 1102, 1125, 1126, 1073, 1062,
- /* 230 */ 1127, 1131, 1089, 1093, 1135, 1052, 1136, 1137, 1059, 1060,
- /* 240 */ 1141, 1084, 1130, 1132, 1133, 1134, 1138, 1139, 1151, 1154,
- /* 250 */ 1140, 1094, 1143, 1145, 1142, 1156, 1158, 1082, 1086, 1162,
- /* 260 */ 1163, 1165, 1150, 1169, 1177, 1170, 1179, 1161, 1166, 1168,
- /* 270 */ 1172, 1167, 1173, 1174, 1175, 1180, 1181, 1182, 1184, 1144,
- /* 280 */ 1146, 1148, 1147, 1149, 1152, 1153, 1160, 1186, 1194, 1185,
- /* 290 */ 1189, 1187, 1191, 1193, 1192, 1196, 1198, 1197, 1202, 1215,
- /* 300 */ 1217, 1226, 1227, 1231, 1232, 1233, 1234, 1203, 1204, 1205,
- /* 310 */ 1221, 1223, 1209, 1211, 1237,
+ /* 0 */ 238, 954, 213, 289, 310, 234, 144, 317, -109, 382,
+ /* 10 */ 377, 303, 461, 389, 378, 368, 302, 294, 253, 395,
+ /* 20 */ 293, 324, 403, 403, 403, 403, 403, 403, 403, 403,
+ /* 30 */ 403, 403, 403, 403, 403, 403, 403, 403, 403, 403,
+ /* 40 */ 403, 403, 403, 403, 403, 403, 403, 403, 403, 403,
+ /* 50 */ 403, 1022, 1012, 1005, 998, 963, 961, 959, 957, 950,
+ /* 60 */ 947, 930, 912, 873, 861, 823, 810, 771, 759, 720,
+ /* 70 */ 708, 670, 657, 619, 614, 612, 610, 608, 606, 604,
+ /* 80 */ 598, 595, 593, 580, 542, 540, 537, 535, 533, 531,
+ /* 90 */ 529, 527, 503, 386, 403, 403, 403, 403, 403, 403,
+ /* 100 */ 403, 403, 403, 95, 447, 82, 334, 504, 467, 403,
+ /* 110 */ 477, 464, 403, 403, 403, 403, 860, 747, 744, 785,
+ /* 120 */ 638, 638, 926, 891, 900, 899, 887, 844, 840, 835,
+ /* 130 */ 848, 830, 843, 829, 792, 839, 826, 737, 838, 795,
+ /* 140 */ 789, 47, 734, 530, 696, 777, 711, 677, 733, 730,
+ /* 150 */ 729, 728, 727, 627, 448, 64, 187, 1305, 1302, 1252,
+ /* 160 */ 1290, 1273, 1323, 1322, 1321, 1319, 1318, 1316, 1315, 1314,
+ /* 170 */ 1313, 1312, 1311, 1310, 1308, 1307, 1304, 1303, 1301, 1298,
+ /* 180 */ 1294, 1292, 1289, 1266, 1264, 1259, 1288, 1287, 1238, 1285,
+ /* 190 */ 1281, 1280, 1279, 1278, 1251, 1277, 1276, 1275, 1273, 1268,
+ /* 200 */ 1267, 1265, 1263, 1261, 1257, 1248, 1237, 1247, 1246, 1243,
+ /* 210 */ 1238, 1240, 1235, 1249, 1234, 1233, 1230, 1220, 1214, 1210,
+ /* 220 */ 1225, 1219, 1232, 1231, 1197, 1195, 1227, 1224, 1201, 1208,
+ /* 230 */ 1242, 1137, 1236, 1229, 1193, 1181, 1221, 1177, 1196, 1179,
+ /* 240 */ 1191, 1190, 1186, 1182, 1218, 1216, 1176, 1162, 1183, 1180,
+ /* 250 */ 1160, 1199, 1203, 1133, 1095, 1198, 1194, 1188, 1192, 1171,
+ /* 260 */ 1169, 1168, 1173, 1174, 1166, 1159, 1141, 1170, 1158, 1167,
+ /* 270 */ 1157, 1132, 1145, 1143, 1124, 1128, 1103, 1102, 1100, 1096,
+ /* 280 */ 1150, 1149, 1085, 1125, 1080, 1064, 1120, 1097, 1082, 1078,
+ /* 290 */ 1073, 1067, 1109, 1107, 1119, 1117, 1116, 1113, 1111, 1108,
+ /* 300 */ 1007, 1000, 1002, 1076, 1075, 1081,
};
static const YYACTIONTYPE yy_default[] = {
- /* 0 */ 1250, 1240, 1240, 1240, 1174, 1174, 1174, 1240, 1071, 1100,
- /* 10 */ 1100, 1224, 1301, 1301, 1301, 1301, 1301, 1301, 1173, 1301,
- /* 20 */ 1301, 1301, 1301, 1240, 1075, 1106, 1301, 1301, 1301, 1301,
- /* 30 */ 1301, 1301, 1301, 1301, 1223, 1225, 1114, 1113, 1206, 1087,
- /* 40 */ 1111, 1104, 1108, 1175, 1169, 1170, 1168, 1172, 1176, 1301,
- /* 50 */ 1107, 1138, 1153, 1137, 1301, 1301, 1301, 1301, 1301, 1301,
- /* 60 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
- /* 70 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
- /* 80 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
- /* 90 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1147, 1152, 1159,
- /* 100 */ 1151, 1148, 1140, 1139, 1141, 1142, 1301, 994, 1042, 1301,
- /* 110 */ 1301, 1301, 1143, 1301, 1144, 1156, 1155, 1154, 1231, 1258,
- /* 120 */ 1257, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
- /* 130 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
- /* 140 */ 1301, 1301, 1301, 1301, 1301, 1301, 1250, 1240, 1000, 1000,
- /* 150 */ 1301, 1240, 1240, 1240, 1240, 1240, 1240, 1236, 1075, 1066,
- /* 160 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
- /* 170 */ 1228, 1226, 1301, 1187, 1301, 1301, 1301, 1301, 1301, 1301,
- /* 180 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
- /* 190 */ 1301, 1301, 1301, 1301, 1301, 1071, 1301, 1301, 1301, 1301,
- /* 200 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1252, 1301,
- /* 210 */ 1201, 1071, 1071, 1071, 1073, 1055, 1065, 979, 1110, 1089,
- /* 220 */ 1089, 1290, 1110, 1290, 1017, 1272, 1014, 1100, 1089, 1171,
- /* 230 */ 1100, 1100, 1072, 1065, 1301, 1293, 1080, 1080, 1292, 1292,
- /* 240 */ 1080, 1119, 1045, 1110, 1051, 1051, 1051, 1051, 1080, 991,
- /* 250 */ 1110, 1119, 1045, 1045, 1110, 1080, 991, 1205, 1287, 1080,
- /* 260 */ 1080, 991, 1180, 1080, 991, 1080, 991, 1180, 1043, 1043,
- /* 270 */ 1043, 1032, 1180, 1043, 1017, 1043, 1032, 1043, 1043, 1093,
- /* 280 */ 1088, 1093, 1088, 1093, 1088, 1093, 1088, 1080, 1080, 1301,
- /* 290 */ 1180, 1184, 1184, 1180, 1105, 1094, 1103, 1101, 1110, 997,
- /* 300 */ 1035, 1255, 1255, 1251, 1251, 1251, 1251, 1298, 1298, 1236,
- /* 310 */ 1267, 1267, 1019, 1019, 1267, 1301, 1301, 1301, 1301, 1301,
- /* 320 */ 1301, 1262, 1301, 1189, 1301, 1301, 1301, 1301, 1301, 1301,
- /* 330 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
- /* 340 */ 1125, 1301, 975, 1233, 1301, 1301, 1232, 1301, 1301, 1301,
- /* 350 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
- /* 360 */ 1301, 1301, 1301, 1301, 1301, 1289, 1301, 1301, 1301, 1301,
- /* 370 */ 1301, 1301, 1204, 1203, 1301, 1301, 1301, 1301, 1301, 1301,
- /* 380 */ 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
- /* 390 */ 1301, 1301, 1301, 1301, 1301, 1301, 1057, 1301, 1301, 1301,
- /* 400 */ 1276, 1301, 1301, 1301, 1301, 1301, 1301, 1301, 1102, 1301,
- /* 410 */ 1095, 1301, 1280, 1301, 1301, 1301, 1301, 1301, 1301, 1301,
- /* 420 */ 1301, 1301, 1301, 1242, 1301, 1301, 1301, 1241, 1301, 1301,
- /* 430 */ 1301, 1301, 1301, 1127, 1301, 1126, 1130, 1301, 985, 1301,
+ /* 0 */ 647, 964, 964, 964, 878, 878, 969, 964, 774, 802,
+ /* 10 */ 802, 938, 969, 969, 969, 876, 969, 969, 969, 964,
+ /* 20 */ 969, 778, 808, 969, 969, 969, 969, 969, 969, 969,
+ /* 30 */ 969, 937, 939, 816, 815, 918, 789, 813, 806, 810,
+ /* 40 */ 879, 872, 873, 871, 875, 880, 969, 809, 841, 856,
+ /* 50 */ 840, 969, 969, 969, 969, 969, 969, 969, 969, 969,
+ /* 60 */ 969, 969, 969, 969, 969, 969, 969, 969, 969, 969,
+ /* 70 */ 969, 969, 969, 969, 969, 969, 969, 969, 969, 969,
+ /* 80 */ 969, 969, 969, 969, 969, 969, 969, 969, 969, 969,
+ /* 90 */ 969, 969, 969, 969, 850, 855, 862, 854, 851, 843,
+ /* 100 */ 842, 844, 845, 969, 969, 673, 739, 969, 969, 846,
+ /* 110 */ 969, 685, 847, 859, 858, 857, 680, 969, 969, 969,
+ /* 120 */ 969, 969, 969, 969, 969, 969, 969, 969, 969, 969,
+ /* 130 */ 969, 969, 969, 969, 969, 969, 969, 969, 969, 969,
+ /* 140 */ 969, 969, 969, 969, 647, 964, 969, 969, 964, 964,
+ /* 150 */ 964, 964, 964, 964, 956, 778, 768, 969, 969, 969,
+ /* 160 */ 969, 969, 969, 969, 969, 969, 969, 944, 942, 969,
+ /* 170 */ 891, 969, 969, 969, 969, 969, 969, 969, 969, 969,
+ /* 180 */ 969, 969, 969, 969, 969, 969, 969, 969, 969, 969,
+ /* 190 */ 969, 969, 969, 969, 969, 969, 969, 969, 969, 969,
+ /* 200 */ 969, 969, 969, 969, 653, 969, 911, 774, 774, 774,
+ /* 210 */ 776, 754, 766, 655, 812, 791, 791, 923, 812, 923,
+ /* 220 */ 710, 733, 707, 802, 791, 874, 802, 802, 775, 766,
+ /* 230 */ 969, 949, 782, 782, 941, 941, 782, 821, 743, 812,
+ /* 240 */ 750, 750, 750, 750, 782, 670, 812, 821, 743, 743,
+ /* 250 */ 812, 782, 670, 917, 915, 782, 782, 670, 782, 670,
+ /* 260 */ 782, 670, 884, 741, 741, 741, 725, 884, 741, 710,
+ /* 270 */ 741, 725, 741, 741, 795, 790, 795, 790, 795, 790,
+ /* 280 */ 782, 782, 969, 884, 888, 888, 884, 807, 796, 805,
+ /* 290 */ 803, 812, 676, 728, 663, 663, 652, 652, 652, 652,
+ /* 300 */ 961, 961, 956, 712, 712, 695, 969, 969, 969, 969,
+ /* 310 */ 969, 969, 687, 969, 893, 969, 969, 969, 969, 969,
+ /* 320 */ 969, 969, 969, 969, 969, 969, 969, 969, 969, 969,
+ /* 330 */ 969, 828, 969, 648, 951, 969, 969, 948, 969, 969,
+ /* 340 */ 969, 969, 969, 969, 969, 969, 969, 969, 969, 969,
+ /* 350 */ 969, 969, 969, 969, 969, 969, 921, 969, 969, 969,
+ /* 360 */ 969, 969, 969, 914, 913, 969, 969, 969, 969, 969,
+ /* 370 */ 969, 969, 969, 969, 969, 969, 969, 969, 969, 969,
+ /* 380 */ 969, 969, 969, 969, 969, 969, 969, 757, 969, 969,
+ /* 390 */ 969, 761, 969, 969, 969, 969, 969, 969, 804, 969,
+ /* 400 */ 797, 969, 877, 969, 969, 969, 969, 969, 969, 969,
+ /* 410 */ 969, 969, 969, 966, 969, 969, 969, 965, 969, 969,
+ /* 420 */ 969, 969, 969, 830, 969, 829, 833, 969, 661, 969,
+ /* 430 */ 644, 649, 960, 963, 962, 959, 958, 957, 952, 950,
+ /* 440 */ 947, 946, 945, 943, 940, 936, 897, 895, 902, 901,
+ /* 450 */ 900, 899, 898, 896, 894, 892, 818, 817, 814, 811,
+ /* 460 */ 753, 935, 890, 752, 749, 748, 669, 953, 920, 929,
+ /* 470 */ 928, 927, 822, 926, 925, 924, 922, 919, 906, 820,
+ /* 480 */ 819, 744, 882, 881, 672, 910, 909, 908, 912, 916,
+ /* 490 */ 907, 784, 751, 671, 668, 675, 679, 731, 732, 740,
+ /* 500 */ 738, 737, 736, 735, 734, 730, 681, 686, 724, 709,
+ /* 510 */ 708, 717, 716, 722, 721, 720, 719, 718, 715, 714,
+ /* 520 */ 713, 706, 705, 711, 704, 727, 726, 723, 703, 747,
+ /* 530 */ 746, 745, 742, 702, 701, 700, 833, 699, 698, 838,
+ /* 540 */ 837, 866, 826, 755, 759, 758, 762, 763, 771, 770,
+ /* 550 */ 769, 780, 781, 793, 792, 824, 823, 794, 779, 773,
+ /* 560 */ 772, 788, 787, 786, 785, 777, 767, 799, 798, 868,
+ /* 570 */ 783, 867, 865, 934, 933, 932, 931, 930, 870, 967,
+ /* 580 */ 968, 887, 889, 886, 801, 800, 885, 869, 839, 836,
+ /* 590 */ 690, 691, 905, 904, 903, 693, 692, 689, 688, 863,
+ /* 600 */ 860, 852, 864, 861, 853, 849, 848, 834, 832, 831,
+ /* 610 */ 827, 835, 760, 756, 825, 765, 764, 697, 696, 694,
+ /* 620 */ 678, 677, 674, 667, 665, 664, 666, 662, 660, 659,
+ /* 630 */ 658, 657, 656, 684, 683, 682, 654, 651, 650, 646,
+ /* 640 */ 645, 643,
};
-/********** End of lemon-generated parsing tables *****************************/
-/* The next table maps tokens (terminal symbols) into fallback tokens.
-** If a construct like the following:
+/* The next table maps tokens into fallback tokens. If a construct
+** like the following:
**
** %fallback ID X Y Z.
**
@@ -131540,109 +124003,79 @@ static const YYACTIONTYPE yy_default[] = {
** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
** but it does not parse, the type of the token is changed to ID and
** the parse is retried before an error is thrown.
-**
-** This feature can be used, for example, to cause some keywords in a language
-** to revert to identifiers if they keyword does not apply in the context where
-** it appears.
*/
#ifdef YYFALLBACK
static const YYCODETYPE yyFallback[] = {
0, /* $ => nothing */
0, /* SEMI => nothing */
- 55, /* EXPLAIN => ID */
- 55, /* QUERY => ID */
- 55, /* PLAN => ID */
- 55, /* BEGIN => ID */
+ 27, /* EXPLAIN => ID */
+ 27, /* QUERY => ID */
+ 27, /* PLAN => ID */
+ 27, /* BEGIN => ID */
0, /* TRANSACTION => nothing */
- 55, /* DEFERRED => ID */
- 55, /* IMMEDIATE => ID */
- 55, /* EXCLUSIVE => ID */
+ 27, /* DEFERRED => ID */
+ 27, /* IMMEDIATE => ID */
+ 27, /* EXCLUSIVE => ID */
0, /* COMMIT => nothing */
- 55, /* END => ID */
- 55, /* ROLLBACK => ID */
- 55, /* SAVEPOINT => ID */
- 55, /* RELEASE => ID */
+ 27, /* END => ID */
+ 27, /* ROLLBACK => ID */
+ 27, /* SAVEPOINT => ID */
+ 27, /* RELEASE => ID */
0, /* TO => nothing */
0, /* TABLE => nothing */
0, /* CREATE => nothing */
- 55, /* IF => ID */
+ 27, /* IF => ID */
0, /* NOT => nothing */
0, /* EXISTS => nothing */
- 55, /* TEMP => ID */
+ 27, /* TEMP => ID */
0, /* LP => nothing */
0, /* RP => nothing */
0, /* AS => nothing */
- 55, /* WITHOUT => ID */
+ 27, /* WITHOUT => ID */
0, /* COMMA => nothing */
- 0, /* OR => nothing */
- 0, /* AND => nothing */
- 0, /* IS => nothing */
- 55, /* MATCH => ID */
- 55, /* LIKE_KW => ID */
- 0, /* BETWEEN => nothing */
- 0, /* IN => nothing */
- 0, /* ISNULL => nothing */
- 0, /* NOTNULL => nothing */
- 0, /* NE => nothing */
- 0, /* EQ => nothing */
- 0, /* GT => nothing */
- 0, /* LE => nothing */
- 0, /* LT => nothing */
- 0, /* GE => nothing */
- 0, /* ESCAPE => nothing */
- 0, /* BITAND => nothing */
- 0, /* BITOR => nothing */
- 0, /* LSHIFT => nothing */
- 0, /* RSHIFT => nothing */
- 0, /* PLUS => nothing */
- 0, /* MINUS => nothing */
- 0, /* STAR => nothing */
- 0, /* SLASH => nothing */
- 0, /* REM => nothing */
- 0, /* CONCAT => nothing */
- 0, /* COLLATE => nothing */
- 0, /* BITNOT => nothing */
0, /* ID => nothing */
0, /* INDEXED => nothing */
- 55, /* ABORT => ID */
- 55, /* ACTION => ID */
- 55, /* AFTER => ID */
- 55, /* ANALYZE => ID */
- 55, /* ASC => ID */
- 55, /* ATTACH => ID */
- 55, /* BEFORE => ID */
- 55, /* BY => ID */
- 55, /* CASCADE => ID */
- 55, /* CAST => ID */
- 55, /* COLUMNKW => ID */
- 55, /* CONFLICT => ID */
- 55, /* DATABASE => ID */
- 55, /* DESC => ID */
- 55, /* DETACH => ID */
- 55, /* EACH => ID */
- 55, /* FAIL => ID */
- 55, /* FOR => ID */
- 55, /* IGNORE => ID */
- 55, /* INITIALLY => ID */
- 55, /* INSTEAD => ID */
- 55, /* NO => ID */
- 55, /* KEY => ID */
- 55, /* OF => ID */
- 55, /* OFFSET => ID */
- 55, /* PRAGMA => ID */
- 55, /* RAISE => ID */
- 55, /* RECURSIVE => ID */
- 55, /* REPLACE => ID */
- 55, /* RESTRICT => ID */
- 55, /* ROW => ID */
- 55, /* TRIGGER => ID */
- 55, /* VACUUM => ID */
- 55, /* VIEW => ID */
- 55, /* VIRTUAL => ID */
- 55, /* WITH => ID */
- 55, /* REINDEX => ID */
- 55, /* RENAME => ID */
- 55, /* CTIME_KW => ID */
+ 27, /* ABORT => ID */
+ 27, /* ACTION => ID */
+ 27, /* AFTER => ID */
+ 27, /* ANALYZE => ID */
+ 27, /* ASC => ID */
+ 27, /* ATTACH => ID */
+ 27, /* BEFORE => ID */
+ 27, /* BY => ID */
+ 27, /* CASCADE => ID */
+ 27, /* CAST => ID */
+ 27, /* COLUMNKW => ID */
+ 27, /* CONFLICT => ID */
+ 27, /* DATABASE => ID */
+ 27, /* DESC => ID */
+ 27, /* DETACH => ID */
+ 27, /* EACH => ID */
+ 27, /* FAIL => ID */
+ 27, /* FOR => ID */
+ 27, /* IGNORE => ID */
+ 27, /* INITIALLY => ID */
+ 27, /* INSTEAD => ID */
+ 27, /* LIKE_KW => ID */
+ 27, /* MATCH => ID */
+ 27, /* NO => ID */
+ 27, /* KEY => ID */
+ 27, /* OF => ID */
+ 27, /* OFFSET => ID */
+ 27, /* PRAGMA => ID */
+ 27, /* RAISE => ID */
+ 27, /* RECURSIVE => ID */
+ 27, /* REPLACE => ID */
+ 27, /* RESTRICT => ID */
+ 27, /* ROW => ID */
+ 27, /* TRIGGER => ID */
+ 27, /* VACUUM => ID */
+ 27, /* VIEW => ID */
+ 27, /* VIRTUAL => ID */
+ 27, /* WITH => ID */
+ 27, /* REINDEX => ID */
+ 27, /* RENAME => ID */
+ 27, /* CTIME_KW => ID */
};
#endif /* YYFALLBACK */
@@ -131657,13 +124090,9 @@ static const YYCODETYPE yyFallback[] = {
** + The semantic value stored at this level of the stack. This is
** the information used by the action routines in the grammar.
** It is sometimes called the "minor" token.
-**
-** After the "shift" half of a SHIFTREDUCE action, the stateno field
-** actually contains the reduce action for the second half of the
-** SHIFTREDUCE.
*/
struct yyStackEntry {
- YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */
+ YYACTIONTYPE stateno; /* The state-number */
YYCODETYPE major; /* The major token value. This is the code
** number for the token at this stack level */
YYMINORTYPE minor; /* The user-supplied minor token value. This
@@ -131678,9 +124107,7 @@ struct yyParser {
#ifdef YYTRACKMAXSTACKDEPTH
int yyidxMax; /* Maximum value of yyidx */
#endif
-#ifndef YYNOERRORRECOVERY
int yyerrcnt; /* Shifts left before out of the error */
-#endif
sqlite3ParserARG_SDECL /* A place to hold %extra_argument */
#if YYSTACKDEPTH<=0
int yystksz; /* Current side of the stack */
@@ -131733,25 +124160,25 @@ static const char *const yyTokenName[] = {
"ROLLBACK", "SAVEPOINT", "RELEASE", "TO",
"TABLE", "CREATE", "IF", "NOT",
"EXISTS", "TEMP", "LP", "RP",
- "AS", "WITHOUT", "COMMA", "OR",
- "AND", "IS", "MATCH", "LIKE_KW",
- "BETWEEN", "IN", "ISNULL", "NOTNULL",
- "NE", "EQ", "GT", "LE",
- "LT", "GE", "ESCAPE", "BITAND",
- "BITOR", "LSHIFT", "RSHIFT", "PLUS",
- "MINUS", "STAR", "SLASH", "REM",
- "CONCAT", "COLLATE", "BITNOT", "ID",
+ "AS", "WITHOUT", "COMMA", "ID",
"INDEXED", "ABORT", "ACTION", "AFTER",
"ANALYZE", "ASC", "ATTACH", "BEFORE",
"BY", "CASCADE", "CAST", "COLUMNKW",
"CONFLICT", "DATABASE", "DESC", "DETACH",
"EACH", "FAIL", "FOR", "IGNORE",
- "INITIALLY", "INSTEAD", "NO", "KEY",
- "OF", "OFFSET", "PRAGMA", "RAISE",
- "RECURSIVE", "REPLACE", "RESTRICT", "ROW",
- "TRIGGER", "VACUUM", "VIEW", "VIRTUAL",
- "WITH", "REINDEX", "RENAME", "CTIME_KW",
- "ANY", "STRING", "JOIN_KW", "CONSTRAINT",
+ "INITIALLY", "INSTEAD", "LIKE_KW", "MATCH",
+ "NO", "KEY", "OF", "OFFSET",
+ "PRAGMA", "RAISE", "RECURSIVE", "REPLACE",
+ "RESTRICT", "ROW", "TRIGGER", "VACUUM",
+ "VIEW", "VIRTUAL", "WITH", "REINDEX",
+ "RENAME", "CTIME_KW", "ANY", "OR",
+ "AND", "IS", "BETWEEN", "IN",
+ "ISNULL", "NOTNULL", "NE", "EQ",
+ "GT", "LE", "LT", "GE",
+ "ESCAPE", "BITAND", "BITOR", "LSHIFT",
+ "RSHIFT", "PLUS", "MINUS", "STAR",
+ "SLASH", "REM", "CONCAT", "COLLATE",
+ "BITNOT", "STRING", "JOIN_KW", "CONSTRAINT",
"DEFAULT", "NULL", "PRIMARY", "UNIQUE",
"CHECK", "REFERENCES", "AUTOINCR", "ON",
"INSERT", "DELETE", "UPDATE", "SET",
@@ -131768,28 +124195,29 @@ static const char *const yyTokenName[] = {
"nm", "savepoint_opt", "create_table", "create_table_args",
"createkw", "temp", "ifnotexists", "dbnm",
"columnlist", "conslist_opt", "table_options", "select",
- "columnname", "carglist", "typetoken", "typename",
- "signed", "plus_num", "minus_num", "ccons",
- "term", "expr", "onconf", "sortorder",
- "autoinc", "eidlist_opt", "refargs", "defer_subclause",
- "refarg", "refact", "init_deferred_pred_opt", "conslist",
- "tconscomma", "tcons", "sortlist", "eidlist",
- "defer_subclause_opt", "orconf", "resolvetype", "raisetype",
- "ifexists", "fullname", "selectnowith", "oneselect",
- "with", "multiselect_op", "distinct", "selcollist",
- "from", "where_opt", "groupby_opt", "having_opt",
- "orderby_opt", "limit_opt", "values", "nexprlist",
- "exprlist", "sclp", "as", "seltablist",
- "stl_prefix", "joinop", "indexed_opt", "on_opt",
- "using_opt", "idlist", "setlist", "insert_cmd",
- "idlist_opt", "likeop", "between_op", "in_op",
- "case_operand", "case_exprlist", "case_else", "uniqueflag",
- "collate", "nmnum", "trigger_decl", "trigger_cmd_list",
- "trigger_time", "trigger_event", "foreach_clause", "when_clause",
- "trigger_cmd", "trnm", "tridxby", "database_kw_opt",
- "key_opt", "add_column_fullname", "kwcolumn_opt", "create_vtab",
- "vtabarglist", "vtabarg", "vtabargtoken", "lp",
- "anylist", "wqlist",
+ "column", "columnid", "type", "carglist",
+ "typetoken", "typename", "signed", "plus_num",
+ "minus_num", "ccons", "term", "expr",
+ "onconf", "sortorder", "autoinc", "idxlist_opt",
+ "refargs", "defer_subclause", "refarg", "refact",
+ "init_deferred_pred_opt", "conslist", "tconscomma", "tcons",
+ "idxlist", "defer_subclause_opt", "orconf", "resolvetype",
+ "raisetype", "ifexists", "fullname", "selectnowith",
+ "oneselect", "with", "multiselect_op", "distinct",
+ "selcollist", "from", "where_opt", "groupby_opt",
+ "having_opt", "orderby_opt", "limit_opt", "values",
+ "nexprlist", "exprlist", "sclp", "as",
+ "seltablist", "stl_prefix", "joinop", "indexed_opt",
+ "on_opt", "using_opt", "joinop2", "idlist",
+ "sortlist", "setlist", "insert_cmd", "inscollist_opt",
+ "likeop", "between_op", "in_op", "case_operand",
+ "case_exprlist", "case_else", "uniqueflag", "collate",
+ "nmnum", "trigger_decl", "trigger_cmd_list", "trigger_time",
+ "trigger_event", "foreach_clause", "when_clause", "trigger_cmd",
+ "trnm", "tridxby", "database_kw_opt", "key_opt",
+ "add_column_fullname", "kwcolumn_opt", "create_vtab", "vtabarglist",
+ "vtabarg", "vtabargtoken", "lp", "anylist",
+ "wqlist",
};
#endif /* NDEBUG */
@@ -131797,332 +124225,333 @@ static const char *const yyTokenName[] = {
/* For tracing reduce actions, the names of all rules are required.
*/
static const char *const yyRuleName[] = {
- /* 0 */ "explain ::= EXPLAIN",
- /* 1 */ "explain ::= EXPLAIN QUERY PLAN",
- /* 2 */ "cmdx ::= cmd",
- /* 3 */ "cmd ::= BEGIN transtype trans_opt",
- /* 4 */ "transtype ::=",
- /* 5 */ "transtype ::= DEFERRED",
- /* 6 */ "transtype ::= IMMEDIATE",
- /* 7 */ "transtype ::= EXCLUSIVE",
- /* 8 */ "cmd ::= COMMIT trans_opt",
- /* 9 */ "cmd ::= END trans_opt",
- /* 10 */ "cmd ::= ROLLBACK trans_opt",
- /* 11 */ "cmd ::= SAVEPOINT nm",
- /* 12 */ "cmd ::= RELEASE savepoint_opt nm",
- /* 13 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm",
- /* 14 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm",
- /* 15 */ "createkw ::= CREATE",
- /* 16 */ "ifnotexists ::=",
- /* 17 */ "ifnotexists ::= IF NOT EXISTS",
- /* 18 */ "temp ::= TEMP",
- /* 19 */ "temp ::=",
- /* 20 */ "create_table_args ::= LP columnlist conslist_opt RP table_options",
- /* 21 */ "create_table_args ::= AS select",
- /* 22 */ "table_options ::=",
- /* 23 */ "table_options ::= WITHOUT nm",
- /* 24 */ "columnname ::= nm typetoken",
- /* 25 */ "typetoken ::=",
- /* 26 */ "typetoken ::= typename LP signed RP",
- /* 27 */ "typetoken ::= typename LP signed COMMA signed RP",
- /* 28 */ "typename ::= typename ID|STRING",
- /* 29 */ "ccons ::= CONSTRAINT nm",
- /* 30 */ "ccons ::= DEFAULT term",
- /* 31 */ "ccons ::= DEFAULT LP expr RP",
- /* 32 */ "ccons ::= DEFAULT PLUS term",
- /* 33 */ "ccons ::= DEFAULT MINUS term",
- /* 34 */ "ccons ::= DEFAULT ID|INDEXED",
- /* 35 */ "ccons ::= NOT NULL onconf",
- /* 36 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
- /* 37 */ "ccons ::= UNIQUE onconf",
- /* 38 */ "ccons ::= CHECK LP expr RP",
- /* 39 */ "ccons ::= REFERENCES nm eidlist_opt refargs",
- /* 40 */ "ccons ::= defer_subclause",
- /* 41 */ "ccons ::= COLLATE ID|STRING",
- /* 42 */ "autoinc ::=",
- /* 43 */ "autoinc ::= AUTOINCR",
- /* 44 */ "refargs ::=",
- /* 45 */ "refargs ::= refargs refarg",
- /* 46 */ "refarg ::= MATCH nm",
- /* 47 */ "refarg ::= ON INSERT refact",
- /* 48 */ "refarg ::= ON DELETE refact",
- /* 49 */ "refarg ::= ON UPDATE refact",
- /* 50 */ "refact ::= SET NULL",
- /* 51 */ "refact ::= SET DEFAULT",
- /* 52 */ "refact ::= CASCADE",
- /* 53 */ "refact ::= RESTRICT",
- /* 54 */ "refact ::= NO ACTION",
- /* 55 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
- /* 56 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
- /* 57 */ "init_deferred_pred_opt ::=",
- /* 58 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
- /* 59 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
- /* 60 */ "conslist_opt ::=",
- /* 61 */ "tconscomma ::= COMMA",
- /* 62 */ "tcons ::= CONSTRAINT nm",
- /* 63 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf",
- /* 64 */ "tcons ::= UNIQUE LP sortlist RP onconf",
- /* 65 */ "tcons ::= CHECK LP expr RP onconf",
- /* 66 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt",
- /* 67 */ "defer_subclause_opt ::=",
- /* 68 */ "onconf ::=",
- /* 69 */ "onconf ::= ON CONFLICT resolvetype",
- /* 70 */ "orconf ::=",
- /* 71 */ "orconf ::= OR resolvetype",
- /* 72 */ "resolvetype ::= IGNORE",
- /* 73 */ "resolvetype ::= REPLACE",
- /* 74 */ "cmd ::= DROP TABLE ifexists fullname",
- /* 75 */ "ifexists ::= IF EXISTS",
- /* 76 */ "ifexists ::=",
- /* 77 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select",
- /* 78 */ "cmd ::= DROP VIEW ifexists fullname",
- /* 79 */ "cmd ::= select",
- /* 80 */ "select ::= with selectnowith",
- /* 81 */ "selectnowith ::= selectnowith multiselect_op oneselect",
- /* 82 */ "multiselect_op ::= UNION",
- /* 83 */ "multiselect_op ::= UNION ALL",
- /* 84 */ "multiselect_op ::= EXCEPT|INTERSECT",
- /* 85 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
- /* 86 */ "values ::= VALUES LP nexprlist RP",
- /* 87 */ "values ::= values COMMA LP exprlist RP",
- /* 88 */ "distinct ::= DISTINCT",
- /* 89 */ "distinct ::= ALL",
- /* 90 */ "distinct ::=",
- /* 91 */ "sclp ::=",
- /* 92 */ "selcollist ::= sclp expr as",
- /* 93 */ "selcollist ::= sclp STAR",
- /* 94 */ "selcollist ::= sclp nm DOT STAR",
- /* 95 */ "as ::= AS nm",
- /* 96 */ "as ::=",
- /* 97 */ "from ::=",
- /* 98 */ "from ::= FROM seltablist",
- /* 99 */ "stl_prefix ::= seltablist joinop",
- /* 100 */ "stl_prefix ::=",
- /* 101 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt",
- /* 102 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt",
- /* 103 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt",
- /* 104 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt",
- /* 105 */ "dbnm ::=",
- /* 106 */ "dbnm ::= DOT nm",
- /* 107 */ "fullname ::= nm dbnm",
- /* 108 */ "joinop ::= COMMA|JOIN",
- /* 109 */ "joinop ::= JOIN_KW JOIN",
- /* 110 */ "joinop ::= JOIN_KW nm JOIN",
- /* 111 */ "joinop ::= JOIN_KW nm nm JOIN",
- /* 112 */ "on_opt ::= ON expr",
- /* 113 */ "on_opt ::=",
- /* 114 */ "indexed_opt ::=",
- /* 115 */ "indexed_opt ::= INDEXED BY nm",
- /* 116 */ "indexed_opt ::= NOT INDEXED",
- /* 117 */ "using_opt ::= USING LP idlist RP",
- /* 118 */ "using_opt ::=",
- /* 119 */ "orderby_opt ::=",
- /* 120 */ "orderby_opt ::= ORDER BY sortlist",
- /* 121 */ "sortlist ::= sortlist COMMA expr sortorder",
- /* 122 */ "sortlist ::= expr sortorder",
- /* 123 */ "sortorder ::= ASC",
- /* 124 */ "sortorder ::= DESC",
- /* 125 */ "sortorder ::=",
- /* 126 */ "groupby_opt ::=",
- /* 127 */ "groupby_opt ::= GROUP BY nexprlist",
- /* 128 */ "having_opt ::=",
- /* 129 */ "having_opt ::= HAVING expr",
- /* 130 */ "limit_opt ::=",
- /* 131 */ "limit_opt ::= LIMIT expr",
- /* 132 */ "limit_opt ::= LIMIT expr OFFSET expr",
- /* 133 */ "limit_opt ::= LIMIT expr COMMA expr",
- /* 134 */ "cmd ::= with DELETE FROM fullname indexed_opt where_opt",
- /* 135 */ "where_opt ::=",
- /* 136 */ "where_opt ::= WHERE expr",
- /* 137 */ "cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt",
- /* 138 */ "setlist ::= setlist COMMA nm EQ expr",
- /* 139 */ "setlist ::= nm EQ expr",
- /* 140 */ "cmd ::= with insert_cmd INTO fullname idlist_opt select",
- /* 141 */ "cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES",
- /* 142 */ "insert_cmd ::= INSERT orconf",
- /* 143 */ "insert_cmd ::= REPLACE",
- /* 144 */ "idlist_opt ::=",
- /* 145 */ "idlist_opt ::= LP idlist RP",
- /* 146 */ "idlist ::= idlist COMMA nm",
- /* 147 */ "idlist ::= nm",
- /* 148 */ "expr ::= LP expr RP",
- /* 149 */ "term ::= NULL",
- /* 150 */ "expr ::= ID|INDEXED",
- /* 151 */ "expr ::= JOIN_KW",
- /* 152 */ "expr ::= nm DOT nm",
- /* 153 */ "expr ::= nm DOT nm DOT nm",
- /* 154 */ "term ::= INTEGER|FLOAT|BLOB",
- /* 155 */ "term ::= STRING",
- /* 156 */ "expr ::= VARIABLE",
- /* 157 */ "expr ::= expr COLLATE ID|STRING",
- /* 158 */ "expr ::= CAST LP expr AS typetoken RP",
- /* 159 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
- /* 160 */ "expr ::= ID|INDEXED LP STAR RP",
- /* 161 */ "term ::= CTIME_KW",
- /* 162 */ "expr ::= expr AND expr",
- /* 163 */ "expr ::= expr OR expr",
- /* 164 */ "expr ::= expr LT|GT|GE|LE expr",
- /* 165 */ "expr ::= expr EQ|NE expr",
- /* 166 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
- /* 167 */ "expr ::= expr PLUS|MINUS expr",
- /* 168 */ "expr ::= expr STAR|SLASH|REM expr",
- /* 169 */ "expr ::= expr CONCAT expr",
- /* 170 */ "likeop ::= LIKE_KW|MATCH",
- /* 171 */ "likeop ::= NOT LIKE_KW|MATCH",
- /* 172 */ "expr ::= expr likeop expr",
- /* 173 */ "expr ::= expr likeop expr ESCAPE expr",
- /* 174 */ "expr ::= expr ISNULL|NOTNULL",
- /* 175 */ "expr ::= expr NOT NULL",
- /* 176 */ "expr ::= expr IS expr",
- /* 177 */ "expr ::= expr IS NOT expr",
- /* 178 */ "expr ::= NOT expr",
- /* 179 */ "expr ::= BITNOT expr",
- /* 180 */ "expr ::= MINUS expr",
- /* 181 */ "expr ::= PLUS expr",
- /* 182 */ "between_op ::= BETWEEN",
- /* 183 */ "between_op ::= NOT BETWEEN",
- /* 184 */ "expr ::= expr between_op expr AND expr",
- /* 185 */ "in_op ::= IN",
- /* 186 */ "in_op ::= NOT IN",
- /* 187 */ "expr ::= expr in_op LP exprlist RP",
- /* 188 */ "expr ::= LP select RP",
- /* 189 */ "expr ::= expr in_op LP select RP",
- /* 190 */ "expr ::= expr in_op nm dbnm",
- /* 191 */ "expr ::= EXISTS LP select RP",
- /* 192 */ "expr ::= CASE case_operand case_exprlist case_else END",
- /* 193 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
- /* 194 */ "case_exprlist ::= WHEN expr THEN expr",
- /* 195 */ "case_else ::= ELSE expr",
- /* 196 */ "case_else ::=",
- /* 197 */ "case_operand ::= expr",
- /* 198 */ "case_operand ::=",
- /* 199 */ "exprlist ::=",
- /* 200 */ "nexprlist ::= nexprlist COMMA expr",
- /* 201 */ "nexprlist ::= expr",
- /* 202 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
- /* 203 */ "uniqueflag ::= UNIQUE",
- /* 204 */ "uniqueflag ::=",
- /* 205 */ "eidlist_opt ::=",
- /* 206 */ "eidlist_opt ::= LP eidlist RP",
- /* 207 */ "eidlist ::= eidlist COMMA nm collate sortorder",
- /* 208 */ "eidlist ::= nm collate sortorder",
- /* 209 */ "collate ::=",
- /* 210 */ "collate ::= COLLATE ID|STRING",
- /* 211 */ "cmd ::= DROP INDEX ifexists fullname",
- /* 212 */ "cmd ::= VACUUM",
- /* 213 */ "cmd ::= VACUUM nm",
- /* 214 */ "cmd ::= PRAGMA nm dbnm",
- /* 215 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
- /* 216 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
- /* 217 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
- /* 218 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
- /* 219 */ "plus_num ::= PLUS INTEGER|FLOAT",
- /* 220 */ "minus_num ::= MINUS INTEGER|FLOAT",
- /* 221 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
- /* 222 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
- /* 223 */ "trigger_time ::= BEFORE",
- /* 224 */ "trigger_time ::= AFTER",
- /* 225 */ "trigger_time ::= INSTEAD OF",
- /* 226 */ "trigger_time ::=",
- /* 227 */ "trigger_event ::= DELETE|INSERT",
- /* 228 */ "trigger_event ::= UPDATE",
- /* 229 */ "trigger_event ::= UPDATE OF idlist",
- /* 230 */ "when_clause ::=",
- /* 231 */ "when_clause ::= WHEN expr",
- /* 232 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
- /* 233 */ "trigger_cmd_list ::= trigger_cmd SEMI",
- /* 234 */ "trnm ::= nm DOT nm",
- /* 235 */ "tridxby ::= INDEXED BY nm",
- /* 236 */ "tridxby ::= NOT INDEXED",
- /* 237 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt",
- /* 238 */ "trigger_cmd ::= insert_cmd INTO trnm idlist_opt select",
- /* 239 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt",
- /* 240 */ "trigger_cmd ::= select",
- /* 241 */ "expr ::= RAISE LP IGNORE RP",
- /* 242 */ "expr ::= RAISE LP raisetype COMMA nm RP",
- /* 243 */ "raisetype ::= ROLLBACK",
- /* 244 */ "raisetype ::= ABORT",
- /* 245 */ "raisetype ::= FAIL",
- /* 246 */ "cmd ::= DROP TRIGGER ifexists fullname",
- /* 247 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
- /* 248 */ "cmd ::= DETACH database_kw_opt expr",
- /* 249 */ "key_opt ::=",
- /* 250 */ "key_opt ::= KEY expr",
- /* 251 */ "cmd ::= REINDEX",
- /* 252 */ "cmd ::= REINDEX nm dbnm",
- /* 253 */ "cmd ::= ANALYZE",
- /* 254 */ "cmd ::= ANALYZE nm dbnm",
- /* 255 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
- /* 256 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
- /* 257 */ "add_column_fullname ::= fullname",
- /* 258 */ "cmd ::= create_vtab",
- /* 259 */ "cmd ::= create_vtab LP vtabarglist RP",
- /* 260 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
- /* 261 */ "vtabarg ::=",
- /* 262 */ "vtabargtoken ::= ANY",
- /* 263 */ "vtabargtoken ::= lp anylist RP",
- /* 264 */ "lp ::= LP",
- /* 265 */ "with ::=",
- /* 266 */ "with ::= WITH wqlist",
- /* 267 */ "with ::= WITH RECURSIVE wqlist",
- /* 268 */ "wqlist ::= nm eidlist_opt AS LP select RP",
- /* 269 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP",
- /* 270 */ "input ::= cmdlist",
- /* 271 */ "cmdlist ::= cmdlist ecmd",
- /* 272 */ "cmdlist ::= ecmd",
- /* 273 */ "ecmd ::= SEMI",
- /* 274 */ "ecmd ::= explain cmdx SEMI",
- /* 275 */ "explain ::=",
- /* 276 */ "trans_opt ::=",
- /* 277 */ "trans_opt ::= TRANSACTION",
- /* 278 */ "trans_opt ::= TRANSACTION nm",
- /* 279 */ "savepoint_opt ::= SAVEPOINT",
- /* 280 */ "savepoint_opt ::=",
- /* 281 */ "cmd ::= create_table create_table_args",
- /* 282 */ "columnlist ::= columnlist COMMA columnname carglist",
- /* 283 */ "columnlist ::= columnname carglist",
- /* 284 */ "nm ::= ID|INDEXED",
- /* 285 */ "nm ::= STRING",
- /* 286 */ "nm ::= JOIN_KW",
- /* 287 */ "typetoken ::= typename",
- /* 288 */ "typename ::= ID|STRING",
- /* 289 */ "signed ::= plus_num",
- /* 290 */ "signed ::= minus_num",
- /* 291 */ "carglist ::= carglist ccons",
- /* 292 */ "carglist ::=",
- /* 293 */ "ccons ::= NULL onconf",
- /* 294 */ "conslist_opt ::= COMMA conslist",
- /* 295 */ "conslist ::= conslist tconscomma tcons",
- /* 296 */ "conslist ::= tcons",
- /* 297 */ "tconscomma ::=",
- /* 298 */ "defer_subclause_opt ::= defer_subclause",
- /* 299 */ "resolvetype ::= raisetype",
- /* 300 */ "selectnowith ::= oneselect",
- /* 301 */ "oneselect ::= values",
- /* 302 */ "sclp ::= selcollist COMMA",
- /* 303 */ "as ::= ID|STRING",
- /* 304 */ "expr ::= term",
- /* 305 */ "exprlist ::= nexprlist",
- /* 306 */ "nmnum ::= plus_num",
- /* 307 */ "nmnum ::= nm",
- /* 308 */ "nmnum ::= ON",
- /* 309 */ "nmnum ::= DELETE",
- /* 310 */ "nmnum ::= DEFAULT",
- /* 311 */ "plus_num ::= INTEGER|FLOAT",
- /* 312 */ "foreach_clause ::=",
- /* 313 */ "foreach_clause ::= FOR EACH ROW",
- /* 314 */ "trnm ::= nm",
- /* 315 */ "tridxby ::=",
- /* 316 */ "database_kw_opt ::= DATABASE",
- /* 317 */ "database_kw_opt ::=",
- /* 318 */ "kwcolumn_opt ::=",
- /* 319 */ "kwcolumn_opt ::= COLUMNKW",
- /* 320 */ "vtabarglist ::= vtabarg",
- /* 321 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
- /* 322 */ "vtabarg ::= vtabarg vtabargtoken",
- /* 323 */ "anylist ::=",
- /* 324 */ "anylist ::= anylist LP anylist RP",
- /* 325 */ "anylist ::= anylist ANY",
+ /* 0 */ "input ::= cmdlist",
+ /* 1 */ "cmdlist ::= cmdlist ecmd",
+ /* 2 */ "cmdlist ::= ecmd",
+ /* 3 */ "ecmd ::= SEMI",
+ /* 4 */ "ecmd ::= explain cmdx SEMI",
+ /* 5 */ "explain ::=",
+ /* 6 */ "explain ::= EXPLAIN",
+ /* 7 */ "explain ::= EXPLAIN QUERY PLAN",
+ /* 8 */ "cmdx ::= cmd",
+ /* 9 */ "cmd ::= BEGIN transtype trans_opt",
+ /* 10 */ "trans_opt ::=",
+ /* 11 */ "trans_opt ::= TRANSACTION",
+ /* 12 */ "trans_opt ::= TRANSACTION nm",
+ /* 13 */ "transtype ::=",
+ /* 14 */ "transtype ::= DEFERRED",
+ /* 15 */ "transtype ::= IMMEDIATE",
+ /* 16 */ "transtype ::= EXCLUSIVE",
+ /* 17 */ "cmd ::= COMMIT trans_opt",
+ /* 18 */ "cmd ::= END trans_opt",
+ /* 19 */ "cmd ::= ROLLBACK trans_opt",
+ /* 20 */ "savepoint_opt ::= SAVEPOINT",
+ /* 21 */ "savepoint_opt ::=",
+ /* 22 */ "cmd ::= SAVEPOINT nm",
+ /* 23 */ "cmd ::= RELEASE savepoint_opt nm",
+ /* 24 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm",
+ /* 25 */ "cmd ::= create_table create_table_args",
+ /* 26 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm",
+ /* 27 */ "createkw ::= CREATE",
+ /* 28 */ "ifnotexists ::=",
+ /* 29 */ "ifnotexists ::= IF NOT EXISTS",
+ /* 30 */ "temp ::= TEMP",
+ /* 31 */ "temp ::=",
+ /* 32 */ "create_table_args ::= LP columnlist conslist_opt RP table_options",
+ /* 33 */ "create_table_args ::= AS select",
+ /* 34 */ "table_options ::=",
+ /* 35 */ "table_options ::= WITHOUT nm",
+ /* 36 */ "columnlist ::= columnlist COMMA column",
+ /* 37 */ "columnlist ::= column",
+ /* 38 */ "column ::= columnid type carglist",
+ /* 39 */ "columnid ::= nm",
+ /* 40 */ "nm ::= ID|INDEXED",
+ /* 41 */ "nm ::= STRING",
+ /* 42 */ "nm ::= JOIN_KW",
+ /* 43 */ "type ::=",
+ /* 44 */ "type ::= typetoken",
+ /* 45 */ "typetoken ::= typename",
+ /* 46 */ "typetoken ::= typename LP signed RP",
+ /* 47 */ "typetoken ::= typename LP signed COMMA signed RP",
+ /* 48 */ "typename ::= ID|STRING",
+ /* 49 */ "typename ::= typename ID|STRING",
+ /* 50 */ "signed ::= plus_num",
+ /* 51 */ "signed ::= minus_num",
+ /* 52 */ "carglist ::= carglist ccons",
+ /* 53 */ "carglist ::=",
+ /* 54 */ "ccons ::= CONSTRAINT nm",
+ /* 55 */ "ccons ::= DEFAULT term",
+ /* 56 */ "ccons ::= DEFAULT LP expr RP",
+ /* 57 */ "ccons ::= DEFAULT PLUS term",
+ /* 58 */ "ccons ::= DEFAULT MINUS term",
+ /* 59 */ "ccons ::= DEFAULT ID|INDEXED",
+ /* 60 */ "ccons ::= NULL onconf",
+ /* 61 */ "ccons ::= NOT NULL onconf",
+ /* 62 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
+ /* 63 */ "ccons ::= UNIQUE onconf",
+ /* 64 */ "ccons ::= CHECK LP expr RP",
+ /* 65 */ "ccons ::= REFERENCES nm idxlist_opt refargs",
+ /* 66 */ "ccons ::= defer_subclause",
+ /* 67 */ "ccons ::= COLLATE ID|STRING",
+ /* 68 */ "autoinc ::=",
+ /* 69 */ "autoinc ::= AUTOINCR",
+ /* 70 */ "refargs ::=",
+ /* 71 */ "refargs ::= refargs refarg",
+ /* 72 */ "refarg ::= MATCH nm",
+ /* 73 */ "refarg ::= ON INSERT refact",
+ /* 74 */ "refarg ::= ON DELETE refact",
+ /* 75 */ "refarg ::= ON UPDATE refact",
+ /* 76 */ "refact ::= SET NULL",
+ /* 77 */ "refact ::= SET DEFAULT",
+ /* 78 */ "refact ::= CASCADE",
+ /* 79 */ "refact ::= RESTRICT",
+ /* 80 */ "refact ::= NO ACTION",
+ /* 81 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
+ /* 82 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
+ /* 83 */ "init_deferred_pred_opt ::=",
+ /* 84 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
+ /* 85 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
+ /* 86 */ "conslist_opt ::=",
+ /* 87 */ "conslist_opt ::= COMMA conslist",
+ /* 88 */ "conslist ::= conslist tconscomma tcons",
+ /* 89 */ "conslist ::= tcons",
+ /* 90 */ "tconscomma ::= COMMA",
+ /* 91 */ "tconscomma ::=",
+ /* 92 */ "tcons ::= CONSTRAINT nm",
+ /* 93 */ "tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf",
+ /* 94 */ "tcons ::= UNIQUE LP idxlist RP onconf",
+ /* 95 */ "tcons ::= CHECK LP expr RP onconf",
+ /* 96 */ "tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt",
+ /* 97 */ "defer_subclause_opt ::=",
+ /* 98 */ "defer_subclause_opt ::= defer_subclause",
+ /* 99 */ "onconf ::=",
+ /* 100 */ "onconf ::= ON CONFLICT resolvetype",
+ /* 101 */ "orconf ::=",
+ /* 102 */ "orconf ::= OR resolvetype",
+ /* 103 */ "resolvetype ::= raisetype",
+ /* 104 */ "resolvetype ::= IGNORE",
+ /* 105 */ "resolvetype ::= REPLACE",
+ /* 106 */ "cmd ::= DROP TABLE ifexists fullname",
+ /* 107 */ "ifexists ::= IF EXISTS",
+ /* 108 */ "ifexists ::=",
+ /* 109 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm AS select",
+ /* 110 */ "cmd ::= DROP VIEW ifexists fullname",
+ /* 111 */ "cmd ::= select",
+ /* 112 */ "select ::= with selectnowith",
+ /* 113 */ "selectnowith ::= oneselect",
+ /* 114 */ "selectnowith ::= selectnowith multiselect_op oneselect",
+ /* 115 */ "multiselect_op ::= UNION",
+ /* 116 */ "multiselect_op ::= UNION ALL",
+ /* 117 */ "multiselect_op ::= EXCEPT|INTERSECT",
+ /* 118 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
+ /* 119 */ "oneselect ::= values",
+ /* 120 */ "values ::= VALUES LP nexprlist RP",
+ /* 121 */ "values ::= values COMMA LP exprlist RP",
+ /* 122 */ "distinct ::= DISTINCT",
+ /* 123 */ "distinct ::= ALL",
+ /* 124 */ "distinct ::=",
+ /* 125 */ "sclp ::= selcollist COMMA",
+ /* 126 */ "sclp ::=",
+ /* 127 */ "selcollist ::= sclp expr as",
+ /* 128 */ "selcollist ::= sclp STAR",
+ /* 129 */ "selcollist ::= sclp nm DOT STAR",
+ /* 130 */ "as ::= AS nm",
+ /* 131 */ "as ::= ID|STRING",
+ /* 132 */ "as ::=",
+ /* 133 */ "from ::=",
+ /* 134 */ "from ::= FROM seltablist",
+ /* 135 */ "stl_prefix ::= seltablist joinop",
+ /* 136 */ "stl_prefix ::=",
+ /* 137 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt",
+ /* 138 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt",
+ /* 139 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt",
+ /* 140 */ "dbnm ::=",
+ /* 141 */ "dbnm ::= DOT nm",
+ /* 142 */ "fullname ::= nm dbnm",
+ /* 143 */ "joinop ::= COMMA|JOIN",
+ /* 144 */ "joinop ::= JOIN_KW JOIN",
+ /* 145 */ "joinop ::= JOIN_KW nm JOIN",
+ /* 146 */ "joinop ::= JOIN_KW nm nm JOIN",
+ /* 147 */ "on_opt ::= ON expr",
+ /* 148 */ "on_opt ::=",
+ /* 149 */ "indexed_opt ::=",
+ /* 150 */ "indexed_opt ::= INDEXED BY nm",
+ /* 151 */ "indexed_opt ::= NOT INDEXED",
+ /* 152 */ "using_opt ::= USING LP idlist RP",
+ /* 153 */ "using_opt ::=",
+ /* 154 */ "orderby_opt ::=",
+ /* 155 */ "orderby_opt ::= ORDER BY sortlist",
+ /* 156 */ "sortlist ::= sortlist COMMA expr sortorder",
+ /* 157 */ "sortlist ::= expr sortorder",
+ /* 158 */ "sortorder ::= ASC",
+ /* 159 */ "sortorder ::= DESC",
+ /* 160 */ "sortorder ::=",
+ /* 161 */ "groupby_opt ::=",
+ /* 162 */ "groupby_opt ::= GROUP BY nexprlist",
+ /* 163 */ "having_opt ::=",
+ /* 164 */ "having_opt ::= HAVING expr",
+ /* 165 */ "limit_opt ::=",
+ /* 166 */ "limit_opt ::= LIMIT expr",
+ /* 167 */ "limit_opt ::= LIMIT expr OFFSET expr",
+ /* 168 */ "limit_opt ::= LIMIT expr COMMA expr",
+ /* 169 */ "cmd ::= with DELETE FROM fullname indexed_opt where_opt",
+ /* 170 */ "where_opt ::=",
+ /* 171 */ "where_opt ::= WHERE expr",
+ /* 172 */ "cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt",
+ /* 173 */ "setlist ::= setlist COMMA nm EQ expr",
+ /* 174 */ "setlist ::= nm EQ expr",
+ /* 175 */ "cmd ::= with insert_cmd INTO fullname inscollist_opt select",
+ /* 176 */ "cmd ::= with insert_cmd INTO fullname inscollist_opt DEFAULT VALUES",
+ /* 177 */ "insert_cmd ::= INSERT orconf",
+ /* 178 */ "insert_cmd ::= REPLACE",
+ /* 179 */ "inscollist_opt ::=",
+ /* 180 */ "inscollist_opt ::= LP idlist RP",
+ /* 181 */ "idlist ::= idlist COMMA nm",
+ /* 182 */ "idlist ::= nm",
+ /* 183 */ "expr ::= term",
+ /* 184 */ "expr ::= LP expr RP",
+ /* 185 */ "term ::= NULL",
+ /* 186 */ "expr ::= ID|INDEXED",
+ /* 187 */ "expr ::= JOIN_KW",
+ /* 188 */ "expr ::= nm DOT nm",
+ /* 189 */ "expr ::= nm DOT nm DOT nm",
+ /* 190 */ "term ::= INTEGER|FLOAT|BLOB",
+ /* 191 */ "term ::= STRING",
+ /* 192 */ "expr ::= VARIABLE",
+ /* 193 */ "expr ::= expr COLLATE ID|STRING",
+ /* 194 */ "expr ::= CAST LP expr AS typetoken RP",
+ /* 195 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
+ /* 196 */ "expr ::= ID|INDEXED LP STAR RP",
+ /* 197 */ "term ::= CTIME_KW",
+ /* 198 */ "expr ::= expr AND expr",
+ /* 199 */ "expr ::= expr OR expr",
+ /* 200 */ "expr ::= expr LT|GT|GE|LE expr",
+ /* 201 */ "expr ::= expr EQ|NE expr",
+ /* 202 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
+ /* 203 */ "expr ::= expr PLUS|MINUS expr",
+ /* 204 */ "expr ::= expr STAR|SLASH|REM expr",
+ /* 205 */ "expr ::= expr CONCAT expr",
+ /* 206 */ "likeop ::= LIKE_KW|MATCH",
+ /* 207 */ "likeop ::= NOT LIKE_KW|MATCH",
+ /* 208 */ "expr ::= expr likeop expr",
+ /* 209 */ "expr ::= expr likeop expr ESCAPE expr",
+ /* 210 */ "expr ::= expr ISNULL|NOTNULL",
+ /* 211 */ "expr ::= expr NOT NULL",
+ /* 212 */ "expr ::= expr IS expr",
+ /* 213 */ "expr ::= expr IS NOT expr",
+ /* 214 */ "expr ::= NOT expr",
+ /* 215 */ "expr ::= BITNOT expr",
+ /* 216 */ "expr ::= MINUS expr",
+ /* 217 */ "expr ::= PLUS expr",
+ /* 218 */ "between_op ::= BETWEEN",
+ /* 219 */ "between_op ::= NOT BETWEEN",
+ /* 220 */ "expr ::= expr between_op expr AND expr",
+ /* 221 */ "in_op ::= IN",
+ /* 222 */ "in_op ::= NOT IN",
+ /* 223 */ "expr ::= expr in_op LP exprlist RP",
+ /* 224 */ "expr ::= LP select RP",
+ /* 225 */ "expr ::= expr in_op LP select RP",
+ /* 226 */ "expr ::= expr in_op nm dbnm",
+ /* 227 */ "expr ::= EXISTS LP select RP",
+ /* 228 */ "expr ::= CASE case_operand case_exprlist case_else END",
+ /* 229 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
+ /* 230 */ "case_exprlist ::= WHEN expr THEN expr",
+ /* 231 */ "case_else ::= ELSE expr",
+ /* 232 */ "case_else ::=",
+ /* 233 */ "case_operand ::= expr",
+ /* 234 */ "case_operand ::=",
+ /* 235 */ "exprlist ::= nexprlist",
+ /* 236 */ "exprlist ::=",
+ /* 237 */ "nexprlist ::= nexprlist COMMA expr",
+ /* 238 */ "nexprlist ::= expr",
+ /* 239 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP where_opt",
+ /* 240 */ "uniqueflag ::= UNIQUE",
+ /* 241 */ "uniqueflag ::=",
+ /* 242 */ "idxlist_opt ::=",
+ /* 243 */ "idxlist_opt ::= LP idxlist RP",
+ /* 244 */ "idxlist ::= idxlist COMMA nm collate sortorder",
+ /* 245 */ "idxlist ::= nm collate sortorder",
+ /* 246 */ "collate ::=",
+ /* 247 */ "collate ::= COLLATE ID|STRING",
+ /* 248 */ "cmd ::= DROP INDEX ifexists fullname",
+ /* 249 */ "cmd ::= VACUUM",
+ /* 250 */ "cmd ::= VACUUM nm",
+ /* 251 */ "cmd ::= PRAGMA nm dbnm",
+ /* 252 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
+ /* 253 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
+ /* 254 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
+ /* 255 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
+ /* 256 */ "nmnum ::= plus_num",
+ /* 257 */ "nmnum ::= nm",
+ /* 258 */ "nmnum ::= ON",
+ /* 259 */ "nmnum ::= DELETE",
+ /* 260 */ "nmnum ::= DEFAULT",
+ /* 261 */ "plus_num ::= PLUS INTEGER|FLOAT",
+ /* 262 */ "plus_num ::= INTEGER|FLOAT",
+ /* 263 */ "minus_num ::= MINUS INTEGER|FLOAT",
+ /* 264 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
+ /* 265 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
+ /* 266 */ "trigger_time ::= BEFORE",
+ /* 267 */ "trigger_time ::= AFTER",
+ /* 268 */ "trigger_time ::= INSTEAD OF",
+ /* 269 */ "trigger_time ::=",
+ /* 270 */ "trigger_event ::= DELETE|INSERT",
+ /* 271 */ "trigger_event ::= UPDATE",
+ /* 272 */ "trigger_event ::= UPDATE OF idlist",
+ /* 273 */ "foreach_clause ::=",
+ /* 274 */ "foreach_clause ::= FOR EACH ROW",
+ /* 275 */ "when_clause ::=",
+ /* 276 */ "when_clause ::= WHEN expr",
+ /* 277 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
+ /* 278 */ "trigger_cmd_list ::= trigger_cmd SEMI",
+ /* 279 */ "trnm ::= nm",
+ /* 280 */ "trnm ::= nm DOT nm",
+ /* 281 */ "tridxby ::=",
+ /* 282 */ "tridxby ::= INDEXED BY nm",
+ /* 283 */ "tridxby ::= NOT INDEXED",
+ /* 284 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt",
+ /* 285 */ "trigger_cmd ::= insert_cmd INTO trnm inscollist_opt select",
+ /* 286 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt",
+ /* 287 */ "trigger_cmd ::= select",
+ /* 288 */ "expr ::= RAISE LP IGNORE RP",
+ /* 289 */ "expr ::= RAISE LP raisetype COMMA nm RP",
+ /* 290 */ "raisetype ::= ROLLBACK",
+ /* 291 */ "raisetype ::= ABORT",
+ /* 292 */ "raisetype ::= FAIL",
+ /* 293 */ "cmd ::= DROP TRIGGER ifexists fullname",
+ /* 294 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
+ /* 295 */ "cmd ::= DETACH database_kw_opt expr",
+ /* 296 */ "key_opt ::=",
+ /* 297 */ "key_opt ::= KEY expr",
+ /* 298 */ "database_kw_opt ::= DATABASE",
+ /* 299 */ "database_kw_opt ::=",
+ /* 300 */ "cmd ::= REINDEX",
+ /* 301 */ "cmd ::= REINDEX nm dbnm",
+ /* 302 */ "cmd ::= ANALYZE",
+ /* 303 */ "cmd ::= ANALYZE nm dbnm",
+ /* 304 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
+ /* 305 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column",
+ /* 306 */ "add_column_fullname ::= fullname",
+ /* 307 */ "kwcolumn_opt ::=",
+ /* 308 */ "kwcolumn_opt ::= COLUMNKW",
+ /* 309 */ "cmd ::= create_vtab",
+ /* 310 */ "cmd ::= create_vtab LP vtabarglist RP",
+ /* 311 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
+ /* 312 */ "vtabarglist ::= vtabarg",
+ /* 313 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
+ /* 314 */ "vtabarg ::=",
+ /* 315 */ "vtabarg ::= vtabarg vtabargtoken",
+ /* 316 */ "vtabargtoken ::= ANY",
+ /* 317 */ "vtabargtoken ::= lp anylist RP",
+ /* 318 */ "lp ::= LP",
+ /* 319 */ "anylist ::=",
+ /* 320 */ "anylist ::= anylist LP anylist RP",
+ /* 321 */ "anylist ::= anylist ANY",
+ /* 322 */ "with ::=",
+ /* 323 */ "with ::= WITH wqlist",
+ /* 324 */ "with ::= WITH RECURSIVE wqlist",
+ /* 325 */ "wqlist ::= nm idxlist_opt AS LP select RP",
+ /* 326 */ "wqlist ::= wqlist COMMA nm idxlist_opt AS LP select RP",
};
#endif /* NDEBUG */
@@ -132150,15 +124579,6 @@ static void yyGrowStack(yyParser *p){
}
#endif
-/* Datatype of the argument to the memory allocated passed as the
-** second argument to sqlite3ParserAlloc() below. This can be changed by
-** putting an appropriate #define in the %include section of the input
-** grammar.
-*/
-#ifndef YYMALLOCARGTYPE
-# define YYMALLOCARGTYPE size_t
-#endif
-
/*
** This function allocates a new parser.
** The only argument is a pointer to a function which works like
@@ -132171,9 +124591,9 @@ static void yyGrowStack(yyParser *p){
** A pointer to a parser. This pointer is used in subsequent calls
** to sqlite3Parser and sqlite3ParserFree.
*/
-SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){
+SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(u64)){
yyParser *pParser;
- pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) );
+ pParser = (yyParser*)(*mallocProc)( (u64)sizeof(yyParser) );
if( pParser ){
pParser->yyidx = -1;
#ifdef YYTRACKMAXSTACKDEPTH
@@ -132188,12 +124608,10 @@ SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){
return pParser;
}
-/* The following function deletes the "minor type" or semantic value
-** associated with a symbol. The symbol can be either a terminal
-** or nonterminal. "yymajor" is the symbol code, and "yypminor" is
-** a pointer to the value to be deleted. The code used to do the
-** deletions is derived from the %destructor and/or %token_destructor
-** directives of the input grammar.
+/* The following function deletes the value associated with a
+** symbol. The symbol can be either a terminal or nonterminal.
+** "yymajor" is the symbol code, and "yypminor" is a pointer to
+** the value.
*/
static void yy_destructor(
yyParser *yypParser, /* The parser */
@@ -132209,83 +124627,81 @@ static void yy_destructor(
** being destroyed before it is finished parsing.
**
** Note: during a reduce, the only symbols destroyed are those
- ** which appear on the RHS of the rule, but which are *not* used
+ ** which appear on the RHS of the rule, but which are not used
** inside the C code.
*/
-/********* Begin destructor definitions ***************************************/
case 163: /* select */
- case 194: /* selectnowith */
- case 195: /* oneselect */
- case 206: /* values */
+ case 195: /* selectnowith */
+ case 196: /* oneselect */
+ case 207: /* values */
{
-sqlite3SelectDelete(pParse->db, (yypminor->yy159));
+sqlite3SelectDelete(pParse->db, (yypminor->yy3));
}
break;
- case 172: /* term */
- case 173: /* expr */
+ case 174: /* term */
+ case 175: /* expr */
{
-sqlite3ExprDelete(pParse->db, (yypminor->yy342).pExpr);
+sqlite3ExprDelete(pParse->db, (yypminor->yy346).pExpr);
}
break;
- case 177: /* eidlist_opt */
- case 186: /* sortlist */
- case 187: /* eidlist */
- case 199: /* selcollist */
- case 202: /* groupby_opt */
- case 204: /* orderby_opt */
- case 207: /* nexprlist */
- case 208: /* exprlist */
- case 209: /* sclp */
- case 218: /* setlist */
- case 225: /* case_exprlist */
+ case 179: /* idxlist_opt */
+ case 188: /* idxlist */
+ case 200: /* selcollist */
+ case 203: /* groupby_opt */
+ case 205: /* orderby_opt */
+ case 208: /* nexprlist */
+ case 209: /* exprlist */
+ case 210: /* sclp */
+ case 220: /* sortlist */
+ case 221: /* setlist */
+ case 228: /* case_exprlist */
{
-sqlite3ExprListDelete(pParse->db, (yypminor->yy442));
+sqlite3ExprListDelete(pParse->db, (yypminor->yy14));
}
break;
- case 193: /* fullname */
- case 200: /* from */
- case 211: /* seltablist */
- case 212: /* stl_prefix */
+ case 194: /* fullname */
+ case 201: /* from */
+ case 212: /* seltablist */
+ case 213: /* stl_prefix */
{
-sqlite3SrcListDelete(pParse->db, (yypminor->yy347));
+sqlite3SrcListDelete(pParse->db, (yypminor->yy65));
}
break;
- case 196: /* with */
- case 249: /* wqlist */
+ case 197: /* with */
+ case 252: /* wqlist */
{
-sqlite3WithDelete(pParse->db, (yypminor->yy331));
+sqlite3WithDelete(pParse->db, (yypminor->yy59));
}
break;
- case 201: /* where_opt */
- case 203: /* having_opt */
- case 215: /* on_opt */
- case 224: /* case_operand */
- case 226: /* case_else */
- case 235: /* when_clause */
- case 240: /* key_opt */
+ case 202: /* where_opt */
+ case 204: /* having_opt */
+ case 216: /* on_opt */
+ case 227: /* case_operand */
+ case 229: /* case_else */
+ case 238: /* when_clause */
+ case 243: /* key_opt */
{
-sqlite3ExprDelete(pParse->db, (yypminor->yy122));
+sqlite3ExprDelete(pParse->db, (yypminor->yy132));
}
break;
- case 216: /* using_opt */
- case 217: /* idlist */
- case 220: /* idlist_opt */
+ case 217: /* using_opt */
+ case 219: /* idlist */
+ case 223: /* inscollist_opt */
{
-sqlite3IdListDelete(pParse->db, (yypminor->yy180));
+sqlite3IdListDelete(pParse->db, (yypminor->yy408));
}
break;
- case 231: /* trigger_cmd_list */
- case 236: /* trigger_cmd */
+ case 234: /* trigger_cmd_list */
+ case 239: /* trigger_cmd */
{
-sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy327));
+sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy473));
}
break;
- case 233: /* trigger_event */
+ case 236: /* trigger_event */
{
-sqlite3IdListDelete(pParse->db, (yypminor->yy410).b);
+sqlite3IdListDelete(pParse->db, (yypminor->yy378).b);
}
break;
-/********* End destructor definitions *****************************************/
default: break; /* If no destructor action specified: do nothing */
}
}
@@ -132295,37 +124711,49 @@ sqlite3IdListDelete(pParse->db, (yypminor->yy410).b);
**
** If there is a destructor routine associated with the token which
** is popped from the stack, then call it.
+**
+** Return the major token number for the symbol popped.
*/
-static void yy_pop_parser_stack(yyParser *pParser){
- yyStackEntry *yytos;
- assert( pParser->yyidx>=0 );
- yytos = &pParser->yystack[pParser->yyidx--];
+static int yy_pop_parser_stack(yyParser *pParser){
+ YYCODETYPE yymajor;
+ yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
+
+ /* There is no mechanism by which the parser stack can be popped below
+ ** empty in SQLite. */
+ if( NEVER(pParser->yyidx<0) ) return 0;
#ifndef NDEBUG
- if( yyTraceFILE ){
+ if( yyTraceFILE && pParser->yyidx>=0 ){
fprintf(yyTraceFILE,"%sPopping %s\n",
yyTracePrompt,
yyTokenName[yytos->major]);
}
#endif
- yy_destructor(pParser, yytos->major, &yytos->minor);
+ yymajor = yytos->major;
+ yy_destructor(pParser, yymajor, &yytos->minor);
+ pParser->yyidx--;
+ return yymajor;
}
/*
-** Deallocate and destroy a parser. Destructors are called for
+** Deallocate and destroy a parser. Destructors are all called for
** all stack elements before shutting the parser down.
**
-** If the YYPARSEFREENEVERNULL macro exists (for example because it
-** is defined in a %include section of the input grammar) then it is
-** assumed that the input pointer is never NULL.
+** Inputs:
+** <ul>
+** <li> A pointer to the parser. This should be a pointer
+** obtained from sqlite3ParserAlloc.
+** <li> A pointer to a function used to reclaim memory obtained
+** from malloc.
+** </ul>
*/
SQLITE_PRIVATE void sqlite3ParserFree(
void *p, /* The parser to be deleted */
void (*freeProc)(void*) /* Function used to reclaim memory */
){
yyParser *pParser = (yyParser*)p;
-#ifndef YYPARSEFREENEVERNULL
- if( pParser==0 ) return;
-#endif
+ /* In SQLite, we never try to destroy a parser that was not successfully
+ ** created in the first place. */
+ if( NEVER(pParser==0) ) return;
while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
#if YYSTACKDEPTH<=0
free(pParser->yystack);
@@ -132346,72 +124774,75 @@ SQLITE_PRIVATE int sqlite3ParserStackPeak(void *p){
/*
** Find the appropriate action for a parser given the terminal
** look-ahead token iLookAhead.
+**
+** If the look-ahead token is YYNOCODE, then check to see if the action is
+** independent of the look-ahead. If it is, return the action, otherwise
+** return YY_NO_ACTION.
*/
-static unsigned int yy_find_shift_action(
+static int yy_find_shift_action(
yyParser *pParser, /* The parser */
YYCODETYPE iLookAhead /* The look-ahead token */
){
int i;
int stateno = pParser->yystack[pParser->yyidx].stateno;
- if( stateno>=YY_MIN_REDUCE ) return stateno;
- assert( stateno <= YY_SHIFT_COUNT );
- do{
- i = yy_shift_ofst[stateno];
- if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno];
- assert( iLookAhead!=YYNOCODE );
- i += iLookAhead;
- if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
- if( iLookAhead>0 ){
+ if( stateno>YY_SHIFT_COUNT
+ || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){
+ return yy_default[stateno];
+ }
+ assert( iLookAhead!=YYNOCODE );
+ i += iLookAhead;
+ if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
+ if( iLookAhead>0 ){
#ifdef YYFALLBACK
- YYCODETYPE iFallback; /* Fallback token */
- if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
- && (iFallback = yyFallback[iLookAhead])!=0 ){
+ YYCODETYPE iFallback; /* Fallback token */
+ if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
+ && (iFallback = yyFallback[iLookAhead])!=0 ){
#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
- yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
- }
-#endif
- assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */
- iLookAhead = iFallback;
- continue;
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
}
#endif
+ return yy_find_shift_action(pParser, iFallback);
+ }
+#endif
#ifdef YYWILDCARD
- {
- int j = i - iLookAhead + YYWILDCARD;
- if(
+ {
+ int j = i - iLookAhead + YYWILDCARD;
+ if(
#if YY_SHIFT_MIN+YYWILDCARD<0
- j>=0 &&
+ j>=0 &&
#endif
#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT
- j<YY_ACTTAB_COUNT &&
+ j<YY_ACTTAB_COUNT &&
#endif
- yy_lookahead[j]==YYWILDCARD
- ){
+ yy_lookahead[j]==YYWILDCARD
+ ){
#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
- yyTracePrompt, yyTokenName[iLookAhead],
- yyTokenName[YYWILDCARD]);
- }
-#endif /* NDEBUG */
- return yy_action[j];
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]);
}
+#endif /* NDEBUG */
+ return yy_action[j];
}
-#endif /* YYWILDCARD */
}
- return yy_default[stateno];
- }else{
- return yy_action[i];
+#endif /* YYWILDCARD */
}
- }while(1);
+ return yy_default[stateno];
+ }else{
+ return yy_action[i];
+ }
}
/*
** Find the appropriate action for a parser given the non-terminal
** look-ahead token iLookAhead.
+**
+** If the look-ahead token is YYNOCODE, then check to see if the action is
+** independent of the look-ahead. If it is, return the action, otherwise
+** return YY_NO_ACTION.
*/
static int yy_find_reduce_action(
int stateno, /* Current state number */
@@ -132443,7 +124874,7 @@ static int yy_find_reduce_action(
/*
** The following routine is called if the stack overflows.
*/
-static void yyStackOverflow(yyParser *yypParser){
+static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
sqlite3ParserARG_FETCH;
yypParser->yyidx--;
#ifndef NDEBUG
@@ -132454,41 +124885,20 @@ static void yyStackOverflow(yyParser *yypParser){
while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
/* Here code is inserted which will execute if the parser
** stack every overflows */
-/******** Begin %stack_overflow code ******************************************/
+ UNUSED_PARAMETER(yypMinor); /* Silence some compiler warnings */
sqlite3ErrorMsg(pParse, "parser stack overflow");
-/******** End %stack_overflow code ********************************************/
sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument var */
}
/*
-** Print tracing information for a SHIFT action
-*/
-#ifndef NDEBUG
-static void yyTraceShift(yyParser *yypParser, int yyNewState){
- if( yyTraceFILE ){
- if( yyNewState<YYNSTATE ){
- fprintf(yyTraceFILE,"%sShift '%s', go to state %d\n",
- yyTracePrompt,yyTokenName[yypParser->yystack[yypParser->yyidx].major],
- yyNewState);
- }else{
- fprintf(yyTraceFILE,"%sShift '%s'\n",
- yyTracePrompt,yyTokenName[yypParser->yystack[yypParser->yyidx].major]);
- }
- }
-}
-#else
-# define yyTraceShift(X,Y)
-#endif
-
-/*
** Perform a shift action.
*/
static void yy_shift(
yyParser *yypParser, /* The parser to be shifted */
int yyNewState, /* The new state to shift in */
int yyMajor, /* The major token to shift in */
- sqlite3ParserTOKENTYPE yyMinor /* The minor token to shift in */
+ YYMINORTYPE *yypMinor /* Pointer to the minor token to shift in */
){
yyStackEntry *yytos;
yypParser->yyidx++;
@@ -132499,14 +124909,14 @@ static void yy_shift(
#endif
#if YYSTACKDEPTH>0
if( yypParser->yyidx>=YYSTACKDEPTH ){
- yyStackOverflow(yypParser);
+ yyStackOverflow(yypParser, yypMinor);
return;
}
#else
if( yypParser->yyidx>=yypParser->yystksz ){
yyGrowStack(yypParser);
if( yypParser->yyidx>=yypParser->yystksz ){
- yyStackOverflow(yypParser);
+ yyStackOverflow(yypParser, yypMinor);
return;
}
}
@@ -132514,8 +124924,17 @@ static void yy_shift(
yytos = &yypParser->yystack[yypParser->yyidx];
yytos->stateno = (YYACTIONTYPE)yyNewState;
yytos->major = (YYCODETYPE)yyMajor;
- yytos->minor.yy0 = yyMinor;
- yyTraceShift(yypParser, yyNewState);
+ yytos->minor = *yypMinor;
+#ifndef NDEBUG
+ if( yyTraceFILE && yypParser->yyidx>0 ){
+ int i;
+ fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
+ fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
+ for(i=1; i<=yypParser->yyidx; i++)
+ fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
+ fprintf(yyTraceFILE,"\n");
+ }
+#endif
}
/* The following table contains information about every rule that
@@ -132525,10 +124944,19 @@ static const struct {
YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
unsigned char nrhs; /* Number of right-hand side symbols in the rule */
} yyRuleInfo[] = {
+ { 144, 1 },
+ { 145, 2 },
+ { 145, 1 },
+ { 146, 1 },
+ { 146, 3 },
+ { 147, 0 },
{ 147, 1 },
{ 147, 3 },
{ 148, 1 },
{ 149, 3 },
+ { 151, 0 },
+ { 151, 1 },
+ { 151, 2 },
{ 150, 0 },
{ 150, 1 },
{ 150, 1 },
@@ -132536,9 +124964,12 @@ static const struct {
{ 149, 2 },
{ 149, 2 },
{ 149, 2 },
+ { 153, 1 },
+ { 153, 0 },
{ 149, 2 },
{ 149, 3 },
{ 149, 5 },
+ { 149, 2 },
{ 154, 6 },
{ 156, 1 },
{ 158, 0 },
@@ -132549,193 +124980,218 @@ static const struct {
{ 155, 2 },
{ 162, 0 },
{ 162, 2 },
- { 164, 2 },
+ { 160, 3 },
+ { 160, 1 },
+ { 164, 3 },
+ { 165, 1 },
+ { 152, 1 },
+ { 152, 1 },
+ { 152, 1 },
{ 166, 0 },
- { 166, 4 },
- { 166, 6 },
+ { 166, 1 },
+ { 168, 1 },
+ { 168, 4 },
+ { 168, 6 },
+ { 169, 1 },
+ { 169, 2 },
+ { 170, 1 },
+ { 170, 1 },
{ 167, 2 },
- { 171, 2 },
- { 171, 2 },
- { 171, 4 },
- { 171, 3 },
- { 171, 3 },
- { 171, 2 },
- { 171, 3 },
- { 171, 5 },
- { 171, 2 },
- { 171, 4 },
- { 171, 4 },
- { 171, 1 },
- { 171, 2 },
- { 176, 0 },
- { 176, 1 },
+ { 167, 0 },
+ { 173, 2 },
+ { 173, 2 },
+ { 173, 4 },
+ { 173, 3 },
+ { 173, 3 },
+ { 173, 2 },
+ { 173, 2 },
+ { 173, 3 },
+ { 173, 5 },
+ { 173, 2 },
+ { 173, 4 },
+ { 173, 4 },
+ { 173, 1 },
+ { 173, 2 },
{ 178, 0 },
- { 178, 2 },
+ { 178, 1 },
+ { 180, 0 },
{ 180, 2 },
- { 180, 3 },
- { 180, 3 },
- { 180, 3 },
- { 181, 2 },
- { 181, 2 },
- { 181, 1 },
- { 181, 1 },
- { 181, 2 },
- { 179, 3 },
- { 179, 2 },
- { 182, 0 },
- { 182, 2 },
{ 182, 2 },
+ { 182, 3 },
+ { 182, 3 },
+ { 182, 3 },
+ { 183, 2 },
+ { 183, 2 },
+ { 183, 1 },
+ { 183, 1 },
+ { 183, 2 },
+ { 181, 3 },
+ { 181, 2 },
+ { 184, 0 },
+ { 184, 2 },
+ { 184, 2 },
{ 161, 0 },
- { 184, 1 },
- { 185, 2 },
- { 185, 7 },
- { 185, 5 },
- { 185, 5 },
- { 185, 10 },
- { 188, 0 },
- { 174, 0 },
- { 174, 3 },
+ { 161, 2 },
+ { 185, 3 },
+ { 185, 1 },
+ { 186, 1 },
+ { 186, 0 },
+ { 187, 2 },
+ { 187, 7 },
+ { 187, 5 },
+ { 187, 5 },
+ { 187, 10 },
{ 189, 0 },
- { 189, 2 },
- { 190, 1 },
- { 190, 1 },
+ { 189, 1 },
+ { 176, 0 },
+ { 176, 3 },
+ { 190, 0 },
+ { 190, 2 },
+ { 191, 1 },
+ { 191, 1 },
+ { 191, 1 },
{ 149, 4 },
- { 192, 2 },
- { 192, 0 },
- { 149, 9 },
+ { 193, 2 },
+ { 193, 0 },
+ { 149, 8 },
{ 149, 4 },
{ 149, 1 },
{ 163, 2 },
- { 194, 3 },
- { 197, 1 },
- { 197, 2 },
- { 197, 1 },
- { 195, 9 },
- { 206, 4 },
- { 206, 5 },
+ { 195, 1 },
+ { 195, 3 },
{ 198, 1 },
+ { 198, 2 },
{ 198, 1 },
- { 198, 0 },
- { 209, 0 },
- { 199, 3 },
- { 199, 2 },
- { 199, 4 },
+ { 196, 9 },
+ { 196, 1 },
+ { 207, 4 },
+ { 207, 5 },
+ { 199, 1 },
+ { 199, 1 },
+ { 199, 0 },
{ 210, 2 },
{ 210, 0 },
- { 200, 0 },
+ { 200, 3 },
{ 200, 2 },
- { 212, 2 },
- { 212, 0 },
- { 211, 7 },
- { 211, 9 },
- { 211, 7 },
- { 211, 7 },
+ { 200, 4 },
+ { 211, 2 },
+ { 211, 1 },
+ { 211, 0 },
+ { 201, 0 },
+ { 201, 2 },
+ { 213, 2 },
+ { 213, 0 },
+ { 212, 7 },
+ { 212, 7 },
+ { 212, 7 },
{ 159, 0 },
{ 159, 2 },
- { 193, 2 },
- { 213, 1 },
- { 213, 2 },
- { 213, 3 },
- { 213, 4 },
- { 215, 2 },
- { 215, 0 },
- { 214, 0 },
- { 214, 3 },
+ { 194, 2 },
+ { 214, 1 },
{ 214, 2 },
- { 216, 4 },
+ { 214, 3 },
+ { 214, 4 },
+ { 216, 2 },
{ 216, 0 },
- { 204, 0 },
- { 204, 3 },
- { 186, 4 },
- { 186, 2 },
- { 175, 1 },
- { 175, 1 },
- { 175, 0 },
- { 202, 0 },
- { 202, 3 },
- { 203, 0 },
- { 203, 2 },
+ { 215, 0 },
+ { 215, 3 },
+ { 215, 2 },
+ { 217, 4 },
+ { 217, 0 },
{ 205, 0 },
- { 205, 2 },
- { 205, 4 },
- { 205, 4 },
+ { 205, 3 },
+ { 220, 4 },
+ { 220, 2 },
+ { 177, 1 },
+ { 177, 1 },
+ { 177, 0 },
+ { 203, 0 },
+ { 203, 3 },
+ { 204, 0 },
+ { 204, 2 },
+ { 206, 0 },
+ { 206, 2 },
+ { 206, 4 },
+ { 206, 4 },
{ 149, 6 },
- { 201, 0 },
- { 201, 2 },
+ { 202, 0 },
+ { 202, 2 },
{ 149, 8 },
- { 218, 5 },
- { 218, 3 },
+ { 221, 5 },
+ { 221, 3 },
{ 149, 6 },
{ 149, 7 },
- { 219, 2 },
- { 219, 1 },
- { 220, 0 },
- { 220, 3 },
- { 217, 3 },
- { 217, 1 },
- { 173, 3 },
- { 172, 1 },
- { 173, 1 },
- { 173, 1 },
- { 173, 3 },
- { 173, 5 },
- { 172, 1 },
- { 172, 1 },
- { 173, 1 },
- { 173, 3 },
- { 173, 6 },
- { 173, 5 },
- { 173, 4 },
- { 172, 1 },
- { 173, 3 },
- { 173, 3 },
- { 173, 3 },
- { 173, 3 },
- { 173, 3 },
- { 173, 3 },
- { 173, 3 },
- { 173, 3 },
- { 221, 1 },
- { 221, 2 },
- { 173, 3 },
- { 173, 5 },
- { 173, 2 },
- { 173, 3 },
- { 173, 3 },
- { 173, 4 },
- { 173, 2 },
- { 173, 2 },
- { 173, 2 },
- { 173, 2 },
- { 222, 1 },
{ 222, 2 },
- { 173, 5 },
- { 223, 1 },
- { 223, 2 },
- { 173, 5 },
- { 173, 3 },
- { 173, 5 },
- { 173, 4 },
- { 173, 4 },
- { 173, 5 },
- { 225, 5 },
- { 225, 4 },
- { 226, 2 },
- { 226, 0 },
+ { 222, 1 },
+ { 223, 0 },
+ { 223, 3 },
+ { 219, 3 },
+ { 219, 1 },
+ { 175, 1 },
+ { 175, 3 },
+ { 174, 1 },
+ { 175, 1 },
+ { 175, 1 },
+ { 175, 3 },
+ { 175, 5 },
+ { 174, 1 },
+ { 174, 1 },
+ { 175, 1 },
+ { 175, 3 },
+ { 175, 6 },
+ { 175, 5 },
+ { 175, 4 },
+ { 174, 1 },
+ { 175, 3 },
+ { 175, 3 },
+ { 175, 3 },
+ { 175, 3 },
+ { 175, 3 },
+ { 175, 3 },
+ { 175, 3 },
+ { 175, 3 },
{ 224, 1 },
- { 224, 0 },
- { 208, 0 },
- { 207, 3 },
- { 207, 1 },
- { 149, 12 },
+ { 224, 2 },
+ { 175, 3 },
+ { 175, 5 },
+ { 175, 2 },
+ { 175, 3 },
+ { 175, 3 },
+ { 175, 4 },
+ { 175, 2 },
+ { 175, 2 },
+ { 175, 2 },
+ { 175, 2 },
+ { 225, 1 },
+ { 225, 2 },
+ { 175, 5 },
+ { 226, 1 },
+ { 226, 2 },
+ { 175, 5 },
+ { 175, 3 },
+ { 175, 5 },
+ { 175, 4 },
+ { 175, 4 },
+ { 175, 5 },
+ { 228, 5 },
+ { 228, 4 },
+ { 229, 2 },
+ { 229, 0 },
{ 227, 1 },
{ 227, 0 },
- { 177, 0 },
- { 177, 3 },
- { 187, 5 },
- { 187, 3 },
- { 228, 0 },
- { 228, 2 },
+ { 209, 1 },
+ { 209, 0 },
+ { 208, 3 },
+ { 208, 1 },
+ { 149, 12 },
+ { 230, 1 },
+ { 230, 0 },
+ { 179, 0 },
+ { 179, 3 },
+ { 188, 5 },
+ { 188, 3 },
+ { 231, 0 },
+ { 231, 2 },
{ 149, 4 },
{ 149, 1 },
{ 149, 2 },
@@ -132744,113 +125200,77 @@ static const struct {
{ 149, 6 },
{ 149, 5 },
{ 149, 6 },
- { 169, 2 },
- { 170, 2 },
- { 149, 5 },
- { 230, 11 },
{ 232, 1 },
{ 232, 1 },
- { 232, 2 },
- { 232, 0 },
- { 233, 1 },
- { 233, 1 },
- { 233, 3 },
- { 235, 0 },
+ { 232, 1 },
+ { 232, 1 },
+ { 232, 1 },
+ { 171, 2 },
+ { 171, 1 },
+ { 172, 2 },
+ { 149, 5 },
+ { 233, 11 },
+ { 235, 1 },
+ { 235, 1 },
{ 235, 2 },
- { 231, 3 },
- { 231, 2 },
+ { 235, 0 },
+ { 236, 1 },
+ { 236, 1 },
+ { 236, 3 },
+ { 237, 0 },
{ 237, 3 },
- { 238, 3 },
+ { 238, 0 },
{ 238, 2 },
- { 236, 7 },
- { 236, 5 },
- { 236, 5 },
- { 236, 1 },
- { 173, 4 },
- { 173, 6 },
- { 191, 1 },
- { 191, 1 },
- { 191, 1 },
+ { 234, 3 },
+ { 234, 2 },
+ { 240, 1 },
+ { 240, 3 },
+ { 241, 0 },
+ { 241, 3 },
+ { 241, 2 },
+ { 239, 7 },
+ { 239, 5 },
+ { 239, 5 },
+ { 239, 1 },
+ { 175, 4 },
+ { 175, 6 },
+ { 192, 1 },
+ { 192, 1 },
+ { 192, 1 },
{ 149, 4 },
{ 149, 6 },
{ 149, 3 },
- { 240, 0 },
- { 240, 2 },
+ { 243, 0 },
+ { 243, 2 },
+ { 242, 1 },
+ { 242, 0 },
{ 149, 1 },
{ 149, 3 },
{ 149, 1 },
{ 149, 3 },
{ 149, 6 },
- { 149, 7 },
- { 241, 1 },
+ { 149, 6 },
+ { 244, 1 },
+ { 245, 0 },
+ { 245, 1 },
{ 149, 1 },
{ 149, 4 },
- { 243, 8 },
- { 245, 0 },
- { 246, 1 },
- { 246, 3 },
+ { 246, 8 },
{ 247, 1 },
- { 196, 0 },
- { 196, 2 },
- { 196, 3 },
- { 249, 6 },
- { 249, 8 },
- { 144, 1 },
- { 145, 2 },
- { 145, 1 },
- { 146, 1 },
- { 146, 3 },
- { 147, 0 },
- { 151, 0 },
- { 151, 1 },
- { 151, 2 },
- { 153, 1 },
- { 153, 0 },
- { 149, 2 },
- { 160, 4 },
- { 160, 2 },
- { 152, 1 },
- { 152, 1 },
- { 152, 1 },
- { 166, 1 },
- { 167, 1 },
- { 168, 1 },
- { 168, 1 },
- { 165, 2 },
- { 165, 0 },
- { 171, 2 },
- { 161, 2 },
- { 183, 3 },
- { 183, 1 },
- { 184, 0 },
- { 188, 1 },
- { 190, 1 },
- { 194, 1 },
- { 195, 1 },
- { 209, 2 },
- { 210, 1 },
- { 173, 1 },
- { 208, 1 },
- { 229, 1 },
- { 229, 1 },
- { 229, 1 },
- { 229, 1 },
- { 229, 1 },
- { 169, 1 },
- { 234, 0 },
- { 234, 3 },
- { 237, 1 },
- { 238, 0 },
- { 239, 1 },
- { 239, 0 },
- { 242, 0 },
- { 242, 1 },
- { 244, 1 },
- { 244, 3 },
- { 245, 2 },
+ { 247, 3 },
{ 248, 0 },
- { 248, 4 },
{ 248, 2 },
+ { 249, 1 },
+ { 249, 3 },
+ { 250, 1 },
+ { 251, 0 },
+ { 251, 4 },
+ { 251, 2 },
+ { 197, 0 },
+ { 197, 2 },
+ { 197, 3 },
+ { 252, 6 },
+ { 252, 8 },
};
static void yy_accept(yyParser*); /* Forward Declaration */
@@ -132861,46 +125281,40 @@ static void yy_accept(yyParser*); /* Forward Declaration */
*/
static void yy_reduce(
yyParser *yypParser, /* The parser */
- unsigned int yyruleno /* Number of the rule by which to reduce */
+ int yyruleno /* Number of the rule by which to reduce */
){
int yygoto; /* The next state */
int yyact; /* The next action */
+ YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
yyStackEntry *yymsp; /* The top of the parser's stack */
int yysize; /* Amount to pop the stack */
sqlite3ParserARG_FETCH;
yymsp = &yypParser->yystack[yypParser->yyidx];
#ifndef NDEBUG
- if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
- yysize = yyRuleInfo[yyruleno].nrhs;
- fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt,
- yyRuleName[yyruleno], yymsp[-yysize].stateno);
+ if( yyTraceFILE && yyruleno>=0
+ && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
+ fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
+ yyRuleName[yyruleno]);
}
#endif /* NDEBUG */
- /* Check that the stack is large enough to grow by a single entry
- ** if the RHS of the rule is empty. This ensures that there is room
- ** enough on the stack to push the LHS value */
- if( yyRuleInfo[yyruleno].nrhs==0 ){
-#ifdef YYTRACKMAXSTACKDEPTH
- if( yypParser->yyidx>yypParser->yyidxMax ){
- yypParser->yyidxMax = yypParser->yyidx;
- }
-#endif
-#if YYSTACKDEPTH>0
- if( yypParser->yyidx>=YYSTACKDEPTH-1 ){
- yyStackOverflow(yypParser);
- return;
- }
-#else
- if( yypParser->yyidx>=yypParser->yystksz-1 ){
- yyGrowStack(yypParser);
- if( yypParser->yyidx>=yypParser->yystksz-1 ){
- yyStackOverflow(yypParser);
- return;
- }
- }
-#endif
- }
+ /* Silence complaints from purify about yygotominor being uninitialized
+ ** in some cases when it is copied into the stack after the following
+ ** switch. yygotominor is uninitialized when a rule reduces that does
+ ** not set the value of its left-hand side nonterminal. Leaving the
+ ** value of the nonterminal uninitialized is utterly harmless as long
+ ** as the value is never used. So really the only thing this code
+ ** accomplishes is to quieten purify.
+ **
+ ** 2007-01-16: The wireshark project (www.wireshark.org) reports that
+ ** without this code, their parser segfaults. I'm not sure what there
+ ** parser is doing to make this happen. This is the second bug report
+ ** from wireshark this week. Clearly they are stressing Lemon in ways
+ ** that it has not been previously stressed... (SQLite ticket #2172)
+ */
+ /*memset(&yygotominor, 0, sizeof(yygotominor));*/
+ yygotominor = yyzerominor;
+
switch( yyruleno ){
/* Beginning here are the reduction cases. A typical example
@@ -132911,287 +125325,326 @@ static void yy_reduce(
** #line <lineno> <thisfile>
** break;
*/
-/********** Begin reduce actions **********************************************/
- YYMINORTYPE yylhsminor;
- case 0: /* explain ::= EXPLAIN */
-{ pParse->explain = 1; }
+ case 5: /* explain ::= */
+{ sqlite3BeginParse(pParse, 0); }
+ break;
+ case 6: /* explain ::= EXPLAIN */
+{ sqlite3BeginParse(pParse, 1); }
break;
- case 1: /* explain ::= EXPLAIN QUERY PLAN */
-{ pParse->explain = 2; }
+ case 7: /* explain ::= EXPLAIN QUERY PLAN */
+{ sqlite3BeginParse(pParse, 2); }
break;
- case 2: /* cmdx ::= cmd */
+ case 8: /* cmdx ::= cmd */
{ sqlite3FinishCoding(pParse); }
break;
- case 3: /* cmd ::= BEGIN transtype trans_opt */
-{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy392);}
+ case 9: /* cmd ::= BEGIN transtype trans_opt */
+{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy328);}
break;
- case 4: /* transtype ::= */
-{yymsp[1].minor.yy392 = TK_DEFERRED;}
+ case 13: /* transtype ::= */
+{yygotominor.yy328 = TK_DEFERRED;}
break;
- case 5: /* transtype ::= DEFERRED */
- case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6);
- case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7);
-{yymsp[0].minor.yy392 = yymsp[0].major; /*A-overwrites-X*/}
+ case 14: /* transtype ::= DEFERRED */
+ case 15: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==15);
+ case 16: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==16);
+ case 115: /* multiselect_op ::= UNION */ yytestcase(yyruleno==115);
+ case 117: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==117);
+{yygotominor.yy328 = yymsp[0].major;}
break;
- case 8: /* cmd ::= COMMIT trans_opt */
- case 9: /* cmd ::= END trans_opt */ yytestcase(yyruleno==9);
+ case 17: /* cmd ::= COMMIT trans_opt */
+ case 18: /* cmd ::= END trans_opt */ yytestcase(yyruleno==18);
{sqlite3CommitTransaction(pParse);}
break;
- case 10: /* cmd ::= ROLLBACK trans_opt */
+ case 19: /* cmd ::= ROLLBACK trans_opt */
{sqlite3RollbackTransaction(pParse);}
break;
- case 11: /* cmd ::= SAVEPOINT nm */
+ case 22: /* cmd ::= SAVEPOINT nm */
{
sqlite3Savepoint(pParse, SAVEPOINT_BEGIN, &yymsp[0].minor.yy0);
}
break;
- case 12: /* cmd ::= RELEASE savepoint_opt nm */
+ case 23: /* cmd ::= RELEASE savepoint_opt nm */
{
sqlite3Savepoint(pParse, SAVEPOINT_RELEASE, &yymsp[0].minor.yy0);
}
break;
- case 13: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
+ case 24: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
{
sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0);
}
break;
- case 14: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
+ case 26: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
{
- sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy392,0,0,yymsp[-2].minor.yy392);
+ sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy328,0,0,yymsp[-2].minor.yy328);
}
break;
- case 15: /* createkw ::= CREATE */
-{disableLookaside(pParse);}
- break;
- case 16: /* ifnotexists ::= */
- case 19: /* temp ::= */ yytestcase(yyruleno==19);
- case 22: /* table_options ::= */ yytestcase(yyruleno==22);
- case 42: /* autoinc ::= */ yytestcase(yyruleno==42);
- case 57: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==57);
- case 67: /* defer_subclause_opt ::= */ yytestcase(yyruleno==67);
- case 76: /* ifexists ::= */ yytestcase(yyruleno==76);
- case 90: /* distinct ::= */ yytestcase(yyruleno==90);
- case 209: /* collate ::= */ yytestcase(yyruleno==209);
-{yymsp[1].minor.yy392 = 0;}
+ case 27: /* createkw ::= CREATE */
+{
+ pParse->db->lookaside.bEnabled = 0;
+ yygotominor.yy0 = yymsp[0].minor.yy0;
+}
break;
- case 17: /* ifnotexists ::= IF NOT EXISTS */
-{yymsp[-2].minor.yy392 = 1;}
+ case 28: /* ifnotexists ::= */
+ case 31: /* temp ::= */ yytestcase(yyruleno==31);
+ case 68: /* autoinc ::= */ yytestcase(yyruleno==68);
+ case 81: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ yytestcase(yyruleno==81);
+ case 83: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==83);
+ case 85: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ yytestcase(yyruleno==85);
+ case 97: /* defer_subclause_opt ::= */ yytestcase(yyruleno==97);
+ case 108: /* ifexists ::= */ yytestcase(yyruleno==108);
+ case 218: /* between_op ::= BETWEEN */ yytestcase(yyruleno==218);
+ case 221: /* in_op ::= IN */ yytestcase(yyruleno==221);
+{yygotominor.yy328 = 0;}
break;
- case 18: /* temp ::= TEMP */
- case 43: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==43);
-{yymsp[0].minor.yy392 = 1;}
+ case 29: /* ifnotexists ::= IF NOT EXISTS */
+ case 30: /* temp ::= TEMP */ yytestcase(yyruleno==30);
+ case 69: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==69);
+ case 84: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ yytestcase(yyruleno==84);
+ case 107: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==107);
+ case 219: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==219);
+ case 222: /* in_op ::= NOT IN */ yytestcase(yyruleno==222);
+{yygotominor.yy328 = 1;}
break;
- case 20: /* create_table_args ::= LP columnlist conslist_opt RP table_options */
+ case 32: /* create_table_args ::= LP columnlist conslist_opt RP table_options */
{
- sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy392,0);
+ sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy186,0);
}
break;
- case 21: /* create_table_args ::= AS select */
+ case 33: /* create_table_args ::= AS select */
{
- sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy159);
- sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy159);
+ sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy3);
+ sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy3);
}
break;
- case 23: /* table_options ::= WITHOUT nm */
+ case 34: /* table_options ::= */
+{yygotominor.yy186 = 0;}
+ break;
+ case 35: /* table_options ::= WITHOUT nm */
{
if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){
- yymsp[-1].minor.yy392 = TF_WithoutRowid | TF_NoVisibleRowid;
+ yygotominor.yy186 = TF_WithoutRowid;
}else{
- yymsp[-1].minor.yy392 = 0;
+ yygotominor.yy186 = 0;
sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
}
}
break;
- case 24: /* columnname ::= nm typetoken */
-{sqlite3AddColumn(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
+ case 38: /* column ::= columnid type carglist */
+{
+ yygotominor.yy0.z = yymsp[-2].minor.yy0.z;
+ yygotominor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-2].minor.yy0.z) + pParse->sLastToken.n;
+}
break;
- case 25: /* typetoken ::= */
- case 60: /* conslist_opt ::= */ yytestcase(yyruleno==60);
- case 96: /* as ::= */ yytestcase(yyruleno==96);
-{yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;}
+ case 39: /* columnid ::= nm */
+{
+ sqlite3AddColumn(pParse,&yymsp[0].minor.yy0);
+ yygotominor.yy0 = yymsp[0].minor.yy0;
+ pParse->constraintName.n = 0;
+}
break;
- case 26: /* typetoken ::= typename LP signed RP */
+ case 40: /* nm ::= ID|INDEXED */
+ case 41: /* nm ::= STRING */ yytestcase(yyruleno==41);
+ case 42: /* nm ::= JOIN_KW */ yytestcase(yyruleno==42);
+ case 45: /* typetoken ::= typename */ yytestcase(yyruleno==45);
+ case 48: /* typename ::= ID|STRING */ yytestcase(yyruleno==48);
+ case 130: /* as ::= AS nm */ yytestcase(yyruleno==130);
+ case 131: /* as ::= ID|STRING */ yytestcase(yyruleno==131);
+ case 141: /* dbnm ::= DOT nm */ yytestcase(yyruleno==141);
+ case 150: /* indexed_opt ::= INDEXED BY nm */ yytestcase(yyruleno==150);
+ case 247: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==247);
+ case 256: /* nmnum ::= plus_num */ yytestcase(yyruleno==256);
+ case 257: /* nmnum ::= nm */ yytestcase(yyruleno==257);
+ case 258: /* nmnum ::= ON */ yytestcase(yyruleno==258);
+ case 259: /* nmnum ::= DELETE */ yytestcase(yyruleno==259);
+ case 260: /* nmnum ::= DEFAULT */ yytestcase(yyruleno==260);
+ case 261: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==261);
+ case 262: /* plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==262);
+ case 263: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==263);
+ case 279: /* trnm ::= nm */ yytestcase(yyruleno==279);
+{yygotominor.yy0 = yymsp[0].minor.yy0;}
+ break;
+ case 44: /* type ::= typetoken */
+{sqlite3AddColumnType(pParse,&yymsp[0].minor.yy0);}
+ break;
+ case 46: /* typetoken ::= typename LP signed RP */
{
- yymsp[-3].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z);
+ yygotominor.yy0.z = yymsp[-3].minor.yy0.z;
+ yygotominor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z);
}
break;
- case 27: /* typetoken ::= typename LP signed COMMA signed RP */
+ case 47: /* typetoken ::= typename LP signed COMMA signed RP */
{
- yymsp[-5].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z);
+ yygotominor.yy0.z = yymsp[-5].minor.yy0.z;
+ yygotominor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z);
}
break;
- case 28: /* typename ::= typename ID|STRING */
-{yymsp[-1].minor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);}
+ case 49: /* typename ::= typename ID|STRING */
+{yygotominor.yy0.z=yymsp[-1].minor.yy0.z; yygotominor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);}
break;
- case 29: /* ccons ::= CONSTRAINT nm */
- case 62: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==62);
+ case 54: /* ccons ::= CONSTRAINT nm */
+ case 92: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==92);
{pParse->constraintName = yymsp[0].minor.yy0;}
break;
- case 30: /* ccons ::= DEFAULT term */
- case 32: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==32);
-{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy342);}
+ case 55: /* ccons ::= DEFAULT term */
+ case 57: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==57);
+{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy346);}
break;
- case 31: /* ccons ::= DEFAULT LP expr RP */
-{sqlite3AddDefaultValue(pParse,&yymsp[-1].minor.yy342);}
+ case 56: /* ccons ::= DEFAULT LP expr RP */
+{sqlite3AddDefaultValue(pParse,&yymsp[-1].minor.yy346);}
break;
- case 33: /* ccons ::= DEFAULT MINUS term */
+ case 58: /* ccons ::= DEFAULT MINUS term */
{
ExprSpan v;
- v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy342.pExpr, 0, 0);
+ v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy346.pExpr, 0, 0);
v.zStart = yymsp[-1].minor.yy0.z;
- v.zEnd = yymsp[0].minor.yy342.zEnd;
+ v.zEnd = yymsp[0].minor.yy346.zEnd;
sqlite3AddDefaultValue(pParse,&v);
}
break;
- case 34: /* ccons ::= DEFAULT ID|INDEXED */
+ case 59: /* ccons ::= DEFAULT ID|INDEXED */
{
ExprSpan v;
- spanExpr(&v, pParse, TK_STRING, yymsp[0].minor.yy0);
+ spanExpr(&v, pParse, TK_STRING, &yymsp[0].minor.yy0);
sqlite3AddDefaultValue(pParse,&v);
}
break;
- case 35: /* ccons ::= NOT NULL onconf */
-{sqlite3AddNotNull(pParse, yymsp[0].minor.yy392);}
+ case 61: /* ccons ::= NOT NULL onconf */
+{sqlite3AddNotNull(pParse, yymsp[0].minor.yy328);}
break;
- case 36: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
-{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy392,yymsp[0].minor.yy392,yymsp[-2].minor.yy392);}
+ case 62: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
+{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy328,yymsp[0].minor.yy328,yymsp[-2].minor.yy328);}
break;
- case 37: /* ccons ::= UNIQUE onconf */
-{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy392,0,0,0,0);}
+ case 63: /* ccons ::= UNIQUE onconf */
+{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy328,0,0,0,0);}
break;
- case 38: /* ccons ::= CHECK LP expr RP */
-{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy342.pExpr);}
+ case 64: /* ccons ::= CHECK LP expr RP */
+{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy346.pExpr);}
break;
- case 39: /* ccons ::= REFERENCES nm eidlist_opt refargs */
-{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy442,yymsp[0].minor.yy392);}
+ case 65: /* ccons ::= REFERENCES nm idxlist_opt refargs */
+{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy14,yymsp[0].minor.yy328);}
break;
- case 40: /* ccons ::= defer_subclause */
-{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy392);}
+ case 66: /* ccons ::= defer_subclause */
+{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy328);}
break;
- case 41: /* ccons ::= COLLATE ID|STRING */
+ case 67: /* ccons ::= COLLATE ID|STRING */
{sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);}
break;
- case 44: /* refargs ::= */
-{ yymsp[1].minor.yy392 = OE_None*0x0101; /* EV: R-19803-45884 */}
- break;
- case 45: /* refargs ::= refargs refarg */
-{ yymsp[-1].minor.yy392 = (yymsp[-1].minor.yy392 & ~yymsp[0].minor.yy207.mask) | yymsp[0].minor.yy207.value; }
+ case 70: /* refargs ::= */
+{ yygotominor.yy328 = OE_None*0x0101; /* EV: R-19803-45884 */}
break;
- case 46: /* refarg ::= MATCH nm */
-{ yymsp[-1].minor.yy207.value = 0; yymsp[-1].minor.yy207.mask = 0x000000; }
+ case 71: /* refargs ::= refargs refarg */
+{ yygotominor.yy328 = (yymsp[-1].minor.yy328 & ~yymsp[0].minor.yy429.mask) | yymsp[0].minor.yy429.value; }
break;
- case 47: /* refarg ::= ON INSERT refact */
-{ yymsp[-2].minor.yy207.value = 0; yymsp[-2].minor.yy207.mask = 0x000000; }
+ case 72: /* refarg ::= MATCH nm */
+ case 73: /* refarg ::= ON INSERT refact */ yytestcase(yyruleno==73);
+{ yygotominor.yy429.value = 0; yygotominor.yy429.mask = 0x000000; }
break;
- case 48: /* refarg ::= ON DELETE refact */
-{ yymsp[-2].minor.yy207.value = yymsp[0].minor.yy392; yymsp[-2].minor.yy207.mask = 0x0000ff; }
+ case 74: /* refarg ::= ON DELETE refact */
+{ yygotominor.yy429.value = yymsp[0].minor.yy328; yygotominor.yy429.mask = 0x0000ff; }
break;
- case 49: /* refarg ::= ON UPDATE refact */
-{ yymsp[-2].minor.yy207.value = yymsp[0].minor.yy392<<8; yymsp[-2].minor.yy207.mask = 0x00ff00; }
+ case 75: /* refarg ::= ON UPDATE refact */
+{ yygotominor.yy429.value = yymsp[0].minor.yy328<<8; yygotominor.yy429.mask = 0x00ff00; }
break;
- case 50: /* refact ::= SET NULL */
-{ yymsp[-1].minor.yy392 = OE_SetNull; /* EV: R-33326-45252 */}
+ case 76: /* refact ::= SET NULL */
+{ yygotominor.yy328 = OE_SetNull; /* EV: R-33326-45252 */}
break;
- case 51: /* refact ::= SET DEFAULT */
-{ yymsp[-1].minor.yy392 = OE_SetDflt; /* EV: R-33326-45252 */}
+ case 77: /* refact ::= SET DEFAULT */
+{ yygotominor.yy328 = OE_SetDflt; /* EV: R-33326-45252 */}
break;
- case 52: /* refact ::= CASCADE */
-{ yymsp[0].minor.yy392 = OE_Cascade; /* EV: R-33326-45252 */}
+ case 78: /* refact ::= CASCADE */
+{ yygotominor.yy328 = OE_Cascade; /* EV: R-33326-45252 */}
break;
- case 53: /* refact ::= RESTRICT */
-{ yymsp[0].minor.yy392 = OE_Restrict; /* EV: R-33326-45252 */}
+ case 79: /* refact ::= RESTRICT */
+{ yygotominor.yy328 = OE_Restrict; /* EV: R-33326-45252 */}
break;
- case 54: /* refact ::= NO ACTION */
-{ yymsp[-1].minor.yy392 = OE_None; /* EV: R-33326-45252 */}
+ case 80: /* refact ::= NO ACTION */
+{ yygotominor.yy328 = OE_None; /* EV: R-33326-45252 */}
break;
- case 55: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
-{yymsp[-2].minor.yy392 = 0;}
+ case 82: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
+ case 98: /* defer_subclause_opt ::= defer_subclause */ yytestcase(yyruleno==98);
+ case 100: /* onconf ::= ON CONFLICT resolvetype */ yytestcase(yyruleno==100);
+ case 103: /* resolvetype ::= raisetype */ yytestcase(yyruleno==103);
+{yygotominor.yy328 = yymsp[0].minor.yy328;}
break;
- case 56: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
- case 71: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==71);
- case 142: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==142);
-{yymsp[-1].minor.yy392 = yymsp[0].minor.yy392;}
+ case 86: /* conslist_opt ::= */
+{yygotominor.yy0.n = 0; yygotominor.yy0.z = 0;}
break;
- case 58: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
- case 75: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==75);
- case 183: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==183);
- case 186: /* in_op ::= NOT IN */ yytestcase(yyruleno==186);
- case 210: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==210);
-{yymsp[-1].minor.yy392 = 1;}
+ case 87: /* conslist_opt ::= COMMA conslist */
+{yygotominor.yy0 = yymsp[-1].minor.yy0;}
break;
- case 59: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
-{yymsp[-1].minor.yy392 = 0;}
- break;
- case 61: /* tconscomma ::= COMMA */
+ case 90: /* tconscomma ::= COMMA */
{pParse->constraintName.n = 0;}
break;
- case 63: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
-{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy442,yymsp[0].minor.yy392,yymsp[-2].minor.yy392,0);}
+ case 93: /* tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf */
+{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy14,yymsp[0].minor.yy328,yymsp[-2].minor.yy328,0);}
break;
- case 64: /* tcons ::= UNIQUE LP sortlist RP onconf */
-{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy442,yymsp[0].minor.yy392,0,0,0,0);}
+ case 94: /* tcons ::= UNIQUE LP idxlist RP onconf */
+{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy14,yymsp[0].minor.yy328,0,0,0,0);}
break;
- case 65: /* tcons ::= CHECK LP expr RP onconf */
-{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy342.pExpr);}
+ case 95: /* tcons ::= CHECK LP expr RP onconf */
+{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy346.pExpr);}
break;
- case 66: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
+ case 96: /* tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt */
{
- sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy442, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy442, yymsp[-1].minor.yy392);
- sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy392);
+ sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy14, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[-1].minor.yy328);
+ sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy328);
}
break;
- case 68: /* onconf ::= */
- case 70: /* orconf ::= */ yytestcase(yyruleno==70);
-{yymsp[1].minor.yy392 = OE_Default;}
+ case 99: /* onconf ::= */
+{yygotominor.yy328 = OE_Default;}
+ break;
+ case 101: /* orconf ::= */
+{yygotominor.yy186 = OE_Default;}
break;
- case 69: /* onconf ::= ON CONFLICT resolvetype */
-{yymsp[-2].minor.yy392 = yymsp[0].minor.yy392;}
+ case 102: /* orconf ::= OR resolvetype */
+{yygotominor.yy186 = (u8)yymsp[0].minor.yy328;}
break;
- case 72: /* resolvetype ::= IGNORE */
-{yymsp[0].minor.yy392 = OE_Ignore;}
+ case 104: /* resolvetype ::= IGNORE */
+{yygotominor.yy328 = OE_Ignore;}
break;
- case 73: /* resolvetype ::= REPLACE */
- case 143: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==143);
-{yymsp[0].minor.yy392 = OE_Replace;}
+ case 105: /* resolvetype ::= REPLACE */
+{yygotominor.yy328 = OE_Replace;}
break;
- case 74: /* cmd ::= DROP TABLE ifexists fullname */
+ case 106: /* cmd ::= DROP TABLE ifexists fullname */
{
- sqlite3DropTable(pParse, yymsp[0].minor.yy347, 0, yymsp[-1].minor.yy392);
+ sqlite3DropTable(pParse, yymsp[0].minor.yy65, 0, yymsp[-1].minor.yy328);
}
break;
- case 77: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
+ case 109: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm AS select */
{
- sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy442, yymsp[0].minor.yy159, yymsp[-7].minor.yy392, yymsp[-5].minor.yy392);
+ sqlite3CreateView(pParse, &yymsp[-7].minor.yy0, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, yymsp[0].minor.yy3, yymsp[-6].minor.yy328, yymsp[-4].minor.yy328);
}
break;
- case 78: /* cmd ::= DROP VIEW ifexists fullname */
+ case 110: /* cmd ::= DROP VIEW ifexists fullname */
{
- sqlite3DropTable(pParse, yymsp[0].minor.yy347, 1, yymsp[-1].minor.yy392);
+ sqlite3DropTable(pParse, yymsp[0].minor.yy65, 1, yymsp[-1].minor.yy328);
}
break;
- case 79: /* cmd ::= select */
+ case 111: /* cmd ::= select */
{
SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0};
- sqlite3Select(pParse, yymsp[0].minor.yy159, &dest);
- sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy159);
+ sqlite3Select(pParse, yymsp[0].minor.yy3, &dest);
+ sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy3);
}
break;
- case 80: /* select ::= with selectnowith */
+ case 112: /* select ::= with selectnowith */
{
- Select *p = yymsp[0].minor.yy159;
+ Select *p = yymsp[0].minor.yy3;
if( p ){
- p->pWith = yymsp[-1].minor.yy331;
+ p->pWith = yymsp[-1].minor.yy59;
parserDoubleLinkSelect(pParse, p);
}else{
- sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy331);
+ sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy59);
}
- yymsp[-1].minor.yy159 = p; /*A-overwrites-W*/
+ yygotominor.yy3 = p;
}
break;
- case 81: /* selectnowith ::= selectnowith multiselect_op oneselect */
+ case 113: /* selectnowith ::= oneselect */
+ case 119: /* oneselect ::= values */ yytestcase(yyruleno==119);
+{yygotominor.yy3 = yymsp[0].minor.yy3;}
+ break;
+ case 114: /* selectnowith ::= selectnowith multiselect_op oneselect */
{
- Select *pRhs = yymsp[0].minor.yy159;
- Select *pLhs = yymsp[-2].minor.yy159;
+ Select *pRhs = yymsp[0].minor.yy3;
if( pRhs && pRhs->pPrior ){
SrcList *pFrom;
Token x;
@@ -133201,30 +125654,22 @@ static void yy_reduce(
pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0,0);
}
if( pRhs ){
- pRhs->op = (u8)yymsp[-1].minor.yy392;
- pRhs->pPrior = pLhs;
- if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue;
+ pRhs->op = (u8)yymsp[-1].minor.yy328;
+ pRhs->pPrior = yymsp[-2].minor.yy3;
pRhs->selFlags &= ~SF_MultiValue;
- if( yymsp[-1].minor.yy392!=TK_ALL ) pParse->hasCompound = 1;
+ if( yymsp[-1].minor.yy328!=TK_ALL ) pParse->hasCompound = 1;
}else{
- sqlite3SelectDelete(pParse->db, pLhs);
+ sqlite3SelectDelete(pParse->db, yymsp[-2].minor.yy3);
}
- yymsp[-2].minor.yy159 = pRhs;
+ yygotominor.yy3 = pRhs;
}
break;
- case 82: /* multiselect_op ::= UNION */
- case 84: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==84);
-{yymsp[0].minor.yy392 = yymsp[0].major; /*A-overwrites-OP*/}
+ case 116: /* multiselect_op ::= UNION ALL */
+{yygotominor.yy328 = TK_ALL;}
break;
- case 83: /* multiselect_op ::= UNION ALL */
-{yymsp[-1].minor.yy392 = TK_ALL;}
- break;
- case 85: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
+ case 118: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
{
-#if SELECTTRACE_ENABLED
- Token s = yymsp[-8].minor.yy0; /*A-overwrites-S*/
-#endif
- yymsp[-8].minor.yy159 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy442,yymsp[-5].minor.yy347,yymsp[-4].minor.yy122,yymsp[-3].minor.yy442,yymsp[-2].minor.yy122,yymsp[-1].minor.yy442,yymsp[-7].minor.yy392,yymsp[0].minor.yy64.pLimit,yymsp[0].minor.yy64.pOffset);
+ yygotominor.yy3 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy14,yymsp[-5].minor.yy65,yymsp[-4].minor.yy132,yymsp[-3].minor.yy14,yymsp[-2].minor.yy132,yymsp[-1].minor.yy14,yymsp[-7].minor.yy381,yymsp[0].minor.yy476.pLimit,yymsp[0].minor.yy476.pOffset);
#if SELECTTRACE_ENABLED
/* Populate the Select.zSelName[] string that is used to help with
** query planner debugging, to differentiate between multiple Select
@@ -133235,449 +125680,445 @@ static void yy_reduce(
** comment to be the zSelName value. Otherwise, the label is #N where
** is an integer that is incremented with each SELECT statement seen.
*/
- if( yymsp[-8].minor.yy159!=0 ){
- const char *z = s.z+6;
+ if( yygotominor.yy3!=0 ){
+ const char *z = yymsp[-8].minor.yy0.z+6;
int i;
- sqlite3_snprintf(sizeof(yymsp[-8].minor.yy159->zSelName), yymsp[-8].minor.yy159->zSelName, "#%d",
+ sqlite3_snprintf(sizeof(yygotominor.yy3->zSelName), yygotominor.yy3->zSelName, "#%d",
++pParse->nSelect);
while( z[0]==' ' ) z++;
if( z[0]=='/' && z[1]=='*' ){
z += 2;
while( z[0]==' ' ) z++;
for(i=0; sqlite3Isalnum(z[i]); i++){}
- sqlite3_snprintf(sizeof(yymsp[-8].minor.yy159->zSelName), yymsp[-8].minor.yy159->zSelName, "%.*s", i, z);
+ sqlite3_snprintf(sizeof(yygotominor.yy3->zSelName), yygotominor.yy3->zSelName, "%.*s", i, z);
}
}
#endif /* SELECTRACE_ENABLED */
}
break;
- case 86: /* values ::= VALUES LP nexprlist RP */
+ case 120: /* values ::= VALUES LP nexprlist RP */
{
- yymsp[-3].minor.yy159 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy442,0,0,0,0,0,SF_Values,0,0);
+ yygotominor.yy3 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy14,0,0,0,0,0,SF_Values,0,0);
}
break;
- case 87: /* values ::= values COMMA LP exprlist RP */
+ case 121: /* values ::= values COMMA LP exprlist RP */
{
- Select *pRight, *pLeft = yymsp[-4].minor.yy159;
- pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy442,0,0,0,0,0,SF_Values|SF_MultiValue,0,0);
+ Select *pRight, *pLeft = yymsp[-4].minor.yy3;
+ pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy14,0,0,0,0,0,SF_Values|SF_MultiValue,0,0);
if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue;
if( pRight ){
pRight->op = TK_ALL;
+ pLeft = yymsp[-4].minor.yy3;
pRight->pPrior = pLeft;
- yymsp[-4].minor.yy159 = pRight;
+ yygotominor.yy3 = pRight;
}else{
- yymsp[-4].minor.yy159 = pLeft;
+ yygotominor.yy3 = pLeft;
}
}
break;
- case 88: /* distinct ::= DISTINCT */
-{yymsp[0].minor.yy392 = SF_Distinct;}
+ case 122: /* distinct ::= DISTINCT */
+{yygotominor.yy381 = SF_Distinct;}
break;
- case 89: /* distinct ::= ALL */
-{yymsp[0].minor.yy392 = SF_All;}
+ case 123: /* distinct ::= ALL */
+ case 124: /* distinct ::= */ yytestcase(yyruleno==124);
+{yygotominor.yy381 = 0;}
break;
- case 91: /* sclp ::= */
- case 119: /* orderby_opt ::= */ yytestcase(yyruleno==119);
- case 126: /* groupby_opt ::= */ yytestcase(yyruleno==126);
- case 199: /* exprlist ::= */ yytestcase(yyruleno==199);
- case 205: /* eidlist_opt ::= */ yytestcase(yyruleno==205);
-{yymsp[1].minor.yy442 = 0;}
+ case 125: /* sclp ::= selcollist COMMA */
+ case 243: /* idxlist_opt ::= LP idxlist RP */ yytestcase(yyruleno==243);
+{yygotominor.yy14 = yymsp[-1].minor.yy14;}
break;
- case 92: /* selcollist ::= sclp expr as */
+ case 126: /* sclp ::= */
+ case 154: /* orderby_opt ::= */ yytestcase(yyruleno==154);
+ case 161: /* groupby_opt ::= */ yytestcase(yyruleno==161);
+ case 236: /* exprlist ::= */ yytestcase(yyruleno==236);
+ case 242: /* idxlist_opt ::= */ yytestcase(yyruleno==242);
+{yygotominor.yy14 = 0;}
+ break;
+ case 127: /* selcollist ::= sclp expr as */
{
- yymsp[-2].minor.yy442 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy442, yymsp[-1].minor.yy342.pExpr);
- if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-2].minor.yy442, &yymsp[0].minor.yy0, 1);
- sqlite3ExprListSetSpan(pParse,yymsp[-2].minor.yy442,&yymsp[-1].minor.yy342);
+ yygotominor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy14, yymsp[-1].minor.yy346.pExpr);
+ if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yygotominor.yy14, &yymsp[0].minor.yy0, 1);
+ sqlite3ExprListSetSpan(pParse,yygotominor.yy14,&yymsp[-1].minor.yy346);
}
break;
- case 93: /* selcollist ::= sclp STAR */
+ case 128: /* selcollist ::= sclp STAR */
{
- Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
- yymsp[-1].minor.yy442 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy442, p);
+ Expr *p = sqlite3Expr(pParse->db, TK_ALL, 0);
+ yygotominor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy14, p);
}
break;
- case 94: /* selcollist ::= sclp nm DOT STAR */
+ case 129: /* selcollist ::= sclp nm DOT STAR */
{
- Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0, &yymsp[0].minor.yy0);
+ Expr *pRight = sqlite3PExpr(pParse, TK_ALL, 0, 0, &yymsp[0].minor.yy0);
Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0);
Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
- yymsp[-3].minor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy442, pDot);
+ yygotominor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy14, pDot);
}
break;
- case 95: /* as ::= AS nm */
- case 106: /* dbnm ::= DOT nm */ yytestcase(yyruleno==106);
- case 219: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==219);
- case 220: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==220);
-{yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;}
+ case 132: /* as ::= */
+{yygotominor.yy0.n = 0;}
break;
- case 97: /* from ::= */
-{yymsp[1].minor.yy347 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy347));}
+ case 133: /* from ::= */
+{yygotominor.yy65 = sqlite3DbMallocZero(pParse->db, sizeof(*yygotominor.yy65));}
break;
- case 98: /* from ::= FROM seltablist */
+ case 134: /* from ::= FROM seltablist */
{
- yymsp[-1].minor.yy347 = yymsp[0].minor.yy347;
- sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy347);
+ yygotominor.yy65 = yymsp[0].minor.yy65;
+ sqlite3SrcListShiftJoinType(yygotominor.yy65);
}
break;
- case 99: /* stl_prefix ::= seltablist joinop */
+ case 135: /* stl_prefix ::= seltablist joinop */
{
- if( ALWAYS(yymsp[-1].minor.yy347 && yymsp[-1].minor.yy347->nSrc>0) ) yymsp[-1].minor.yy347->a[yymsp[-1].minor.yy347->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy392;
+ yygotominor.yy65 = yymsp[-1].minor.yy65;
+ if( ALWAYS(yygotominor.yy65 && yygotominor.yy65->nSrc>0) ) yygotominor.yy65->a[yygotominor.yy65->nSrc-1].jointype = (u8)yymsp[0].minor.yy328;
}
break;
- case 100: /* stl_prefix ::= */
-{yymsp[1].minor.yy347 = 0;}
+ case 136: /* stl_prefix ::= */
+{yygotominor.yy65 = 0;}
break;
- case 101: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
+ case 137: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
{
- yymsp[-6].minor.yy347 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy347,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy122,yymsp[0].minor.yy180);
- sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy347, &yymsp[-2].minor.yy0);
+ yygotominor.yy65 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy65,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy132,yymsp[0].minor.yy408);
+ sqlite3SrcListIndexedBy(pParse, yygotominor.yy65, &yymsp[-2].minor.yy0);
}
break;
- case 102: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
+ case 138: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
{
- yymsp[-8].minor.yy347 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy347,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy122,yymsp[0].minor.yy180);
- sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy347, yymsp[-4].minor.yy442);
-}
- break;
- case 103: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
-{
- yymsp[-6].minor.yy347 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy347,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy159,yymsp[-1].minor.yy122,yymsp[0].minor.yy180);
+ yygotominor.yy65 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy65,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy3,yymsp[-1].minor.yy132,yymsp[0].minor.yy408);
}
break;
- case 104: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
+ case 139: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
{
- if( yymsp[-6].minor.yy347==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy122==0 && yymsp[0].minor.yy180==0 ){
- yymsp[-6].minor.yy347 = yymsp[-4].minor.yy347;
- }else if( yymsp[-4].minor.yy347->nSrc==1 ){
- yymsp[-6].minor.yy347 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy347,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy122,yymsp[0].minor.yy180);
- if( yymsp[-6].minor.yy347 ){
- struct SrcList_item *pNew = &yymsp[-6].minor.yy347->a[yymsp[-6].minor.yy347->nSrc-1];
- struct SrcList_item *pOld = yymsp[-4].minor.yy347->a;
+ if( yymsp[-6].minor.yy65==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy132==0 && yymsp[0].minor.yy408==0 ){
+ yygotominor.yy65 = yymsp[-4].minor.yy65;
+ }else if( yymsp[-4].minor.yy65->nSrc==1 ){
+ yygotominor.yy65 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy65,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy132,yymsp[0].minor.yy408);
+ if( yygotominor.yy65 ){
+ struct SrcList_item *pNew = &yygotominor.yy65->a[yygotominor.yy65->nSrc-1];
+ struct SrcList_item *pOld = yymsp[-4].minor.yy65->a;
pNew->zName = pOld->zName;
pNew->zDatabase = pOld->zDatabase;
pNew->pSelect = pOld->pSelect;
pOld->zName = pOld->zDatabase = 0;
pOld->pSelect = 0;
}
- sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy347);
+ sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy65);
}else{
Select *pSubquery;
- sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy347);
- pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy347,0,0,0,0,SF_NestedFrom,0,0);
- yymsp[-6].minor.yy347 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy347,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy122,yymsp[0].minor.yy180);
+ sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy65);
+ pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy65,0,0,0,0,SF_NestedFrom,0,0);
+ yygotominor.yy65 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy65,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy132,yymsp[0].minor.yy408);
}
}
break;
- case 105: /* dbnm ::= */
- case 114: /* indexed_opt ::= */ yytestcase(yyruleno==114);
-{yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;}
- break;
- case 107: /* fullname ::= nm dbnm */
-{yymsp[-1].minor.yy347 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
+ case 140: /* dbnm ::= */
+ case 149: /* indexed_opt ::= */ yytestcase(yyruleno==149);
+{yygotominor.yy0.z=0; yygotominor.yy0.n=0;}
break;
- case 108: /* joinop ::= COMMA|JOIN */
-{ yymsp[0].minor.yy392 = JT_INNER; }
+ case 142: /* fullname ::= nm dbnm */
+{yygotominor.yy65 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
break;
- case 109: /* joinop ::= JOIN_KW JOIN */
-{yymsp[-1].minor.yy392 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/}
+ case 143: /* joinop ::= COMMA|JOIN */
+{ yygotominor.yy328 = JT_INNER; }
break;
- case 110: /* joinop ::= JOIN_KW nm JOIN */
-{yymsp[-2].minor.yy392 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
+ case 144: /* joinop ::= JOIN_KW JOIN */
+{ yygotominor.yy328 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); }
break;
- case 111: /* joinop ::= JOIN_KW nm nm JOIN */
-{yymsp[-3].minor.yy392 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
+ case 145: /* joinop ::= JOIN_KW nm JOIN */
+{ yygotominor.yy328 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); }
break;
- case 112: /* on_opt ::= ON expr */
- case 129: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==129);
- case 136: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==136);
- case 195: /* case_else ::= ELSE expr */ yytestcase(yyruleno==195);
-{yymsp[-1].minor.yy122 = yymsp[0].minor.yy342.pExpr;}
+ case 146: /* joinop ::= JOIN_KW nm nm JOIN */
+{ yygotominor.yy328 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); }
break;
- case 113: /* on_opt ::= */
- case 128: /* having_opt ::= */ yytestcase(yyruleno==128);
- case 135: /* where_opt ::= */ yytestcase(yyruleno==135);
- case 196: /* case_else ::= */ yytestcase(yyruleno==196);
- case 198: /* case_operand ::= */ yytestcase(yyruleno==198);
-{yymsp[1].minor.yy122 = 0;}
+ case 147: /* on_opt ::= ON expr */
+ case 164: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==164);
+ case 171: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==171);
+ case 231: /* case_else ::= ELSE expr */ yytestcase(yyruleno==231);
+ case 233: /* case_operand ::= expr */ yytestcase(yyruleno==233);
+{yygotominor.yy132 = yymsp[0].minor.yy346.pExpr;}
break;
- case 115: /* indexed_opt ::= INDEXED BY nm */
-{yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;}
+ case 148: /* on_opt ::= */
+ case 163: /* having_opt ::= */ yytestcase(yyruleno==163);
+ case 170: /* where_opt ::= */ yytestcase(yyruleno==170);
+ case 232: /* case_else ::= */ yytestcase(yyruleno==232);
+ case 234: /* case_operand ::= */ yytestcase(yyruleno==234);
+{yygotominor.yy132 = 0;}
break;
- case 116: /* indexed_opt ::= NOT INDEXED */
-{yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;}
+ case 151: /* indexed_opt ::= NOT INDEXED */
+{yygotominor.yy0.z=0; yygotominor.yy0.n=1;}
break;
- case 117: /* using_opt ::= USING LP idlist RP */
-{yymsp[-3].minor.yy180 = yymsp[-1].minor.yy180;}
+ case 152: /* using_opt ::= USING LP idlist RP */
+ case 180: /* inscollist_opt ::= LP idlist RP */ yytestcase(yyruleno==180);
+{yygotominor.yy408 = yymsp[-1].minor.yy408;}
break;
- case 118: /* using_opt ::= */
- case 144: /* idlist_opt ::= */ yytestcase(yyruleno==144);
-{yymsp[1].minor.yy180 = 0;}
+ case 153: /* using_opt ::= */
+ case 179: /* inscollist_opt ::= */ yytestcase(yyruleno==179);
+{yygotominor.yy408 = 0;}
break;
- case 120: /* orderby_opt ::= ORDER BY sortlist */
- case 127: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==127);
-{yymsp[-2].minor.yy442 = yymsp[0].minor.yy442;}
+ case 155: /* orderby_opt ::= ORDER BY sortlist */
+ case 162: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==162);
+ case 235: /* exprlist ::= nexprlist */ yytestcase(yyruleno==235);
+{yygotominor.yy14 = yymsp[0].minor.yy14;}
break;
- case 121: /* sortlist ::= sortlist COMMA expr sortorder */
+ case 156: /* sortlist ::= sortlist COMMA expr sortorder */
{
- yymsp[-3].minor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy442,yymsp[-1].minor.yy342.pExpr);
- sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy442,yymsp[0].minor.yy392);
+ yygotominor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy14,yymsp[-1].minor.yy346.pExpr);
+ if( yygotominor.yy14 ) yygotominor.yy14->a[yygotominor.yy14->nExpr-1].sortOrder = (u8)yymsp[0].minor.yy328;
}
break;
- case 122: /* sortlist ::= expr sortorder */
+ case 157: /* sortlist ::= expr sortorder */
{
- yymsp[-1].minor.yy442 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy342.pExpr); /*A-overwrites-Y*/
- sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy442,yymsp[0].minor.yy392);
+ yygotominor.yy14 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy346.pExpr);
+ if( yygotominor.yy14 && ALWAYS(yygotominor.yy14->a) ) yygotominor.yy14->a[0].sortOrder = (u8)yymsp[0].minor.yy328;
}
break;
- case 123: /* sortorder ::= ASC */
-{yymsp[0].minor.yy392 = SQLITE_SO_ASC;}
- break;
- case 124: /* sortorder ::= DESC */
-{yymsp[0].minor.yy392 = SQLITE_SO_DESC;}
+ case 158: /* sortorder ::= ASC */
+ case 160: /* sortorder ::= */ yytestcase(yyruleno==160);
+{yygotominor.yy328 = SQLITE_SO_ASC;}
break;
- case 125: /* sortorder ::= */
-{yymsp[1].minor.yy392 = SQLITE_SO_UNDEFINED;}
+ case 159: /* sortorder ::= DESC */
+{yygotominor.yy328 = SQLITE_SO_DESC;}
break;
- case 130: /* limit_opt ::= */
-{yymsp[1].minor.yy64.pLimit = 0; yymsp[1].minor.yy64.pOffset = 0;}
+ case 165: /* limit_opt ::= */
+{yygotominor.yy476.pLimit = 0; yygotominor.yy476.pOffset = 0;}
break;
- case 131: /* limit_opt ::= LIMIT expr */
-{yymsp[-1].minor.yy64.pLimit = yymsp[0].minor.yy342.pExpr; yymsp[-1].minor.yy64.pOffset = 0;}
+ case 166: /* limit_opt ::= LIMIT expr */
+{yygotominor.yy476.pLimit = yymsp[0].minor.yy346.pExpr; yygotominor.yy476.pOffset = 0;}
break;
- case 132: /* limit_opt ::= LIMIT expr OFFSET expr */
-{yymsp[-3].minor.yy64.pLimit = yymsp[-2].minor.yy342.pExpr; yymsp[-3].minor.yy64.pOffset = yymsp[0].minor.yy342.pExpr;}
+ case 167: /* limit_opt ::= LIMIT expr OFFSET expr */
+{yygotominor.yy476.pLimit = yymsp[-2].minor.yy346.pExpr; yygotominor.yy476.pOffset = yymsp[0].minor.yy346.pExpr;}
break;
- case 133: /* limit_opt ::= LIMIT expr COMMA expr */
-{yymsp[-3].minor.yy64.pOffset = yymsp[-2].minor.yy342.pExpr; yymsp[-3].minor.yy64.pLimit = yymsp[0].minor.yy342.pExpr;}
+ case 168: /* limit_opt ::= LIMIT expr COMMA expr */
+{yygotominor.yy476.pOffset = yymsp[-2].minor.yy346.pExpr; yygotominor.yy476.pLimit = yymsp[0].minor.yy346.pExpr;}
break;
- case 134: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */
+ case 169: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */
{
- sqlite3WithPush(pParse, yymsp[-5].minor.yy331, 1);
- sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy347, &yymsp[-1].minor.yy0);
- sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy347,yymsp[0].minor.yy122);
+ sqlite3WithPush(pParse, yymsp[-5].minor.yy59, 1);
+ sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy65, &yymsp[-1].minor.yy0);
+ sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy65,yymsp[0].minor.yy132);
}
break;
- case 137: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */
+ case 172: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */
{
- sqlite3WithPush(pParse, yymsp[-7].minor.yy331, 1);
- sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy347, &yymsp[-3].minor.yy0);
- sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy442,"set list");
- sqlite3Update(pParse,yymsp[-4].minor.yy347,yymsp[-1].minor.yy442,yymsp[0].minor.yy122,yymsp[-5].minor.yy392);
+ sqlite3WithPush(pParse, yymsp[-7].minor.yy59, 1);
+ sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy65, &yymsp[-3].minor.yy0);
+ sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy14,"set list");
+ sqlite3Update(pParse,yymsp[-4].minor.yy65,yymsp[-1].minor.yy14,yymsp[0].minor.yy132,yymsp[-5].minor.yy186);
}
break;
- case 138: /* setlist ::= setlist COMMA nm EQ expr */
+ case 173: /* setlist ::= setlist COMMA nm EQ expr */
{
- yymsp[-4].minor.yy442 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy442, yymsp[0].minor.yy342.pExpr);
- sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy442, &yymsp[-2].minor.yy0, 1);
+ yygotominor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy14, yymsp[0].minor.yy346.pExpr);
+ sqlite3ExprListSetName(pParse, yygotominor.yy14, &yymsp[-2].minor.yy0, 1);
}
break;
- case 139: /* setlist ::= nm EQ expr */
+ case 174: /* setlist ::= nm EQ expr */
{
- yylhsminor.yy442 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy342.pExpr);
- sqlite3ExprListSetName(pParse, yylhsminor.yy442, &yymsp[-2].minor.yy0, 1);
+ yygotominor.yy14 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy346.pExpr);
+ sqlite3ExprListSetName(pParse, yygotominor.yy14, &yymsp[-2].minor.yy0, 1);
}
- yymsp[-2].minor.yy442 = yylhsminor.yy442;
break;
- case 140: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */
+ case 175: /* cmd ::= with insert_cmd INTO fullname inscollist_opt select */
{
- sqlite3WithPush(pParse, yymsp[-5].minor.yy331, 1);
- sqlite3Insert(pParse, yymsp[-2].minor.yy347, yymsp[0].minor.yy159, yymsp[-1].minor.yy180, yymsp[-4].minor.yy392);
+ sqlite3WithPush(pParse, yymsp[-5].minor.yy59, 1);
+ sqlite3Insert(pParse, yymsp[-2].minor.yy65, yymsp[0].minor.yy3, yymsp[-1].minor.yy408, yymsp[-4].minor.yy186);
}
break;
- case 141: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */
+ case 176: /* cmd ::= with insert_cmd INTO fullname inscollist_opt DEFAULT VALUES */
{
- sqlite3WithPush(pParse, yymsp[-6].minor.yy331, 1);
- sqlite3Insert(pParse, yymsp[-3].minor.yy347, 0, yymsp[-2].minor.yy180, yymsp[-5].minor.yy392);
+ sqlite3WithPush(pParse, yymsp[-6].minor.yy59, 1);
+ sqlite3Insert(pParse, yymsp[-3].minor.yy65, 0, yymsp[-2].minor.yy408, yymsp[-5].minor.yy186);
}
break;
- case 145: /* idlist_opt ::= LP idlist RP */
-{yymsp[-2].minor.yy180 = yymsp[-1].minor.yy180;}
+ case 177: /* insert_cmd ::= INSERT orconf */
+{yygotominor.yy186 = yymsp[0].minor.yy186;}
break;
- case 146: /* idlist ::= idlist COMMA nm */
-{yymsp[-2].minor.yy180 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy180,&yymsp[0].minor.yy0);}
+ case 178: /* insert_cmd ::= REPLACE */
+{yygotominor.yy186 = OE_Replace;}
break;
- case 147: /* idlist ::= nm */
-{yymsp[0].minor.yy180 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
+ case 181: /* idlist ::= idlist COMMA nm */
+{yygotominor.yy408 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy408,&yymsp[0].minor.yy0);}
break;
- case 148: /* expr ::= LP expr RP */
-{spanSet(&yymsp[-2].minor.yy342,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ yymsp[-2].minor.yy342.pExpr = yymsp[-1].minor.yy342.pExpr;}
+ case 182: /* idlist ::= nm */
+{yygotominor.yy408 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0);}
break;
- case 149: /* term ::= NULL */
- case 154: /* term ::= INTEGER|FLOAT|BLOB */ yytestcase(yyruleno==154);
- case 155: /* term ::= STRING */ yytestcase(yyruleno==155);
-{spanExpr(&yymsp[0].minor.yy342,pParse,yymsp[0].major,yymsp[0].minor.yy0);/*A-overwrites-X*/}
+ case 183: /* expr ::= term */
+{yygotominor.yy346 = yymsp[0].minor.yy346;}
break;
- case 150: /* expr ::= ID|INDEXED */
- case 151: /* expr ::= JOIN_KW */ yytestcase(yyruleno==151);
-{spanExpr(&yymsp[0].minor.yy342,pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
+ case 184: /* expr ::= LP expr RP */
+{yygotominor.yy346.pExpr = yymsp[-1].minor.yy346.pExpr; spanSet(&yygotominor.yy346,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);}
break;
- case 152: /* expr ::= nm DOT nm */
+ case 185: /* term ::= NULL */
+ case 190: /* term ::= INTEGER|FLOAT|BLOB */ yytestcase(yyruleno==190);
+ case 191: /* term ::= STRING */ yytestcase(yyruleno==191);
+{spanExpr(&yygotominor.yy346, pParse, yymsp[0].major, &yymsp[0].minor.yy0);}
+ break;
+ case 186: /* expr ::= ID|INDEXED */
+ case 187: /* expr ::= JOIN_KW */ yytestcase(yyruleno==187);
+{spanExpr(&yygotominor.yy346, pParse, TK_ID, &yymsp[0].minor.yy0);}
+ break;
+ case 188: /* expr ::= nm DOT nm */
{
Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0);
Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy0);
- spanSet(&yymsp[-2].minor.yy342,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/
- yymsp[-2].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
+ yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
+ spanSet(&yygotominor.yy346,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
}
break;
- case 153: /* expr ::= nm DOT nm DOT nm */
+ case 189: /* expr ::= nm DOT nm DOT nm */
{
Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-4].minor.yy0);
Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0);
Expr *temp3 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy0);
Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0);
- spanSet(&yymsp[-4].minor.yy342,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/
- yymsp[-4].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0);
+ yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0);
+ spanSet(&yygotominor.yy346,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
}
break;
- case 156: /* expr ::= VARIABLE */
+ case 192: /* expr ::= VARIABLE */
{
- if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){
- spanExpr(&yymsp[0].minor.yy342, pParse, TK_VARIABLE, yymsp[0].minor.yy0);
- sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy342.pExpr);
- }else{
+ if( yymsp[0].minor.yy0.n>=2 && yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1]) ){
/* When doing a nested parse, one can include terms in an expression
** that look like this: #1 #2 ... These terms refer to registers
** in the virtual machine. #N is the N-th register. */
- Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/
- assert( t.n>=2 );
- spanSet(&yymsp[0].minor.yy342, &t, &t);
if( pParse->nested==0 ){
- sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
- yymsp[0].minor.yy342.pExpr = 0;
+ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &yymsp[0].minor.yy0);
+ yygotominor.yy346.pExpr = 0;
}else{
- yymsp[0].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, &t);
- if( yymsp[0].minor.yy342.pExpr ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy342.pExpr->iTable);
+ yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, &yymsp[0].minor.yy0);
+ if( yygotominor.yy346.pExpr ) sqlite3GetInt32(&yymsp[0].minor.yy0.z[1], &yygotominor.yy346.pExpr->iTable);
}
+ }else{
+ spanExpr(&yygotominor.yy346, pParse, TK_VARIABLE, &yymsp[0].minor.yy0);
+ sqlite3ExprAssignVarNumber(pParse, yygotominor.yy346.pExpr);
}
+ spanSet(&yygotominor.yy346, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
}
break;
- case 157: /* expr ::= expr COLLATE ID|STRING */
+ case 193: /* expr ::= expr COLLATE ID|STRING */
{
- yymsp[-2].minor.yy342.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy342.pExpr, &yymsp[0].minor.yy0, 1);
- yymsp[-2].minor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
+ yygotominor.yy346.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy346.pExpr, &yymsp[0].minor.yy0, 1);
+ yygotominor.yy346.zStart = yymsp[-2].minor.yy346.zStart;
+ yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 158: /* expr ::= CAST LP expr AS typetoken RP */
+ case 194: /* expr ::= CAST LP expr AS typetoken RP */
{
- spanSet(&yymsp[-5].minor.yy342,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/
- yymsp[-5].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_CAST, yymsp[-3].minor.yy342.pExpr, 0, &yymsp[-1].minor.yy0);
+ yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_CAST, yymsp[-3].minor.yy346.pExpr, 0, &yymsp[-1].minor.yy0);
+ spanSet(&yygotominor.yy346,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0);
}
break;
- case 159: /* expr ::= ID|INDEXED LP distinct exprlist RP */
+ case 195: /* expr ::= ID|INDEXED LP distinct exprlist RP */
{
- if( yymsp[-1].minor.yy442 && yymsp[-1].minor.yy442->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
+ if( yymsp[-1].minor.yy14 && yymsp[-1].minor.yy14->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0);
}
- yylhsminor.yy342.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy442, &yymsp[-4].minor.yy0);
- spanSet(&yylhsminor.yy342,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
- if( yymsp[-2].minor.yy392==SF_Distinct && yylhsminor.yy342.pExpr ){
- yylhsminor.yy342.pExpr->flags |= EP_Distinct;
+ yygotominor.yy346.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy14, &yymsp[-4].minor.yy0);
+ spanSet(&yygotominor.yy346,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
+ if( yymsp[-2].minor.yy381 && yygotominor.yy346.pExpr ){
+ yygotominor.yy346.pExpr->flags |= EP_Distinct;
}
}
- yymsp[-4].minor.yy342 = yylhsminor.yy342;
break;
- case 160: /* expr ::= ID|INDEXED LP STAR RP */
+ case 196: /* expr ::= ID|INDEXED LP STAR RP */
{
- yylhsminor.yy342.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0);
- spanSet(&yylhsminor.yy342,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
+ yygotominor.yy346.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0);
+ spanSet(&yygotominor.yy346,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
}
- yymsp[-3].minor.yy342 = yylhsminor.yy342;
break;
- case 161: /* term ::= CTIME_KW */
+ case 197: /* term ::= CTIME_KW */
{
- yylhsminor.yy342.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0);
- spanSet(&yylhsminor.yy342, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
+ yygotominor.yy346.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0);
+ spanSet(&yygotominor.yy346, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
}
- yymsp[0].minor.yy342 = yylhsminor.yy342;
break;
- case 162: /* expr ::= expr AND expr */
- case 163: /* expr ::= expr OR expr */ yytestcase(yyruleno==163);
- case 164: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==164);
- case 165: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==165);
- case 166: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==166);
- case 167: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==167);
- case 168: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==168);
- case 169: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==169);
-{spanBinaryExpr(pParse,yymsp[-1].major,&yymsp[-2].minor.yy342,&yymsp[0].minor.yy342);}
+ case 198: /* expr ::= expr AND expr */
+ case 199: /* expr ::= expr OR expr */ yytestcase(yyruleno==199);
+ case 200: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==200);
+ case 201: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==201);
+ case 202: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==202);
+ case 203: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==203);
+ case 204: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==204);
+ case 205: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==205);
+{spanBinaryExpr(&yygotominor.yy346,pParse,yymsp[-1].major,&yymsp[-2].minor.yy346,&yymsp[0].minor.yy346);}
break;
- case 170: /* likeop ::= LIKE_KW|MATCH */
-{yymsp[0].minor.yy318.eOperator = yymsp[0].minor.yy0; yymsp[0].minor.yy318.bNot = 0;/*A-overwrites-X*/}
+ case 206: /* likeop ::= LIKE_KW|MATCH */
+{yygotominor.yy96.eOperator = yymsp[0].minor.yy0; yygotominor.yy96.bNot = 0;}
break;
- case 171: /* likeop ::= NOT LIKE_KW|MATCH */
-{yymsp[-1].minor.yy318.eOperator = yymsp[0].minor.yy0; yymsp[-1].minor.yy318.bNot = 1;}
+ case 207: /* likeop ::= NOT LIKE_KW|MATCH */
+{yygotominor.yy96.eOperator = yymsp[0].minor.yy0; yygotominor.yy96.bNot = 1;}
break;
- case 172: /* expr ::= expr likeop expr */
+ case 208: /* expr ::= expr likeop expr */
{
ExprList *pList;
- pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy342.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy342.pExpr);
- yymsp[-2].minor.yy342.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy318.eOperator);
- exprNot(pParse, yymsp[-1].minor.yy318.bNot, &yymsp[-2].minor.yy342);
- yymsp[-2].minor.yy342.zEnd = yymsp[0].minor.yy342.zEnd;
- if( yymsp[-2].minor.yy342.pExpr ) yymsp[-2].minor.yy342.pExpr->flags |= EP_InfixFunc;
+ pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy346.pExpr);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy346.pExpr);
+ yygotominor.yy346.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy96.eOperator);
+ if( yymsp[-1].minor.yy96.bNot ) yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy346.pExpr, 0, 0);
+ yygotominor.yy346.zStart = yymsp[-2].minor.yy346.zStart;
+ yygotominor.yy346.zEnd = yymsp[0].minor.yy346.zEnd;
+ if( yygotominor.yy346.pExpr ) yygotominor.yy346.pExpr->flags |= EP_InfixFunc;
}
break;
- case 173: /* expr ::= expr likeop expr ESCAPE expr */
+ case 209: /* expr ::= expr likeop expr ESCAPE expr */
{
ExprList *pList;
- pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy342.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy342.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy342.pExpr);
- yymsp[-4].minor.yy342.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy318.eOperator);
- exprNot(pParse, yymsp[-3].minor.yy318.bNot, &yymsp[-4].minor.yy342);
- yymsp[-4].minor.yy342.zEnd = yymsp[0].minor.yy342.zEnd;
- if( yymsp[-4].minor.yy342.pExpr ) yymsp[-4].minor.yy342.pExpr->flags |= EP_InfixFunc;
+ pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy346.pExpr);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy346.pExpr);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy346.pExpr);
+ yygotominor.yy346.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy96.eOperator);
+ if( yymsp[-3].minor.yy96.bNot ) yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy346.pExpr, 0, 0);
+ yygotominor.yy346.zStart = yymsp[-4].minor.yy346.zStart;
+ yygotominor.yy346.zEnd = yymsp[0].minor.yy346.zEnd;
+ if( yygotominor.yy346.pExpr ) yygotominor.yy346.pExpr->flags |= EP_InfixFunc;
}
break;
- case 174: /* expr ::= expr ISNULL|NOTNULL */
-{spanUnaryPostfix(pParse,yymsp[0].major,&yymsp[-1].minor.yy342,&yymsp[0].minor.yy0);}
+ case 210: /* expr ::= expr ISNULL|NOTNULL */
+{spanUnaryPostfix(&yygotominor.yy346,pParse,yymsp[0].major,&yymsp[-1].minor.yy346,&yymsp[0].minor.yy0);}
break;
- case 175: /* expr ::= expr NOT NULL */
-{spanUnaryPostfix(pParse,TK_NOTNULL,&yymsp[-2].minor.yy342,&yymsp[0].minor.yy0);}
+ case 211: /* expr ::= expr NOT NULL */
+{spanUnaryPostfix(&yygotominor.yy346,pParse,TK_NOTNULL,&yymsp[-2].minor.yy346,&yymsp[0].minor.yy0);}
break;
- case 176: /* expr ::= expr IS expr */
+ case 212: /* expr ::= expr IS expr */
{
- spanBinaryExpr(pParse,TK_IS,&yymsp[-2].minor.yy342,&yymsp[0].minor.yy342);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy342.pExpr, yymsp[-2].minor.yy342.pExpr, TK_ISNULL);
+ spanBinaryExpr(&yygotominor.yy346,pParse,TK_IS,&yymsp[-2].minor.yy346,&yymsp[0].minor.yy346);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy346.pExpr, yygotominor.yy346.pExpr, TK_ISNULL);
}
break;
- case 177: /* expr ::= expr IS NOT expr */
+ case 213: /* expr ::= expr IS NOT expr */
{
- spanBinaryExpr(pParse,TK_ISNOT,&yymsp[-3].minor.yy342,&yymsp[0].minor.yy342);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy342.pExpr, yymsp[-3].minor.yy342.pExpr, TK_NOTNULL);
+ spanBinaryExpr(&yygotominor.yy346,pParse,TK_ISNOT,&yymsp[-3].minor.yy346,&yymsp[0].minor.yy346);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy346.pExpr, yygotominor.yy346.pExpr, TK_NOTNULL);
}
break;
- case 178: /* expr ::= NOT expr */
- case 179: /* expr ::= BITNOT expr */ yytestcase(yyruleno==179);
-{spanUnaryPrefix(&yymsp[-1].minor.yy342,pParse,yymsp[-1].major,&yymsp[0].minor.yy342,&yymsp[-1].minor.yy0);/*A-overwrites-B*/}
- break;
- case 180: /* expr ::= MINUS expr */
-{spanUnaryPrefix(&yymsp[-1].minor.yy342,pParse,TK_UMINUS,&yymsp[0].minor.yy342,&yymsp[-1].minor.yy0);/*A-overwrites-B*/}
+ case 214: /* expr ::= NOT expr */
+ case 215: /* expr ::= BITNOT expr */ yytestcase(yyruleno==215);
+{spanUnaryPrefix(&yygotominor.yy346,pParse,yymsp[-1].major,&yymsp[0].minor.yy346,&yymsp[-1].minor.yy0);}
break;
- case 181: /* expr ::= PLUS expr */
-{spanUnaryPrefix(&yymsp[-1].minor.yy342,pParse,TK_UPLUS,&yymsp[0].minor.yy342,&yymsp[-1].minor.yy0);/*A-overwrites-B*/}
+ case 216: /* expr ::= MINUS expr */
+{spanUnaryPrefix(&yygotominor.yy346,pParse,TK_UMINUS,&yymsp[0].minor.yy346,&yymsp[-1].minor.yy0);}
break;
- case 182: /* between_op ::= BETWEEN */
- case 185: /* in_op ::= IN */ yytestcase(yyruleno==185);
-{yymsp[0].minor.yy392 = 0;}
+ case 217: /* expr ::= PLUS expr */
+{spanUnaryPrefix(&yygotominor.yy346,pParse,TK_UPLUS,&yymsp[0].minor.yy346,&yymsp[-1].minor.yy0);}
break;
- case 184: /* expr ::= expr between_op expr AND expr */
+ case 220: /* expr ::= expr between_op expr AND expr */
{
- ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy342.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy342.pExpr);
- yymsp[-4].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy342.pExpr, 0, 0);
- if( yymsp[-4].minor.yy342.pExpr ){
- yymsp[-4].minor.yy342.pExpr->x.pList = pList;
+ ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy346.pExpr);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy346.pExpr);
+ yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy346.pExpr, 0, 0);
+ if( yygotominor.yy346.pExpr ){
+ yygotominor.yy346.pExpr->x.pList = pList;
}else{
sqlite3ExprListDelete(pParse->db, pList);
}
- exprNot(pParse, yymsp[-3].minor.yy392, &yymsp[-4].minor.yy342);
- yymsp[-4].minor.yy342.zEnd = yymsp[0].minor.yy342.zEnd;
+ if( yymsp[-3].minor.yy328 ) yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy346.pExpr, 0, 0);
+ yygotominor.yy346.zStart = yymsp[-4].minor.yy346.zStart;
+ yygotominor.yy346.zEnd = yymsp[0].minor.yy346.zEnd;
}
break;
- case 187: /* expr ::= expr in_op LP exprlist RP */
+ case 223: /* expr ::= expr in_op LP exprlist RP */
{
- if( yymsp[-1].minor.yy442==0 ){
+ if( yymsp[-1].minor.yy14==0 ){
/* Expressions of the form
**
** expr1 IN ()
@@ -133686,9 +126127,9 @@ static void yy_reduce(
** simplify to constants 0 (false) and 1 (true), respectively,
** regardless of the value of expr1.
*/
- sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy342.pExpr);
- yymsp[-4].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[yymsp[-3].minor.yy392]);
- }else if( yymsp[-1].minor.yy442->nExpr==1 ){
+ yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[yymsp[-3].minor.yy328]);
+ sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy346.pExpr);
+ }else if( yymsp[-1].minor.yy14->nExpr==1 ){
/* Expressions of the form:
**
** expr1 IN (?1)
@@ -133705,413 +126146,433 @@ static void yy_reduce(
** affinity or the collating sequence to use for comparison. Otherwise,
** the semantics would be subtly different from IN or NOT IN.
*/
- Expr *pRHS = yymsp[-1].minor.yy442->a[0].pExpr;
- yymsp[-1].minor.yy442->a[0].pExpr = 0;
- sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy442);
+ Expr *pRHS = yymsp[-1].minor.yy14->a[0].pExpr;
+ yymsp[-1].minor.yy14->a[0].pExpr = 0;
+ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
/* pRHS cannot be NULL because a malloc error would have been detected
** before now and control would have never reached this point */
if( ALWAYS(pRHS) ){
pRHS->flags &= ~EP_Collate;
pRHS->flags |= EP_Generic;
}
- yymsp[-4].minor.yy342.pExpr = sqlite3PExpr(pParse, yymsp[-3].minor.yy392 ? TK_NE : TK_EQ, yymsp[-4].minor.yy342.pExpr, pRHS, 0);
+ yygotominor.yy346.pExpr = sqlite3PExpr(pParse, yymsp[-3].minor.yy328 ? TK_NE : TK_EQ, yymsp[-4].minor.yy346.pExpr, pRHS, 0);
}else{
- yymsp[-4].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy342.pExpr, 0, 0);
- if( yymsp[-4].minor.yy342.pExpr ){
- yymsp[-4].minor.yy342.pExpr->x.pList = yymsp[-1].minor.yy442;
- sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy342.pExpr);
+ yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy346.pExpr, 0, 0);
+ if( yygotominor.yy346.pExpr ){
+ yygotominor.yy346.pExpr->x.pList = yymsp[-1].minor.yy14;
+ sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
}else{
- sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy442);
+ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14);
}
- exprNot(pParse, yymsp[-3].minor.yy392, &yymsp[-4].minor.yy342);
+ if( yymsp[-3].minor.yy328 ) yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy346.pExpr, 0, 0);
}
- yymsp[-4].minor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
+ yygotominor.yy346.zStart = yymsp[-4].minor.yy346.zStart;
+ yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 188: /* expr ::= LP select RP */
+ case 224: /* expr ::= LP select RP */
{
- spanSet(&yymsp[-2].minor.yy342,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/
- yymsp[-2].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
- sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy342.pExpr, yymsp[-1].minor.yy159);
+ yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
+ if( yygotominor.yy346.pExpr ){
+ yygotominor.yy346.pExpr->x.pSelect = yymsp[-1].minor.yy3;
+ ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect|EP_Subquery);
+ sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
+ }else{
+ sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy3);
+ }
+ yygotominor.yy346.zStart = yymsp[-2].minor.yy0.z;
+ yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 189: /* expr ::= expr in_op LP select RP */
+ case 225: /* expr ::= expr in_op LP select RP */
{
- yymsp[-4].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy342.pExpr, 0, 0);
- sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy342.pExpr, yymsp[-1].minor.yy159);
- exprNot(pParse, yymsp[-3].minor.yy392, &yymsp[-4].minor.yy342);
- yymsp[-4].minor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
+ yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy346.pExpr, 0, 0);
+ if( yygotominor.yy346.pExpr ){
+ yygotominor.yy346.pExpr->x.pSelect = yymsp[-1].minor.yy3;
+ ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect|EP_Subquery);
+ sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
+ }else{
+ sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy3);
+ }
+ if( yymsp[-3].minor.yy328 ) yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy346.pExpr, 0, 0);
+ yygotominor.yy346.zStart = yymsp[-4].minor.yy346.zStart;
+ yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 190: /* expr ::= expr in_op nm dbnm */
+ case 226: /* expr ::= expr in_op nm dbnm */
{
SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);
- Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
- yymsp[-3].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-3].minor.yy342.pExpr, 0, 0);
- sqlite3PExprAddSelect(pParse, yymsp[-3].minor.yy342.pExpr, pSelect);
- exprNot(pParse, yymsp[-2].minor.yy392, &yymsp[-3].minor.yy342);
- yymsp[-3].minor.yy342.zEnd = yymsp[0].minor.yy0.z ? &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] : &yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n];
+ yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-3].minor.yy346.pExpr, 0, 0);
+ if( yygotominor.yy346.pExpr ){
+ yygotominor.yy346.pExpr->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
+ ExprSetProperty(yygotominor.yy346.pExpr, EP_xIsSelect|EP_Subquery);
+ sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
+ }else{
+ sqlite3SrcListDelete(pParse->db, pSrc);
+ }
+ if( yymsp[-2].minor.yy328 ) yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_NOT, yygotominor.yy346.pExpr, 0, 0);
+ yygotominor.yy346.zStart = yymsp[-3].minor.yy346.zStart;
+ yygotominor.yy346.zEnd = yymsp[0].minor.yy0.z ? &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] : &yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n];
}
break;
- case 191: /* expr ::= EXISTS LP select RP */
+ case 227: /* expr ::= EXISTS LP select RP */
{
- Expr *p;
- spanSet(&yymsp[-3].minor.yy342,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/
- p = yymsp[-3].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
- sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy159);
+ Expr *p = yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
+ if( p ){
+ p->x.pSelect = yymsp[-1].minor.yy3;
+ ExprSetProperty(p, EP_xIsSelect|EP_Subquery);
+ sqlite3ExprSetHeightAndFlags(pParse, p);
+ }else{
+ sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy3);
+ }
+ yygotominor.yy346.zStart = yymsp[-3].minor.yy0.z;
+ yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 192: /* expr ::= CASE case_operand case_exprlist case_else END */
+ case 228: /* expr ::= CASE case_operand case_exprlist case_else END */
{
- spanSet(&yymsp[-4].minor.yy342,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-C*/
- yymsp[-4].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy122, 0, 0);
- if( yymsp[-4].minor.yy342.pExpr ){
- yymsp[-4].minor.yy342.pExpr->x.pList = yymsp[-1].minor.yy122 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy442,yymsp[-1].minor.yy122) : yymsp[-2].minor.yy442;
- sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy342.pExpr);
+ yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy132, 0, 0);
+ if( yygotominor.yy346.pExpr ){
+ yygotominor.yy346.pExpr->x.pList = yymsp[-1].minor.yy132 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[-1].minor.yy132) : yymsp[-2].minor.yy14;
+ sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy346.pExpr);
}else{
- sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy442);
- sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy122);
+ sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy14);
+ sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy132);
}
+ yygotominor.yy346.zStart = yymsp[-4].minor.yy0.z;
+ yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 193: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ case 229: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
{
- yymsp[-4].minor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy442, yymsp[-2].minor.yy342.pExpr);
- yymsp[-4].minor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy442, yymsp[0].minor.yy342.pExpr);
+ yygotominor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, yymsp[-2].minor.yy346.pExpr);
+ yygotominor.yy14 = sqlite3ExprListAppend(pParse,yygotominor.yy14, yymsp[0].minor.yy346.pExpr);
}
break;
- case 194: /* case_exprlist ::= WHEN expr THEN expr */
+ case 230: /* case_exprlist ::= WHEN expr THEN expr */
{
- yymsp[-3].minor.yy442 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy342.pExpr);
- yymsp[-3].minor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy442, yymsp[0].minor.yy342.pExpr);
+ yygotominor.yy14 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy346.pExpr);
+ yygotominor.yy14 = sqlite3ExprListAppend(pParse,yygotominor.yy14, yymsp[0].minor.yy346.pExpr);
}
break;
- case 197: /* case_operand ::= expr */
-{yymsp[0].minor.yy122 = yymsp[0].minor.yy342.pExpr; /*A-overwrites-X*/}
- break;
- case 200: /* nexprlist ::= nexprlist COMMA expr */
-{yymsp[-2].minor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy442,yymsp[0].minor.yy342.pExpr);}
+ case 237: /* nexprlist ::= nexprlist COMMA expr */
+{yygotominor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[0].minor.yy346.pExpr);}
break;
- case 201: /* nexprlist ::= expr */
-{yymsp[0].minor.yy442 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy342.pExpr); /*A-overwrites-Y*/}
+ case 238: /* nexprlist ::= expr */
+{yygotominor.yy14 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy346.pExpr);}
break;
- case 202: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+ case 239: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP where_opt */
{
sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0,
- sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy442, yymsp[-10].minor.yy392,
- &yymsp[-11].minor.yy0, yymsp[0].minor.yy122, SQLITE_SO_ASC, yymsp[-8].minor.yy392);
+ sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy14, yymsp[-10].minor.yy328,
+ &yymsp[-11].minor.yy0, yymsp[0].minor.yy132, SQLITE_SO_ASC, yymsp[-8].minor.yy328);
}
break;
- case 203: /* uniqueflag ::= UNIQUE */
- case 244: /* raisetype ::= ABORT */ yytestcase(yyruleno==244);
-{yymsp[0].minor.yy392 = OE_Abort;}
- break;
- case 204: /* uniqueflag ::= */
-{yymsp[1].minor.yy392 = OE_None;}
+ case 240: /* uniqueflag ::= UNIQUE */
+ case 291: /* raisetype ::= ABORT */ yytestcase(yyruleno==291);
+{yygotominor.yy328 = OE_Abort;}
break;
- case 206: /* eidlist_opt ::= LP eidlist RP */
-{yymsp[-2].minor.yy442 = yymsp[-1].minor.yy442;}
+ case 241: /* uniqueflag ::= */
+{yygotominor.yy328 = OE_None;}
break;
- case 207: /* eidlist ::= eidlist COMMA nm collate sortorder */
+ case 244: /* idxlist ::= idxlist COMMA nm collate sortorder */
{
- yymsp[-4].minor.yy442 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy442, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy392, yymsp[0].minor.yy392);
+ Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &yymsp[-1].minor.yy0, 1);
+ yygotominor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, p);
+ sqlite3ExprListSetName(pParse,yygotominor.yy14,&yymsp[-2].minor.yy0,1);
+ sqlite3ExprListCheckLength(pParse, yygotominor.yy14, "index");
+ if( yygotominor.yy14 ) yygotominor.yy14->a[yygotominor.yy14->nExpr-1].sortOrder = (u8)yymsp[0].minor.yy328;
}
break;
- case 208: /* eidlist ::= nm collate sortorder */
+ case 245: /* idxlist ::= nm collate sortorder */
{
- yymsp[-2].minor.yy442 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy392, yymsp[0].minor.yy392); /*A-overwrites-Y*/
+ Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &yymsp[-1].minor.yy0, 1);
+ yygotominor.yy14 = sqlite3ExprListAppend(pParse,0, p);
+ sqlite3ExprListSetName(pParse, yygotominor.yy14, &yymsp[-2].minor.yy0, 1);
+ sqlite3ExprListCheckLength(pParse, yygotominor.yy14, "index");
+ if( yygotominor.yy14 ) yygotominor.yy14->a[yygotominor.yy14->nExpr-1].sortOrder = (u8)yymsp[0].minor.yy328;
}
break;
- case 211: /* cmd ::= DROP INDEX ifexists fullname */
-{sqlite3DropIndex(pParse, yymsp[0].minor.yy347, yymsp[-1].minor.yy392);}
+ case 246: /* collate ::= */
+{yygotominor.yy0.z = 0; yygotominor.yy0.n = 0;}
break;
- case 212: /* cmd ::= VACUUM */
- case 213: /* cmd ::= VACUUM nm */ yytestcase(yyruleno==213);
+ case 248: /* cmd ::= DROP INDEX ifexists fullname */
+{sqlite3DropIndex(pParse, yymsp[0].minor.yy65, yymsp[-1].minor.yy328);}
+ break;
+ case 249: /* cmd ::= VACUUM */
+ case 250: /* cmd ::= VACUUM nm */ yytestcase(yyruleno==250);
{sqlite3Vacuum(pParse);}
break;
- case 214: /* cmd ::= PRAGMA nm dbnm */
+ case 251: /* cmd ::= PRAGMA nm dbnm */
{sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);}
break;
- case 215: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
+ case 252: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);}
break;
- case 216: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ case 253: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);}
break;
- case 217: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
+ case 254: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);}
break;
- case 218: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
+ case 255: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);}
break;
- case 221: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+ case 264: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
{
Token all;
all.z = yymsp[-3].minor.yy0.z;
all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n;
- sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy327, &all);
+ sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy473, &all);
}
break;
- case 222: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+ case 265: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
{
- sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy392, yymsp[-4].minor.yy410.a, yymsp[-4].minor.yy410.b, yymsp[-2].minor.yy347, yymsp[0].minor.yy122, yymsp[-10].minor.yy392, yymsp[-8].minor.yy392);
- yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/
+ sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy328, yymsp[-4].minor.yy378.a, yymsp[-4].minor.yy378.b, yymsp[-2].minor.yy65, yymsp[0].minor.yy132, yymsp[-10].minor.yy328, yymsp[-8].minor.yy328);
+ yygotominor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0);
}
break;
- case 223: /* trigger_time ::= BEFORE */
-{ yymsp[0].minor.yy392 = TK_BEFORE; }
- break;
- case 224: /* trigger_time ::= AFTER */
-{ yymsp[0].minor.yy392 = TK_AFTER; }
+ case 266: /* trigger_time ::= BEFORE */
+ case 269: /* trigger_time ::= */ yytestcase(yyruleno==269);
+{ yygotominor.yy328 = TK_BEFORE; }
break;
- case 225: /* trigger_time ::= INSTEAD OF */
-{ yymsp[-1].minor.yy392 = TK_INSTEAD;}
+ case 267: /* trigger_time ::= AFTER */
+{ yygotominor.yy328 = TK_AFTER; }
break;
- case 226: /* trigger_time ::= */
-{ yymsp[1].minor.yy392 = TK_BEFORE; }
+ case 268: /* trigger_time ::= INSTEAD OF */
+{ yygotominor.yy328 = TK_INSTEAD;}
break;
- case 227: /* trigger_event ::= DELETE|INSERT */
- case 228: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==228);
-{yymsp[0].minor.yy410.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy410.b = 0;}
+ case 270: /* trigger_event ::= DELETE|INSERT */
+ case 271: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==271);
+{yygotominor.yy378.a = yymsp[0].major; yygotominor.yy378.b = 0;}
break;
- case 229: /* trigger_event ::= UPDATE OF idlist */
-{yymsp[-2].minor.yy410.a = TK_UPDATE; yymsp[-2].minor.yy410.b = yymsp[0].minor.yy180;}
+ case 272: /* trigger_event ::= UPDATE OF idlist */
+{yygotominor.yy378.a = TK_UPDATE; yygotominor.yy378.b = yymsp[0].minor.yy408;}
break;
- case 230: /* when_clause ::= */
- case 249: /* key_opt ::= */ yytestcase(yyruleno==249);
-{ yymsp[1].minor.yy122 = 0; }
+ case 275: /* when_clause ::= */
+ case 296: /* key_opt ::= */ yytestcase(yyruleno==296);
+{ yygotominor.yy132 = 0; }
break;
- case 231: /* when_clause ::= WHEN expr */
- case 250: /* key_opt ::= KEY expr */ yytestcase(yyruleno==250);
-{ yymsp[-1].minor.yy122 = yymsp[0].minor.yy342.pExpr; }
+ case 276: /* when_clause ::= WHEN expr */
+ case 297: /* key_opt ::= KEY expr */ yytestcase(yyruleno==297);
+{ yygotominor.yy132 = yymsp[0].minor.yy346.pExpr; }
break;
- case 232: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+ case 277: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
{
- assert( yymsp[-2].minor.yy327!=0 );
- yymsp[-2].minor.yy327->pLast->pNext = yymsp[-1].minor.yy327;
- yymsp[-2].minor.yy327->pLast = yymsp[-1].minor.yy327;
+ assert( yymsp[-2].minor.yy473!=0 );
+ yymsp[-2].minor.yy473->pLast->pNext = yymsp[-1].minor.yy473;
+ yymsp[-2].minor.yy473->pLast = yymsp[-1].minor.yy473;
+ yygotominor.yy473 = yymsp[-2].minor.yy473;
}
break;
- case 233: /* trigger_cmd_list ::= trigger_cmd SEMI */
+ case 278: /* trigger_cmd_list ::= trigger_cmd SEMI */
{
- assert( yymsp[-1].minor.yy327!=0 );
- yymsp[-1].minor.yy327->pLast = yymsp[-1].minor.yy327;
+ assert( yymsp[-1].minor.yy473!=0 );
+ yymsp[-1].minor.yy473->pLast = yymsp[-1].minor.yy473;
+ yygotominor.yy473 = yymsp[-1].minor.yy473;
}
break;
- case 234: /* trnm ::= nm DOT nm */
+ case 280: /* trnm ::= nm DOT nm */
{
- yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;
+ yygotominor.yy0 = yymsp[0].minor.yy0;
sqlite3ErrorMsg(pParse,
"qualified table names are not allowed on INSERT, UPDATE, and DELETE "
"statements within triggers");
}
break;
- case 235: /* tridxby ::= INDEXED BY nm */
+ case 282: /* tridxby ::= INDEXED BY nm */
{
sqlite3ErrorMsg(pParse,
"the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
- case 236: /* tridxby ::= NOT INDEXED */
+ case 283: /* tridxby ::= NOT INDEXED */
{
sqlite3ErrorMsg(pParse,
"the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
- case 237: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */
-{yymsp[-6].minor.yy327 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy442, yymsp[0].minor.yy122, yymsp[-5].minor.yy392);}
+ case 284: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */
+{ yygotominor.yy473 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy14, yymsp[0].minor.yy132, yymsp[-5].minor.yy186); }
break;
- case 238: /* trigger_cmd ::= insert_cmd INTO trnm idlist_opt select */
-{yymsp[-4].minor.yy327 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy180, yymsp[0].minor.yy159, yymsp[-4].minor.yy392);/*A-overwrites-R*/}
+ case 285: /* trigger_cmd ::= insert_cmd INTO trnm inscollist_opt select */
+{yygotominor.yy473 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy408, yymsp[0].minor.yy3, yymsp[-4].minor.yy186);}
break;
- case 239: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */
-{yymsp[-4].minor.yy327 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy122);}
+ case 286: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */
+{yygotominor.yy473 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy132);}
break;
- case 240: /* trigger_cmd ::= select */
-{yymsp[0].minor.yy327 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy159); /*A-overwrites-X*/}
+ case 287: /* trigger_cmd ::= select */
+{yygotominor.yy473 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy3); }
break;
- case 241: /* expr ::= RAISE LP IGNORE RP */
+ case 288: /* expr ::= RAISE LP IGNORE RP */
{
- spanSet(&yymsp[-3].minor.yy342,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/
- yymsp[-3].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0);
- if( yymsp[-3].minor.yy342.pExpr ){
- yymsp[-3].minor.yy342.pExpr->affinity = OE_Ignore;
+ yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0);
+ if( yygotominor.yy346.pExpr ){
+ yygotominor.yy346.pExpr->affinity = OE_Ignore;
}
+ yygotominor.yy346.zStart = yymsp[-3].minor.yy0.z;
+ yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 242: /* expr ::= RAISE LP raisetype COMMA nm RP */
+ case 289: /* expr ::= RAISE LP raisetype COMMA nm RP */
{
- spanSet(&yymsp[-5].minor.yy342,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/
- yymsp[-5].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &yymsp[-1].minor.yy0);
- if( yymsp[-5].minor.yy342.pExpr ) {
- yymsp[-5].minor.yy342.pExpr->affinity = (char)yymsp[-3].minor.yy392;
+ yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &yymsp[-1].minor.yy0);
+ if( yygotominor.yy346.pExpr ) {
+ yygotominor.yy346.pExpr->affinity = (char)yymsp[-3].minor.yy328;
}
+ yygotominor.yy346.zStart = yymsp[-5].minor.yy0.z;
+ yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 243: /* raisetype ::= ROLLBACK */
-{yymsp[0].minor.yy392 = OE_Rollback;}
+ case 290: /* raisetype ::= ROLLBACK */
+{yygotominor.yy328 = OE_Rollback;}
break;
- case 245: /* raisetype ::= FAIL */
-{yymsp[0].minor.yy392 = OE_Fail;}
+ case 292: /* raisetype ::= FAIL */
+{yygotominor.yy328 = OE_Fail;}
break;
- case 246: /* cmd ::= DROP TRIGGER ifexists fullname */
+ case 293: /* cmd ::= DROP TRIGGER ifexists fullname */
{
- sqlite3DropTrigger(pParse,yymsp[0].minor.yy347,yymsp[-1].minor.yy392);
+ sqlite3DropTrigger(pParse,yymsp[0].minor.yy65,yymsp[-1].minor.yy328);
}
break;
- case 247: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+ case 294: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
{
- sqlite3Attach(pParse, yymsp[-3].minor.yy342.pExpr, yymsp[-1].minor.yy342.pExpr, yymsp[0].minor.yy122);
+ sqlite3Attach(pParse, yymsp[-3].minor.yy346.pExpr, yymsp[-1].minor.yy346.pExpr, yymsp[0].minor.yy132);
}
break;
- case 248: /* cmd ::= DETACH database_kw_opt expr */
+ case 295: /* cmd ::= DETACH database_kw_opt expr */
{
- sqlite3Detach(pParse, yymsp[0].minor.yy342.pExpr);
+ sqlite3Detach(pParse, yymsp[0].minor.yy346.pExpr);
}
break;
- case 251: /* cmd ::= REINDEX */
+ case 300: /* cmd ::= REINDEX */
{sqlite3Reindex(pParse, 0, 0);}
break;
- case 252: /* cmd ::= REINDEX nm dbnm */
+ case 301: /* cmd ::= REINDEX nm dbnm */
{sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
- case 253: /* cmd ::= ANALYZE */
+ case 302: /* cmd ::= ANALYZE */
{sqlite3Analyze(pParse, 0, 0);}
break;
- case 254: /* cmd ::= ANALYZE nm dbnm */
+ case 303: /* cmd ::= ANALYZE nm dbnm */
{sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
- case 255: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
+ case 304: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
{
- sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy347,&yymsp[0].minor.yy0);
+ sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy65,&yymsp[0].minor.yy0);
}
break;
- case 256: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
+ case 305: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column */
{
- yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n;
- sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0);
+ sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy0);
}
break;
- case 257: /* add_column_fullname ::= fullname */
+ case 306: /* add_column_fullname ::= fullname */
{
- disableLookaside(pParse);
- sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy347);
+ pParse->db->lookaside.bEnabled = 0;
+ sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy65);
}
break;
- case 258: /* cmd ::= create_vtab */
+ case 309: /* cmd ::= create_vtab */
{sqlite3VtabFinishParse(pParse,0);}
break;
- case 259: /* cmd ::= create_vtab LP vtabarglist RP */
+ case 310: /* cmd ::= create_vtab LP vtabarglist RP */
{sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
break;
- case 260: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+ case 311: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
{
- sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy392);
+ sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy328);
}
break;
- case 261: /* vtabarg ::= */
+ case 314: /* vtabarg ::= */
{sqlite3VtabArgInit(pParse);}
break;
- case 262: /* vtabargtoken ::= ANY */
- case 263: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==263);
- case 264: /* lp ::= LP */ yytestcase(yyruleno==264);
+ case 316: /* vtabargtoken ::= ANY */
+ case 317: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==317);
+ case 318: /* lp ::= LP */ yytestcase(yyruleno==318);
{sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);}
break;
- case 265: /* with ::= */
-{yymsp[1].minor.yy331 = 0;}
- break;
- case 266: /* with ::= WITH wqlist */
-{ yymsp[-1].minor.yy331 = yymsp[0].minor.yy331; }
+ case 322: /* with ::= */
+{yygotominor.yy59 = 0;}
break;
- case 267: /* with ::= WITH RECURSIVE wqlist */
-{ yymsp[-2].minor.yy331 = yymsp[0].minor.yy331; }
+ case 323: /* with ::= WITH wqlist */
+ case 324: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==324);
+{ yygotominor.yy59 = yymsp[0].minor.yy59; }
break;
- case 268: /* wqlist ::= nm eidlist_opt AS LP select RP */
+ case 325: /* wqlist ::= nm idxlist_opt AS LP select RP */
{
- yymsp[-5].minor.yy331 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy442, yymsp[-1].minor.yy159); /*A-overwrites-X*/
+ yygotominor.yy59 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy14, yymsp[-1].minor.yy3);
}
break;
- case 269: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
+ case 326: /* wqlist ::= wqlist COMMA nm idxlist_opt AS LP select RP */
{
- yymsp[-7].minor.yy331 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy331, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy442, yymsp[-1].minor.yy159);
+ yygotominor.yy59 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy59, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy14, yymsp[-1].minor.yy3);
}
break;
default:
- /* (270) input ::= cmdlist */ yytestcase(yyruleno==270);
- /* (271) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==271);
- /* (272) cmdlist ::= ecmd */ yytestcase(yyruleno==272);
- /* (273) ecmd ::= SEMI */ yytestcase(yyruleno==273);
- /* (274) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==274);
- /* (275) explain ::= */ yytestcase(yyruleno==275);
- /* (276) trans_opt ::= */ yytestcase(yyruleno==276);
- /* (277) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==277);
- /* (278) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==278);
- /* (279) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==279);
- /* (280) savepoint_opt ::= */ yytestcase(yyruleno==280);
- /* (281) cmd ::= create_table create_table_args */ yytestcase(yyruleno==281);
- /* (282) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==282);
- /* (283) columnlist ::= columnname carglist */ yytestcase(yyruleno==283);
- /* (284) nm ::= ID|INDEXED */ yytestcase(yyruleno==284);
- /* (285) nm ::= STRING */ yytestcase(yyruleno==285);
- /* (286) nm ::= JOIN_KW */ yytestcase(yyruleno==286);
- /* (287) typetoken ::= typename */ yytestcase(yyruleno==287);
- /* (288) typename ::= ID|STRING */ yytestcase(yyruleno==288);
- /* (289) signed ::= plus_num */ yytestcase(yyruleno==289);
- /* (290) signed ::= minus_num */ yytestcase(yyruleno==290);
- /* (291) carglist ::= carglist ccons */ yytestcase(yyruleno==291);
- /* (292) carglist ::= */ yytestcase(yyruleno==292);
- /* (293) ccons ::= NULL onconf */ yytestcase(yyruleno==293);
- /* (294) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==294);
- /* (295) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==295);
- /* (296) conslist ::= tcons */ yytestcase(yyruleno==296);
- /* (297) tconscomma ::= */ yytestcase(yyruleno==297);
- /* (298) defer_subclause_opt ::= defer_subclause */ yytestcase(yyruleno==298);
- /* (299) resolvetype ::= raisetype */ yytestcase(yyruleno==299);
- /* (300) selectnowith ::= oneselect */ yytestcase(yyruleno==300);
- /* (301) oneselect ::= values */ yytestcase(yyruleno==301);
- /* (302) sclp ::= selcollist COMMA */ yytestcase(yyruleno==302);
- /* (303) as ::= ID|STRING */ yytestcase(yyruleno==303);
- /* (304) expr ::= term */ yytestcase(yyruleno==304);
- /* (305) exprlist ::= nexprlist */ yytestcase(yyruleno==305);
- /* (306) nmnum ::= plus_num */ yytestcase(yyruleno==306);
- /* (307) nmnum ::= nm */ yytestcase(yyruleno==307);
- /* (308) nmnum ::= ON */ yytestcase(yyruleno==308);
- /* (309) nmnum ::= DELETE */ yytestcase(yyruleno==309);
- /* (310) nmnum ::= DEFAULT */ yytestcase(yyruleno==310);
- /* (311) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==311);
- /* (312) foreach_clause ::= */ yytestcase(yyruleno==312);
- /* (313) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==313);
- /* (314) trnm ::= nm */ yytestcase(yyruleno==314);
- /* (315) tridxby ::= */ yytestcase(yyruleno==315);
- /* (316) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==316);
- /* (317) database_kw_opt ::= */ yytestcase(yyruleno==317);
- /* (318) kwcolumn_opt ::= */ yytestcase(yyruleno==318);
- /* (319) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==319);
- /* (320) vtabarglist ::= vtabarg */ yytestcase(yyruleno==320);
- /* (321) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==321);
- /* (322) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==322);
- /* (323) anylist ::= */ yytestcase(yyruleno==323);
- /* (324) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==324);
- /* (325) anylist ::= anylist ANY */ yytestcase(yyruleno==325);
+ /* (0) input ::= cmdlist */ yytestcase(yyruleno==0);
+ /* (1) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==1);
+ /* (2) cmdlist ::= ecmd */ yytestcase(yyruleno==2);
+ /* (3) ecmd ::= SEMI */ yytestcase(yyruleno==3);
+ /* (4) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==4);
+ /* (10) trans_opt ::= */ yytestcase(yyruleno==10);
+ /* (11) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==11);
+ /* (12) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==12);
+ /* (20) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==20);
+ /* (21) savepoint_opt ::= */ yytestcase(yyruleno==21);
+ /* (25) cmd ::= create_table create_table_args */ yytestcase(yyruleno==25);
+ /* (36) columnlist ::= columnlist COMMA column */ yytestcase(yyruleno==36);
+ /* (37) columnlist ::= column */ yytestcase(yyruleno==37);
+ /* (43) type ::= */ yytestcase(yyruleno==43);
+ /* (50) signed ::= plus_num */ yytestcase(yyruleno==50);
+ /* (51) signed ::= minus_num */ yytestcase(yyruleno==51);
+ /* (52) carglist ::= carglist ccons */ yytestcase(yyruleno==52);
+ /* (53) carglist ::= */ yytestcase(yyruleno==53);
+ /* (60) ccons ::= NULL onconf */ yytestcase(yyruleno==60);
+ /* (88) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==88);
+ /* (89) conslist ::= tcons */ yytestcase(yyruleno==89);
+ /* (91) tconscomma ::= */ yytestcase(yyruleno==91);
+ /* (273) foreach_clause ::= */ yytestcase(yyruleno==273);
+ /* (274) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==274);
+ /* (281) tridxby ::= */ yytestcase(yyruleno==281);
+ /* (298) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==298);
+ /* (299) database_kw_opt ::= */ yytestcase(yyruleno==299);
+ /* (307) kwcolumn_opt ::= */ yytestcase(yyruleno==307);
+ /* (308) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==308);
+ /* (312) vtabarglist ::= vtabarg */ yytestcase(yyruleno==312);
+ /* (313) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==313);
+ /* (315) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==315);
+ /* (319) anylist ::= */ yytestcase(yyruleno==319);
+ /* (320) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==320);
+ /* (321) anylist ::= anylist ANY */ yytestcase(yyruleno==321);
break;
-/********** End reduce actions ************************************************/
};
- assert( yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
+ assert( yyruleno>=0 && yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
yygoto = yyRuleInfo[yyruleno].lhs;
yysize = yyRuleInfo[yyruleno].nrhs;
+ yypParser->yyidx -= yysize;
yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
- if( yyact <= YY_MAX_SHIFTREDUCE ){
- if( yyact>YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
- yypParser->yyidx -= yysize - 1;
- yymsp -= yysize-1;
- yymsp->stateno = (YYACTIONTYPE)yyact;
- yymsp->major = (YYCODETYPE)yygoto;
- yyTraceShift(yypParser, yyact);
- }else{
- assert( yyact == YY_ACCEPT_ACTION );
- yypParser->yyidx -= yysize;
+ if( yyact < YYNSTATE ){
+#ifdef NDEBUG
+ /* If we are not debugging and the reduce action popped at least
+ ** one element off the stack, then we can push the new element back
+ ** onto the stack here, and skip the stack overflow test in yy_shift().
+ ** That gives a significant speed improvement. */
+ if( yysize ){
+ yypParser->yyidx++;
+ yymsp -= yysize-1;
+ yymsp->stateno = (YYACTIONTYPE)yyact;
+ yymsp->major = (YYCODETYPE)yygoto;
+ yymsp->minor = yygotominor;
+ }else
+#endif
+ {
+ yy_shift(yypParser,yyact,yygoto,&yygotominor);
+ }
+ }else{
+ assert( yyact == YYNSTATE + YYNRULE + 1 );
yy_accept(yypParser);
}
}
@@ -134132,8 +126593,6 @@ static void yy_parse_failed(
while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
/* Here code is inserted which will be executed whenever the
** parser fails */
-/************ Begin %parse_failure code ***************************************/
-/************ End %parse_failure code *****************************************/
sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
#endif /* YYNOERRORRECOVERY */
@@ -134144,16 +126603,14 @@ static void yy_parse_failed(
static void yy_syntax_error(
yyParser *yypParser, /* The parser */
int yymajor, /* The major type of the error token */
- sqlite3ParserTOKENTYPE yyminor /* The minor type of the error token */
+ YYMINORTYPE yyminor /* The minor type of the error token */
){
sqlite3ParserARG_FETCH;
-#define TOKEN yyminor
-/************ Begin %syntax_error code ****************************************/
+#define TOKEN (yyminor.yy0)
UNUSED_PARAMETER(yymajor); /* Silence some compiler warnings */
assert( TOKEN.z[0] ); /* The tokenizer always gives us a token */
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
-/************ End %syntax_error code ******************************************/
sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
@@ -134172,8 +126629,6 @@ static void yy_accept(
while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
/* Here code is inserted which will be executed whenever the
** parser accepts */
-/*********** Begin %parse_accept code *****************************************/
-/*********** End %parse_accept code *******************************************/
sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
@@ -134203,7 +126658,7 @@ SQLITE_PRIVATE void sqlite3Parser(
sqlite3ParserARG_PDECL /* Optional %extra_argument parameter */
){
YYMINORTYPE yyminorunion;
- unsigned int yyact; /* The parser action. */
+ int yyact; /* The parser action. */
#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
int yyendofinput; /* True if we are at the end of input */
#endif
@@ -134217,23 +126672,18 @@ SQLITE_PRIVATE void sqlite3Parser(
if( yypParser->yyidx<0 ){
#if YYSTACKDEPTH<=0
if( yypParser->yystksz <=0 ){
- yyStackOverflow(yypParser);
+ /*memset(&yyminorunion, 0, sizeof(yyminorunion));*/
+ yyminorunion = yyzerominor;
+ yyStackOverflow(yypParser, &yyminorunion);
return;
}
#endif
yypParser->yyidx = 0;
-#ifndef YYNOERRORRECOVERY
yypParser->yyerrcnt = -1;
-#endif
yypParser->yystack[0].stateno = 0;
yypParser->yystack[0].major = 0;
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sInitialize. Empty stack. State 0\n",
- yyTracePrompt);
- }
-#endif
}
+ yyminorunion.yy0 = yyminor;
#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
yyendofinput = (yymajor==0);
#endif
@@ -134241,24 +126691,20 @@ SQLITE_PRIVATE void sqlite3Parser(
#ifndef NDEBUG
if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sInput '%s'\n",yyTracePrompt,yyTokenName[yymajor]);
+ fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
}
#endif
do{
yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
- if( yyact <= YY_MAX_SHIFTREDUCE ){
- if( yyact > YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
- yy_shift(yypParser,yyact,yymajor,yyminor);
-#ifndef YYNOERRORRECOVERY
+ if( yyact<YYNSTATE ){
+ yy_shift(yypParser,yyact,yymajor,&yyminorunion);
yypParser->yyerrcnt--;
-#endif
yymajor = YYNOCODE;
- }else if( yyact <= YY_MAX_REDUCE ){
- yy_reduce(yypParser,yyact-YY_MIN_REDUCE);
+ }else if( yyact < YYNSTATE + YYNRULE ){
+ yy_reduce(yypParser,yyact-YYNSTATE);
}else{
assert( yyact == YY_ERROR_ACTION );
- yyminorunion.yy0 = yyminor;
#ifdef YYERRORSYMBOL
int yymx;
#endif
@@ -134288,7 +126734,7 @@ SQLITE_PRIVATE void sqlite3Parser(
**
*/
if( yypParser->yyerrcnt<0 ){
- yy_syntax_error(yypParser,yymajor,yyminor);
+ yy_syntax_error(yypParser,yymajor,yyminorunion);
}
yymx = yypParser->yystack[yypParser->yyidx].major;
if( yymx==YYERRORSYMBOL || yyerrorhit ){
@@ -134298,15 +126744,15 @@ SQLITE_PRIVATE void sqlite3Parser(
yyTracePrompt,yyTokenName[yymajor]);
}
#endif
- yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion);
+ yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion);
yymajor = YYNOCODE;
}else{
- while(
+ while(
yypParser->yyidx >= 0 &&
yymx != YYERRORSYMBOL &&
(yyact = yy_find_reduce_action(
yypParser->yystack[yypParser->yyidx].stateno,
- YYERRORSYMBOL)) >= YY_MIN_REDUCE
+ YYERRORSYMBOL)) >= YYNSTATE
){
yy_pop_parser_stack(yypParser);
}
@@ -134315,7 +126761,9 @@ SQLITE_PRIVATE void sqlite3Parser(
yy_parse_failed(yypParser);
yymajor = YYNOCODE;
}else if( yymx!=YYERRORSYMBOL ){
- yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor);
+ YYMINORTYPE u2;
+ u2.YYERRSYMDT = 0;
+ yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
}
}
yypParser->yyerrcnt = 3;
@@ -134328,7 +126776,7 @@ SQLITE_PRIVATE void sqlite3Parser(
** Applications can set this macro (for example inside %include) if
** they intend to abandon the parse upon the first syntax error seen.
*/
- yy_syntax_error(yypParser,yymajor, yyminor);
+ yy_syntax_error(yypParser,yymajor,yyminorunion);
yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
yymajor = YYNOCODE;
@@ -134343,7 +126791,7 @@ SQLITE_PRIVATE void sqlite3Parser(
** three input tokens have been successfully shifted.
*/
if( yypParser->yyerrcnt<=0 ){
- yy_syntax_error(yypParser,yymajor, yyminor);
+ yy_syntax_error(yypParser,yymajor,yyminorunion);
}
yypParser->yyerrcnt = 3;
yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
@@ -134354,16 +126802,6 @@ SQLITE_PRIVATE void sqlite3Parser(
#endif
}
}while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
-#ifndef NDEBUG
- if( yyTraceFILE ){
- int i;
- fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt);
- for(i=1; i<=yypParser->yyidx; i++)
- fprintf(yyTraceFILE,"%c%s", i==1 ? '[' : ' ',
- yyTokenName[yypParser->yystack[i].major]);
- fprintf(yyTraceFILE,"]\n");
- }
-#endif
return;
}
@@ -134386,95 +126824,14 @@ SQLITE_PRIVATE void sqlite3Parser(
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
*/
-/* #include "sqliteInt.h" */
/* #include <stdlib.h> */
-/* Character classes for tokenizing
-**
-** In the sqlite3GetToken() function, a switch() on aiClass[c] is implemented
-** using a lookup table, whereas a switch() directly on c uses a binary search.
-** The lookup table is much faster. To maximize speed, and to ensure that
-** a lookup table is used, all of the classes need to be small integers and
-** all of them need to be used within the switch.
-*/
-#define CC_X 0 /* The letter 'x', or start of BLOB literal */
-#define CC_KYWD 1 /* Alphabetics or '_'. Usable in a keyword */
-#define CC_ID 2 /* unicode characters usable in IDs */
-#define CC_DIGIT 3 /* Digits */
-#define CC_DOLLAR 4 /* '$' */
-#define CC_VARALPHA 5 /* '@', '#', ':'. Alphabetic SQL variables */
-#define CC_VARNUM 6 /* '?'. Numeric SQL variables */
-#define CC_SPACE 7 /* Space characters */
-#define CC_QUOTE 8 /* '"', '\'', or '`'. String literals, quoted ids */
-#define CC_QUOTE2 9 /* '['. [...] style quoted ids */
-#define CC_PIPE 10 /* '|'. Bitwise OR or concatenate */
-#define CC_MINUS 11 /* '-'. Minus or SQL-style comment */
-#define CC_LT 12 /* '<'. Part of < or <= or <> */
-#define CC_GT 13 /* '>'. Part of > or >= */
-#define CC_EQ 14 /* '='. Part of = or == */
-#define CC_BANG 15 /* '!'. Part of != */
-#define CC_SLASH 16 /* '/'. / or c-style comment */
-#define CC_LP 17 /* '(' */
-#define CC_RP 18 /* ')' */
-#define CC_SEMI 19 /* ';' */
-#define CC_PLUS 20 /* '+' */
-#define CC_STAR 21 /* '*' */
-#define CC_PERCENT 22 /* '%' */
-#define CC_COMMA 23 /* ',' */
-#define CC_AND 24 /* '&' */
-#define CC_TILDA 25 /* '~' */
-#define CC_DOT 26 /* '.' */
-#define CC_ILLEGAL 27 /* Illegal character */
-
-static const unsigned char aiClass[] = {
-#ifdef SQLITE_ASCII
-/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */
-/* 0x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 27, 7, 7, 27, 27,
-/* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
-/* 2x */ 7, 15, 8, 5, 4, 22, 24, 8, 17, 18, 21, 20, 23, 11, 26, 16,
-/* 3x */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 19, 12, 14, 13, 6,
-/* 4x */ 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-/* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 9, 27, 27, 27, 1,
-/* 6x */ 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-/* 7x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 27, 10, 27, 25, 27,
-/* 8x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-/* 9x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-/* Ax */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-/* Bx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-/* Cx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-/* Dx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-/* Ex */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-/* Fx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
-#endif
-#ifdef SQLITE_EBCDIC
-/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */
-/* 0x */ 27, 27, 27, 27, 27, 7, 27, 27, 27, 27, 27, 27, 7, 7, 27, 27,
-/* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
-/* 2x */ 27, 27, 27, 27, 27, 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
-/* 3x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
-/* 4x */ 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 12, 17, 20, 10,
-/* 5x */ 24, 27, 27, 27, 27, 27, 27, 27, 27, 27, 15, 4, 21, 18, 19, 27,
-/* 6x */ 11, 16, 27, 27, 27, 27, 27, 27, 27, 27, 27, 23, 22, 1, 13, 7,
-/* 7x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 8, 5, 5, 5, 8, 14, 8,
-/* 8x */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
-/* 9x */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
-/* 9x */ 25, 1, 1, 1, 1, 1, 1, 0, 1, 1, 27, 27, 27, 27, 27, 27,
-/* Bx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 9, 27, 27, 27, 27, 27,
-/* Cx */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
-/* Dx */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
-/* Ex */ 27, 27, 1, 1, 1, 1, 1, 0, 1, 1, 27, 27, 27, 27, 27, 27,
-/* Fx */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 27, 27, 27, 27, 27, 27,
-#endif
-};
-
/*
-** The charMap() macro maps alphabetic characters (only) into their
+** The charMap() macro maps alphabetic characters into their
** lower-case ASCII equivalent. On ASCII machines, this is just
** an upper-to-lower case map. On EBCDIC machines we also need
-** to adjust the encoding. The mapping is only valid for alphabetics
-** which are the only characters for which this feature is used.
-**
-** Used by keywordhash.h
+** to adjust the encoding. Only alphabetic characters and underscores
+** need to be translated.
*/
#ifdef SQLITE_ASCII
# define charMap(X) sqlite3UpperToLower[(unsigned char)X]
@@ -134508,7 +126865,7 @@ const unsigned char ebcdicToAscii[] = {
** returned. If the input is not a keyword, TK_ID is returned.
**
** The implementation of this routine was generated by a program,
-** mkkeywordhash.c, located in the tool subdirectory of the distribution.
+** mkkeywordhash.h, located in the tool subdirectory of the distribution.
** The output of the mkkeywordhash.c program is written into a file
** named keywordhash.h and then included into this source file by
** the #include below.
@@ -134529,7 +126886,7 @@ const unsigned char ebcdicToAscii[] = {
** on platforms with limited memory.
*/
/* Hash score: 182 */
-static int keywordCode(const char *z, int n, int *pType){
+static int keywordCode(const char *z, int n){
/* zText[] encodes 834 bytes of keywords in 554 bytes */
/* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */
/* ABLEFTHENDEFERRABLELSEXCEPTRANSACTIONATURALTERAISEXCLUSIVE */
@@ -134649,21 +127006,13 @@ static int keywordCode(const char *z, int n, int *pType){
TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_UNION, TK_USING,
TK_VACUUM, TK_VIEW, TK_INITIALLY, TK_ALL,
};
- int i, j;
- const char *zKW;
- if( n>=2 ){
- i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) % 127;
- for(i=((int)aHash[i])-1; i>=0; i=((int)aNext[i])-1){
- if( aLen[i]!=n ) continue;
- j = 0;
- zKW = &zText[aOffset[i]];
-#ifdef SQLITE_ASCII
- while( j<n && (z[j]&~0x20)==zKW[j] ){ j++; }
-#endif
-#ifdef SQLITE_EBCDIC
- while( j<n && toupper(z[j])==zKW[j] ){ j++; }
-#endif
- if( j<n ) continue;
+ int h, i;
+ if( n<2 ) return TK_ID;
+ h = ((charMap(z[0])*4) ^
+ (charMap(z[n-1])*3) ^
+ n) % 127;
+ for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){
+ if( aLen[i]==n && sqlite3StrNICmp(&zText[aOffset[i]],z,n)==0 ){
testcase( i==0 ); /* REINDEX */
testcase( i==1 ); /* INDEXED */
testcase( i==2 ); /* INDEX */
@@ -134788,16 +127137,13 @@ static int keywordCode(const char *z, int n, int *pType){
testcase( i==121 ); /* VIEW */
testcase( i==122 ); /* INITIALLY */
testcase( i==123 ); /* ALL */
- *pType = aCode[i];
- break;
+ return aCode[i];
}
}
- return n;
+ return TK_ID;
}
SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char *z, int n){
- int id = TK_ID;
- keywordCode((char*)z, n, &id);
- return id;
+ return keywordCode((char*)z, n);
}
#define SQLITE_N_KEYWORD 124
@@ -134842,23 +127188,17 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[] = {
};
#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
#endif
-
-/* Make the IdChar function accessible from ctime.c */
-#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
SQLITE_PRIVATE int sqlite3IsIdChar(u8 c){ return IdChar(c); }
-#endif
/*
-** Return the length (in bytes) of the token that begins at z[0].
+** Return the length of the token that begins at z[0].
** Store the token type in *tokenType before returning.
*/
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
int i, c;
- switch( aiClass[*z] ){ /* Switch on the character-class of the first byte
- ** of the token. See the comment on the CC_ defines
- ** above. */
- case CC_SPACE: {
+ switch( *z ){
+ case ' ': case '\t': case '\n': case '\f': case '\r': {
testcase( z[0]==' ' );
testcase( z[0]=='\t' );
testcase( z[0]=='\n' );
@@ -134868,7 +127208,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
*tokenType = TK_SPACE;
return i;
}
- case CC_MINUS: {
+ case '-': {
if( z[1]=='-' ){
for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
*tokenType = TK_SPACE; /* IMP: R-22934-25134 */
@@ -134877,27 +127217,27 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
*tokenType = TK_MINUS;
return 1;
}
- case CC_LP: {
+ case '(': {
*tokenType = TK_LP;
return 1;
}
- case CC_RP: {
+ case ')': {
*tokenType = TK_RP;
return 1;
}
- case CC_SEMI: {
+ case ';': {
*tokenType = TK_SEMI;
return 1;
}
- case CC_PLUS: {
+ case '+': {
*tokenType = TK_PLUS;
return 1;
}
- case CC_STAR: {
+ case '*': {
*tokenType = TK_STAR;
return 1;
}
- case CC_SLASH: {
+ case '/': {
if( z[1]!='*' || z[2]==0 ){
*tokenType = TK_SLASH;
return 1;
@@ -134907,15 +127247,15 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
*tokenType = TK_SPACE; /* IMP: R-22934-25134 */
return i;
}
- case CC_PERCENT: {
+ case '%': {
*tokenType = TK_REM;
return 1;
}
- case CC_EQ: {
+ case '=': {
*tokenType = TK_EQ;
return 1 + (z[1]=='=');
}
- case CC_LT: {
+ case '<': {
if( (c=z[1])=='=' ){
*tokenType = TK_LE;
return 2;
@@ -134930,7 +127270,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
return 1;
}
}
- case CC_GT: {
+ case '>': {
if( (c=z[1])=='=' ){
*tokenType = TK_GE;
return 2;
@@ -134942,16 +127282,16 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
return 1;
}
}
- case CC_BANG: {
+ case '!': {
if( z[1]!='=' ){
*tokenType = TK_ILLEGAL;
- return 1;
+ return 2;
}else{
*tokenType = TK_NE;
return 2;
}
}
- case CC_PIPE: {
+ case '|': {
if( z[1]!='|' ){
*tokenType = TK_BITOR;
return 1;
@@ -134960,19 +127300,21 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
return 2;
}
}
- case CC_COMMA: {
+ case ',': {
*tokenType = TK_COMMA;
return 1;
}
- case CC_AND: {
+ case '&': {
*tokenType = TK_BITAND;
return 1;
}
- case CC_TILDA: {
+ case '~': {
*tokenType = TK_BITNOT;
return 1;
}
- case CC_QUOTE: {
+ case '`':
+ case '\'':
+ case '"': {
int delim = z[0];
testcase( delim=='`' );
testcase( delim=='\'' );
@@ -134997,7 +127339,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
return i;
}
}
- case CC_DOT: {
+ case '.': {
#ifndef SQLITE_OMIT_FLOATING_POINT
if( !sqlite3Isdigit(z[1]) )
#endif
@@ -135008,7 +127350,8 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
/* If the next character is a digit, this is a floating point
** number that begins with ".". Fall thru into the next case */
}
- case CC_DIGIT: {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9': {
testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' );
testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' );
testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' );
@@ -135043,18 +127386,22 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
}
return i;
}
- case CC_QUOTE2: {
+ case '[': {
for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){}
*tokenType = c==']' ? TK_ID : TK_ILLEGAL;
return i;
}
- case CC_VARNUM: {
+ case '?': {
*tokenType = TK_VARIABLE;
for(i=1; sqlite3Isdigit(z[i]); i++){}
return i;
}
- case CC_DOLLAR:
- case CC_VARALPHA: {
+#ifndef SQLITE_OMIT_TCL_VARIABLE
+ case '$':
+#endif
+ case '@': /* For compatibility with MS SQL Server */
+ case '#':
+ case ':': {
int n = 0;
testcase( z[0]=='$' ); testcase( z[0]=='@' );
testcase( z[0]==':' ); testcase( z[0]=='#' );
@@ -135083,20 +127430,8 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
if( n==0 ) *tokenType = TK_ILLEGAL;
return i;
}
- case CC_KYWD: {
- for(i=1; aiClass[z[i]]<=CC_KYWD; i++){}
- if( IdChar(z[i]) ){
- /* This token started out using characters that can appear in keywords,
- ** but z[i] is a character not allowed within keywords, so this must
- ** be an identifier instead */
- i++;
- break;
- }
- *tokenType = TK_ID;
- return keywordCode((char*)z, i, tokenType);
- }
- case CC_X: {
#ifndef SQLITE_OMIT_BLOB_LITERAL
+ case 'x': case 'X': {
testcase( z[0]=='x' ); testcase( z[0]=='X' );
if( z[1]=='\'' ){
*tokenType = TK_BLOB;
@@ -135108,22 +127443,20 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
if( z[i] ) i++;
return i;
}
-#endif
- /* If it is not a BLOB literal, then it must be an ID, since no
- ** SQL keywords start with the letter 'x'. Fall through */
- }
- case CC_ID: {
- i = 1;
- break;
+ /* Otherwise fall through to the next case */
}
+#endif
default: {
- *tokenType = TK_ILLEGAL;
- return 1;
+ if( !IdChar(*z) ){
+ break;
+ }
+ for(i=1; IdChar(z[i]); i++){}
+ *tokenType = keywordCode((char*)z, i);
+ return i;
}
}
- while( IdChar(z[i]) ){ i++; }
- *tokenType = TK_ID;
- return i;
+ *tokenType = TK_ILLEGAL;
+ return 1;
}
/*
@@ -135139,6 +127472,7 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
void *pEngine; /* The LEMON-generated LALR(1) parser */
int tokenType; /* type of the next token */
int lastTokenParsed = -1; /* type of the previous token */
+ u8 enableLookaside; /* Saved value of db->lookaside.bEnabled */
sqlite3 *db = pParse->db; /* The database connection */
int mxSqlLen; /* Max length of an SQL string */
@@ -135151,18 +127485,19 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
pParse->zTail = zSql;
i = 0;
assert( pzErrMsg!=0 );
- /* sqlite3ParserTrace(stdout, "parser: "); */
pEngine = sqlite3ParserAlloc(sqlite3Malloc);
if( pEngine==0 ){
- sqlite3OomFault(db);
- return SQLITE_NOMEM_BKPT;
+ db->mallocFailed = 1;
+ return SQLITE_NOMEM;
}
assert( pParse->pNewTable==0 );
assert( pParse->pNewTrigger==0 );
assert( pParse->nVar==0 );
assert( pParse->nzVar==0 );
assert( pParse->azVar==0 );
- while( zSql[i]!=0 ){
+ enableLookaside = db->lookaside.bEnabled;
+ if( db->lookaside.pStart ) db->lookaside.bEnabled = 1;
+ while( !db->mallocFailed && zSql[i]!=0 ){
assert( i>=0 );
pParse->sLastToken.z = &zSql[i];
pParse->sLastToken.n = sqlite3GetToken((unsigned char*)&zSql[i],&tokenType);
@@ -135171,29 +127506,40 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
pParse->rc = SQLITE_TOOBIG;
break;
}
- if( tokenType>=TK_SPACE ){
- assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
- if( db->u1.isInterrupted ){
- pParse->rc = SQLITE_INTERRUPT;
+ switch( tokenType ){
+ case TK_SPACE: {
+ if( db->u1.isInterrupted ){
+ sqlite3ErrorMsg(pParse, "interrupt");
+ pParse->rc = SQLITE_INTERRUPT;
+ goto abort_parse;
+ }
break;
}
- if( tokenType==TK_ILLEGAL ){
+ case TK_ILLEGAL: {
sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"",
&pParse->sLastToken);
+ goto abort_parse;
+ }
+ case TK_SEMI: {
+ pParse->zTail = &zSql[i];
+ /* Fall thru into the default case */
+ }
+ default: {
+ sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse);
+ lastTokenParsed = tokenType;
+ if( pParse->rc!=SQLITE_OK ){
+ goto abort_parse;
+ }
break;
}
- }else{
- sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse);
- lastTokenParsed = tokenType;
- if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break;
}
}
+abort_parse:
assert( nErr==0 );
- pParse->zTail = &zSql[i];
- if( pParse->rc==SQLITE_OK && db->mallocFailed==0 ){
- assert( zSql[i]==0 );
+ if( zSql[i]==0 && pParse->rc==SQLITE_OK && db->mallocFailed==0 ){
if( lastTokenParsed!=TK_SEMI ){
sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
+ pParse->zTail = &zSql[i];
}
if( pParse->rc==SQLITE_OK && db->mallocFailed==0 ){
sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
@@ -135201,17 +127547,18 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
}
#ifdef YYTRACKMAXSTACKDEPTH
sqlite3_mutex_enter(sqlite3MallocMutex());
- sqlite3StatusHighwater(SQLITE_STATUS_PARSER_STACK,
+ sqlite3StatusSet(SQLITE_STATUS_PARSER_STACK,
sqlite3ParserStackPeak(pEngine)
);
sqlite3_mutex_leave(sqlite3MallocMutex());
#endif /* YYDEBUG */
sqlite3ParserFree(pEngine, sqlite3_free);
+ db->lookaside.bEnabled = enableLookaside;
if( db->mallocFailed ){
- pParse->rc = SQLITE_NOMEM_BKPT;
+ pParse->rc = SQLITE_NOMEM;
}
if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
- pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc));
+ sqlite3SetString(&pParse->zErrMsg, db, "%s", sqlite3ErrStr(pParse->rc));
}
assert( pzErrMsg!=0 );
if( pParse->zErrMsg ){
@@ -135243,7 +127590,7 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
sqlite3DeleteTable(db, pParse->pNewTable);
}
- if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree);
+ if( pParse->bFreeWith ) sqlite3WithDelete(db, pParse->pWith);
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
for(i=pParse->nzVar-1; i>=0; i--) sqlite3DbFree(db, pParse->azVar[i]);
sqlite3DbFree(db, pParse->azVar);
@@ -135281,7 +127628,6 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
** separating it out, the code will be automatically omitted from
** static links that do not use it.
*/
-/* #include "sqliteInt.h" */
#ifndef SQLITE_OMIT_COMPLETE
/*
@@ -135546,10 +127892,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *zSql){
if( zSql8 ){
rc = sqlite3_complete(zSql8);
}else{
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}
sqlite3ValueFree(pVal);
- return rc & 0xff;
+ return sqlite3ApiExit(0, rc);
}
#endif /* SQLITE_OMIT_UTF16 */
#endif /* SQLITE_OMIT_COMPLETE */
@@ -135572,7 +127918,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *zSql){
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
*/
-/* #include "sqliteInt.h" */
#ifdef SQLITE_ENABLE_FTS3
/************** Include fts3.h in the middle of main.c ***********************/
@@ -135592,7 +127937,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *zSql){
** This header file is used by programs that want to link against the
** FTS3 library. All it does is declare the sqlite3Fts3Init() interface.
*/
-/* #include "sqlite3.h" */
#if 0
extern "C" {
@@ -135625,7 +127969,6 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db);
** This header file is used by programs that want to link against the
** RTREE library. All it does is declare the sqlite3RtreeInit() interface.
*/
-/* #include "sqlite3.h" */
#if 0
extern "C" {
@@ -135658,7 +128001,6 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db);
** This header file is used by programs that want to link against the
** ICU extension. All it does is declare the sqlite3IcuInit() interface.
*/
-/* #include "sqlite3.h" */
#if 0
extern "C" {
@@ -135674,12 +128016,6 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db);
/************** End of sqliteicu.h *******************************************/
/************** Continuing where we left off in main.c ***********************/
#endif
-#ifdef SQLITE_ENABLE_JSON1
-SQLITE_PRIVATE int sqlite3Json1Init(sqlite3*);
-#endif
-#ifdef SQLITE_ENABLE_FTS5
-SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3*);
-#endif
#ifndef SQLITE_AMALGAMATION
/* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant
@@ -135836,7 +128172,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){
sqlite3GlobalConfig.pInitMutex =
sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
if( sqlite3GlobalConfig.bCoreMutex && !sqlite3GlobalConfig.pInitMutex ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}
}
}
@@ -135867,15 +128203,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){
*/
sqlite3_mutex_enter(sqlite3GlobalConfig.pInitMutex);
if( sqlite3GlobalConfig.isInit==0 && sqlite3GlobalConfig.inProgress==0 ){
+ FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
sqlite3GlobalConfig.inProgress = 1;
-#ifdef SQLITE_ENABLE_SQLLOG
- {
- extern void sqlite3_init_sqllog(void);
- sqlite3_init_sqllog();
- }
-#endif
- memset(&sqlite3BuiltinFunctions, 0, sizeof(sqlite3BuiltinFunctions));
- sqlite3RegisterBuiltinFunctions();
+ memset(pHash, 0, sizeof(sqlite3GlobalFunctions));
+ sqlite3RegisterGlobalFunctions();
if( sqlite3GlobalConfig.isPCacheInit==0 ){
rc = sqlite3PcacheInitialize();
}
@@ -136093,10 +128424,9 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int op, ...){
break;
}
case SQLITE_CONFIG_PAGECACHE: {
- /* EVIDENCE-OF: R-18761-36601 There are three arguments to
- ** SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned memory (pMem),
- ** the size of each page cache line (sz), and the number of cache lines
- ** (N). */
+ /* EVIDENCE-OF: R-31408-40510 There are three arguments to
+ ** SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned memory, the size
+ ** of each page buffer (sz), and the number of pages (N). */
sqlite3GlobalConfig.pPage = va_arg(ap, void*);
sqlite3GlobalConfig.szPage = va_arg(ap, int);
sqlite3GlobalConfig.nPage = va_arg(ap, int);
@@ -136282,11 +128612,6 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int op, ...){
break;
}
- case SQLITE_CONFIG_STMTJRNL_SPILL: {
- sqlite3GlobalConfig.nStmtSpill = va_arg(ap, int);
- break;
- }
-
default: {
rc = SQLITE_ERROR;
break;
@@ -136308,7 +128633,6 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int op, ...){
** the lookaside memory.
*/
static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
-#ifndef SQLITE_OMIT_LOOKASIDE
void *pStart;
if( db->lookaside.nOut ){
return SQLITE_BUSY;
@@ -136351,15 +128675,14 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
p = (LookasideSlot*)&((u8*)p)[sz];
}
db->lookaside.pEnd = p;
- db->lookaside.bDisable = 0;
+ db->lookaside.bEnabled = 1;
db->lookaside.bMalloced = pBuf==0 ?1:0;
}else{
db->lookaside.pStart = db;
db->lookaside.pEnd = db;
- db->lookaside.bDisable = 1;
+ db->lookaside.bEnabled = 0;
db->lookaside.bMalloced = 0;
}
-#endif /* SQLITE_OMIT_LOOKASIDE */
return SQLITE_OK;
}
@@ -136401,36 +128724,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3 *db){
}
/*
-** Flush any dirty pages in the pager-cache for any attached database
-** to disk.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3_db_cacheflush(sqlite3 *db){
- int i;
- int rc = SQLITE_OK;
- int bSeenBusy = 0;
-
-#ifdef SQLITE_ENABLE_API_ARMOR
- if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
-#endif
- sqlite3_mutex_enter(db->mutex);
- sqlite3BtreeEnterAll(db);
- for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
- Btree *pBt = db->aDb[i].pBt;
- if( pBt && sqlite3BtreeIsInTrans(pBt) ){
- Pager *pPager = sqlite3BtreePager(pBt);
- rc = sqlite3PagerFlush(pPager);
- if( rc==SQLITE_BUSY ){
- bSeenBusy = 1;
- rc = SQLITE_OK;
- }
- }
- }
- sqlite3BtreeLeaveAll(db);
- sqlite3_mutex_leave(db->mutex);
- return ((rc==SQLITE_OK && bSeenBusy) ? SQLITE_BUSY : rc);
-}
-
-/*
** Configuration settings for an individual database connection
*/
SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3 *db, int op, ...){
@@ -136450,10 +128743,8 @@ SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3 *db, int op, ...){
int op; /* The opcode */
u32 mask; /* Mask of the bit in sqlite3.flags to set/clear */
} aFlagOp[] = {
- { SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys },
- { SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger },
- { SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer },
- { SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension },
+ { SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys },
+ { SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger },
};
unsigned int i;
rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
@@ -136613,7 +128904,7 @@ SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *db){
** with SQLITE_ANY as the encoding.
*/
static void functionDestroy(sqlite3 *db, FuncDef *p){
- FuncDestructor *pDestructor = p->u.pDestructor;
+ FuncDestructor *pDestructor = p->pDestructor;
if( pDestructor ){
pDestructor->nRef--;
if( pDestructor->nRef==0 ){
@@ -136630,23 +128921,17 @@ static void functionDestroy(sqlite3 *db, FuncDef *p){
static void disconnectAllVtab(sqlite3 *db){
#ifndef SQLITE_OMIT_VIRTUALTABLE
int i;
- HashElem *p;
sqlite3BtreeEnterAll(db);
for(i=0; i<db->nDb; i++){
Schema *pSchema = db->aDb[i].pSchema;
if( db->aDb[i].pSchema ){
+ HashElem *p;
for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
Table *pTab = (Table *)sqliteHashData(p);
if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab);
}
}
}
- for(p=sqliteHashFirst(&db->aModule); p; p=sqliteHashNext(p)){
- Module *pMod = (Module *)sqliteHashData(p);
- if( pMod->pEpoTab ){
- sqlite3VtabDisconnect(db, pMod->pEpoTab);
- }
- }
sqlite3VtabUnlockList(db);
sqlite3BtreeLeaveAll(db);
#else
@@ -136795,17 +129080,18 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
*/
sqlite3ConnectionClosed(db);
- for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){
- FuncDef *pNext, *p;
- p = sqliteHashData(i);
- do{
- functionDestroy(db, p);
- pNext = p->pNext;
- sqlite3DbFree(db, p);
- p = pNext;
- }while( p );
+ for(j=0; j<ArraySize(db->aFunc.a); j++){
+ FuncDef *pNext, *pHash, *p;
+ 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;
+ }
+ }
}
- sqlite3HashClear(&db->aFunc);
for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){
CollSeq *pColl = (CollSeq *)sqliteHashData(i);
/* Invoke any destructors registered for collation sequence user data. */
@@ -136823,7 +129109,6 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
if( pMod->xDestroy ){
pMod->xDestroy(pMod->pAux);
}
- sqlite3VtabEponymousTableClear(db, pMod);
sqlite3DbFree(db, pMod);
}
sqlite3HashClear(&db->aModule);
@@ -137229,7 +129514,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
int nArg,
int enc,
void *pUserData,
- void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
void (*xFinal)(sqlite3_context*),
FuncDestructor *pDestructor
@@ -137240,9 +129525,9 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
assert( sqlite3_mutex_held(db->mutex) );
if( zFunctionName==0 ||
- (xSFunc && (xFinal || xStep)) ||
- (!xSFunc && (xFinal && !xStep)) ||
- (!xSFunc && (!xFinal && xStep)) ||
+ (xFunc && (xFinal || xStep)) ||
+ (!xFunc && (xFinal && !xStep)) ||
+ (!xFunc && (!xFinal && xStep)) ||
(nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) ||
(255<(nName = sqlite3Strlen30( zFunctionName))) ){
return SQLITE_MISUSE_BKPT;
@@ -137265,10 +129550,10 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
}else if( enc==SQLITE_ANY ){
int rc;
rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags,
- pUserData, xSFunc, xStep, xFinal, pDestructor);
+ pUserData, xFunc, xStep, xFinal, pDestructor);
if( rc==SQLITE_OK ){
rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags,
- pUserData, xSFunc, xStep, xFinal, pDestructor);
+ pUserData, xFunc, xStep, xFinal, pDestructor);
}
if( rc!=SQLITE_OK ){
return rc;
@@ -137284,7 +129569,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
** is being overridden/deleted but there are no active VMs, allow the
** operation to continue but invalidate all precompiled statements.
*/
- p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 0);
+ p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 0);
if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){
if( db->nVdbeActive ){
sqlite3ErrorWithMsg(db, SQLITE_BUSY,
@@ -137296,10 +129581,10 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
}
}
- p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 1);
+ p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 1);
assert(p || db->mallocFailed);
if( !p ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
/* If an older version of the function with a configured destructor is
@@ -137309,10 +129594,11 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
if( pDestructor ){
pDestructor->nRef++;
}
- p->u.pDestructor = pDestructor;
+ p->pDestructor = pDestructor;
p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags;
testcase( p->funcFlags & SQLITE_DETERMINISTIC );
- p->xSFunc = xSFunc ? xSFunc : xStep;
+ p->xFunc = xFunc;
+ p->xStep = xStep;
p->xFinalize = xFinal;
p->pUserData = pUserData;
p->nArg = (u16)nArg;
@@ -137328,11 +129614,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
int nArg,
int enc,
void *p,
- void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
void (*xFinal)(sqlite3_context*)
){
- return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xSFunc, xStep,
+ return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xFunc, xStep,
xFinal, 0);
}
@@ -137342,7 +129628,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
int nArg,
int enc,
void *p,
- void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value **),
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
void (*xFinal)(sqlite3_context*),
void (*xDestroy)(void *)
@@ -137365,7 +129651,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
pArg->xDestroy = xDestroy;
pArg->pUserData = p;
}
- rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, pArg);
+ rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xFunc, xStep, xFinal, pArg);
if( pArg && pArg->nRef==0 ){
assert( rc!=SQLITE_OK );
xDestroy(p);
@@ -137385,7 +129671,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
int nArg,
int eTextRep,
void *p,
- void (*xSFunc)(sqlite3_context*,int,sqlite3_value**),
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
){
@@ -137398,7 +129684,7 @@ SQLITE_API int SQLITE_STDCALL 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, xSFunc,xStep,xFinal,0);
+ rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal,0);
sqlite3DbFree(db, zFunc8);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
@@ -137424,6 +129710,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(
const char *zName,
int nArg
){
+ int nName = sqlite3Strlen30(zName);
int rc = SQLITE_OK;
#ifdef SQLITE_ENABLE_API_ARMOR
@@ -137432,7 +129719,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(
}
#endif
sqlite3_mutex_enter(db->mutex);
- if( sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)==0 ){
+ if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){
rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
0, sqlite3InvalidFunction, 0, 0, 0);
}
@@ -137572,27 +129859,6 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(
return pRet;
}
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
-/*
-** Register a callback to be invoked each time a row is updated,
-** inserted or deleted using this database connection.
-*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_preupdate_hook(
- sqlite3 *db, /* Attach the hook to this database */
- void(*xCallback)( /* Callback function */
- void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64),
- void *pArg /* First callback argument */
-){
- void *pRet;
- sqlite3_mutex_enter(db->mutex);
- pRet = db->pPreUpdateArg;
- db->xPreUpdateCallback = xCallback;
- db->pPreUpdateArg = pArg;
- sqlite3_mutex_leave(db->mutex);
- return pRet;
-}
-#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
-
#ifndef SQLITE_OMIT_WAL
/*
** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint().
@@ -137807,11 +130073,9 @@ SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3 *db){
return ( db->temp_store!=1 );
#endif
#if SQLITE_TEMP_STORE==3
- UNUSED_PARAMETER(db);
return 1;
#endif
#if SQLITE_TEMP_STORE<1 || SQLITE_TEMP_STORE>3
- UNUSED_PARAMETER(db);
return 0;
#endif
}
@@ -137823,14 +130087,14 @@ SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3 *db){
SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3 *db){
const char *z;
if( !db ){
- return sqlite3ErrStr(SQLITE_NOMEM_BKPT);
+ return sqlite3ErrStr(SQLITE_NOMEM);
}
if( !sqlite3SafetyCheckSickOrOk(db) ){
return sqlite3ErrStr(SQLITE_MISUSE_BKPT);
}
sqlite3_mutex_enter(db->mutex);
if( db->mallocFailed ){
- z = sqlite3ErrStr(SQLITE_NOMEM_BKPT);
+ z = sqlite3ErrStr(SQLITE_NOMEM);
}else{
testcase( db->pErr==0 );
z = (char*)sqlite3_value_text(db->pErr);
@@ -137882,7 +130146,7 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3 *db){
** be cleared before returning. Do this directly, instead of via
** sqlite3ApiExit(), to avoid setting the database handle error message.
*/
- sqlite3OomClear(db);
+ db->mallocFailed = 0;
}
sqlite3_mutex_leave(db->mutex);
return z;
@@ -137898,7 +130162,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_errcode(sqlite3 *db){
return SQLITE_MISUSE_BKPT;
}
if( !db || db->mallocFailed ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
return db->errCode & db->errMask;
}
@@ -137907,13 +130171,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_extended_errcode(sqlite3 *db){
return SQLITE_MISUSE_BKPT;
}
if( !db || db->mallocFailed ){
- return SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM;
}
return db->errCode;
}
-SQLITE_API int SQLITE_STDCALL sqlite3_system_errno(sqlite3 *db){
- return db ? db->iSysErrno : 0;
-}
/*
** Return a string that describes the kind of error specified in the
@@ -137990,7 +130251,7 @@ static int createCollation(
}
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 1);
- if( pColl==0 ) return SQLITE_NOMEM_BKPT;
+ if( pColl==0 ) return SQLITE_NOMEM;
pColl->xCmp = xCompare;
pColl->pUser = pCtx;
pColl->xDel = xDel;
@@ -138038,8 +130299,8 @@ static const int aHardLimit[] = {
#if SQLITE_MAX_VDBE_OP<40
# error SQLITE_MAX_VDBE_OP must be at least 40
#endif
-#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>127
-# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 127
+#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>1000
+# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 1000
#endif
#if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>125
# error SQLITE_MAX_ATTACHED must be between 0 and 125
@@ -138169,7 +130430,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&');
zFile = sqlite3_malloc64(nByte);
- if( !zFile ) return SQLITE_NOMEM_BKPT;
+ if( !zFile ) return SQLITE_NOMEM;
iIn = 5;
#ifdef SQLITE_ALLOW_URI_AUTHORITY
@@ -138335,7 +130596,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
}else{
zFile = sqlite3_malloc64(nUri+2);
- if( !zFile ) return SQLITE_NOMEM_BKPT;
+ if( !zFile ) return SQLITE_NOMEM;
memcpy(zFile, zUri, nUri);
zFile[nUri] = '\0';
zFile[nUri+1] = '\0';
@@ -138489,12 +130750,6 @@ static int openDatabase(
#if defined(SQLITE_REVERSE_UNORDERED_SELECTS)
| SQLITE_ReverseOrder
#endif
-#if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK)
- | SQLITE_CellSizeCk
-#endif
-#if defined(SQLITE_ENABLE_FTS3_TOKENIZER)
- | SQLITE_Fts3Tokenizer
-#endif
;
sqlite3HashInit(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -138508,9 +130763,9 @@ static int openDatabase(
** EVIDENCE-OF: R-52786-44878 SQLite defines three built-in collating
** functions:
*/
- createCollation(db, sqlite3StrBINARY, SQLITE_UTF8, 0, binCollFunc, 0);
- createCollation(db, sqlite3StrBINARY, SQLITE_UTF16BE, 0, binCollFunc, 0);
- createCollation(db, sqlite3StrBINARY, SQLITE_UTF16LE, 0, binCollFunc, 0);
+ createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc, 0);
+ createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc, 0);
+ createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc, 0);
createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
createCollation(db, "RTRIM", SQLITE_UTF8, (void*)1, binCollFunc, 0);
if( db->mallocFailed ){
@@ -138519,14 +130774,14 @@ static int openDatabase(
/* EVIDENCE-OF: R-08308-17224 The default collating function for all
** strings is BINARY.
*/
- db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, sqlite3StrBINARY, 0);
+ db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 0);
assert( db->pDfltColl!=0 );
/* Parse the filename/URI argument. */
db->openFlags = flags;
rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
if( rc!=SQLITE_OK ){
- if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
+ if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
sqlite3_free(zErrMsg);
goto opendb_out;
@@ -138537,7 +130792,7 @@ static int openDatabase(
flags | SQLITE_OPEN_MAIN_DB);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_IOERR_NOMEM ){
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}
sqlite3Error(db, rc);
goto opendb_out;
@@ -138548,13 +130803,13 @@ static int openDatabase(
sqlite3BtreeLeave(db->aDb[0].pBt);
db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);
- /* The default safety_level for the main database is FULL; for the temp
- ** database it is OFF. This matches the pager layer defaults.
+ /* The default safety_level for the main database is 'full'; for the temp
+ ** database it is 'NONE'. This matches the pager layer defaults.
*/
db->aDb[0].zName = "main";
- db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
+ db->aDb[0].safety_level = 3;
db->aDb[1].zName = "temp";
- db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF;
+ db->aDb[1].safety_level = 1;
db->magic = SQLITE_MAGIC_OPEN;
if( db->mallocFailed ){
@@ -138566,7 +130821,7 @@ static int openDatabase(
** is accessed.
*/
sqlite3Error(db, SQLITE_OK);
- sqlite3RegisterPerConnectionBuiltinFunctions(db);
+ sqlite3RegisterBuiltinFunctions(db);
/* Load automatic extensions - extensions that have been registered
** using the sqlite3_automatic_extension() API.
@@ -138594,18 +130849,12 @@ static int openDatabase(
}
#endif
-#ifdef SQLITE_ENABLE_FTS3 /* automatically defined by SQLITE_ENABLE_FTS4 */
+#ifdef SQLITE_ENABLE_FTS3
if( !db->mallocFailed && rc==SQLITE_OK ){
rc = sqlite3Fts3Init(db);
}
#endif
-#ifdef SQLITE_ENABLE_FTS5
- if( !db->mallocFailed && rc==SQLITE_OK ){
- rc = sqlite3Fts5Init(db);
- }
-#endif
-
#ifdef SQLITE_ENABLE_ICU
if( !db->mallocFailed && rc==SQLITE_OK ){
rc = sqlite3IcuInit(db);
@@ -138620,13 +130869,8 @@ static int openDatabase(
#ifdef SQLITE_ENABLE_DBSTAT_VTAB
if( !db->mallocFailed && rc==SQLITE_OK){
- rc = sqlite3DbstatRegister(db);
- }
-#endif
-
-#ifdef SQLITE_ENABLE_JSON1
- if( !db->mallocFailed && rc==SQLITE_OK){
- rc = sqlite3Json1Init(db);
+ int sqlite3_dbstat_register(sqlite3*);
+ rc = sqlite3_dbstat_register(db);
}
#endif
@@ -138649,6 +130893,7 @@ static int openDatabase(
sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT);
opendb_out:
+ sqlite3_free(zOpen);
if( db ){
assert( db->mutex!=0 || isThreadsafe==0
|| sqlite3GlobalConfig.bFullMutex==0 );
@@ -138670,23 +130915,7 @@ opendb_out:
sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0);
}
#endif
-#if defined(SQLITE_HAS_CODEC)
- if( rc==SQLITE_OK ){
- const char *zHexKey = sqlite3_uri_parameter(zOpen, "hexkey");
- if( zHexKey && zHexKey[0] ){
- u8 iByte;
- int i;
- char zKey[40];
- for(i=0, iByte=0; i<sizeof(zKey)*2 && sqlite3Isxdigit(zHexKey[i]); i++){
- iByte = (iByte<<4) + sqlite3HexToInt(zHexKey[i]);
- if( (i&1)!=0 ) zKey[i/2] = iByte;
- }
- sqlite3_key_v2(db, 0, zKey, i/2);
- }
- }
-#endif
- sqlite3_free(zOpen);
- return rc & 0xff;
+ return sqlite3ApiExit(0, rc);
}
/*
@@ -138740,11 +130969,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_open16(
SCHEMA_ENC(*ppDb) = ENC(*ppDb) = SQLITE_UTF16NATIVE;
}
}else{
- rc = SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}
sqlite3ValueFree(pVal);
- return rc & 0xff;
+ return sqlite3ApiExit(0, rc);
}
#endif /* SQLITE_OMIT_UTF16 */
@@ -138885,7 +131114,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3 *db){
/*
** The following routines are substitutes for constants SQLITE_CORRUPT,
-** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_NOMEM and possibly other error
+** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_IOERR and possibly other error
** constants. They serve two purposes:
**
** 1. Serve as a convenient place to set a breakpoint in a debugger
@@ -138894,33 +131123,28 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3 *db){
** 2. Invoke sqlite3_log() to provide the source code location where
** a low-level error is first detected.
*/
-static int reportError(int iErr, int lineno, const char *zType){
- sqlite3_log(iErr, "%s at line %d of [%.10s]",
- zType, lineno, 20+sqlite3_sourceid());
- return iErr;
-}
SQLITE_PRIVATE int sqlite3CorruptError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
- return reportError(SQLITE_CORRUPT, lineno, "database corruption");
+ sqlite3_log(SQLITE_CORRUPT,
+ "database corruption at line %d of [%.10s]",
+ lineno, 20+sqlite3_sourceid());
+ return SQLITE_CORRUPT;
}
SQLITE_PRIVATE int sqlite3MisuseError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
- return reportError(SQLITE_MISUSE, lineno, "misuse");
+ sqlite3_log(SQLITE_MISUSE,
+ "misuse at line %d of [%.10s]",
+ lineno, 20+sqlite3_sourceid());
+ return SQLITE_MISUSE;
}
SQLITE_PRIVATE int sqlite3CantopenError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
- return reportError(SQLITE_CANTOPEN, lineno, "cannot open file");
-}
-#ifdef SQLITE_DEBUG
-SQLITE_PRIVATE int sqlite3NomemError(int lineno){
- testcase( sqlite3GlobalConfig.xLog!=0 );
- return reportError(SQLITE_NOMEM, lineno, "OOM");
+ sqlite3_log(SQLITE_CANTOPEN,
+ "cannot open file at line %d of [%.10s]",
+ lineno, 20+sqlite3_sourceid());
+ return SQLITE_CANTOPEN;
}
-SQLITE_PRIVATE int sqlite3IoerrnomemError(int lineno){
- testcase( sqlite3GlobalConfig.xLog!=0 );
- return reportError(SQLITE_IOERR_NOMEM, lineno, "I/O OOM error");
-}
-#endif
+
#ifndef SQLITE_OMIT_DEPRECATED
/*
@@ -139014,7 +131238,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
** explicitly declared column. Copy meta information from *pCol.
*/
if( pCol ){
- zDataType = sqlite3ColumnType(pCol,0);
+ zDataType = pCol->zType;
zCollSeq = pCol->zColl;
notnull = pCol->notNull!=0;
primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0;
@@ -139024,7 +131248,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
primarykey = 1;
}
if( !zCollSeq ){
- zCollSeq = sqlite3StrBINARY;
+ zCollSeq = "BINARY";
}
error_out:
@@ -139105,12 +131329,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3 *db, const char *zDbN
if( op==SQLITE_FCNTL_FILE_POINTER ){
*(sqlite3_file**)pArg = fd;
rc = SQLITE_OK;
- }else if( op==SQLITE_FCNTL_VFS_POINTER ){
- *(sqlite3_vfs**)pArg = sqlite3PagerVfs(pPager);
- rc = SQLITE_OK;
- }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){
- *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager);
- rc = SQLITE_OK;
}else if( fd->pMethods ){
rc = sqlite3OsFileControl(fd, op, pArg);
}else{
@@ -139127,9 +131345,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3 *db, const char *zDbN
*/
SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
int rc = 0;
-#ifdef SQLITE_OMIT_BUILTIN_TEST
- UNUSED_PARAMETER(op);
-#else
+#ifndef SQLITE_OMIT_BUILTIN_TEST
va_list ap;
va_start(ap, op);
switch( op ){
@@ -139251,7 +131467,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
*/
case SQLITE_TESTCTRL_ASSERT: {
volatile int x = 0;
- assert( /*side-effects-ok*/ (x = va_arg(ap,int))!=0 );
+ assert( (x = va_arg(ap,int))!=0 );
rc = x;
break;
}
@@ -139554,88 +131770,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbNa
return pBt ? sqlite3BtreeIsReadonly(pBt) : -1;
}
-#ifdef SQLITE_ENABLE_SNAPSHOT
-/*
-** Obtain a snapshot handle for the snapshot of database zDb currently
-** being read by handle db.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3_snapshot_get(
- sqlite3 *db,
- const char *zDb,
- sqlite3_snapshot **ppSnapshot
-){
- int rc = SQLITE_ERROR;
-#ifndef SQLITE_OMIT_WAL
- int iDb;
-
-#ifdef SQLITE_ENABLE_API_ARMOR
- if( !sqlite3SafetyCheckOk(db) ){
- return SQLITE_MISUSE_BKPT;
- }
-#endif
- sqlite3_mutex_enter(db->mutex);
-
- iDb = sqlite3FindDbName(db, zDb);
- if( iDb==0 || iDb>1 ){
- Btree *pBt = db->aDb[iDb].pBt;
- if( 0==sqlite3BtreeIsInTrans(pBt) ){
- rc = sqlite3BtreeBeginTrans(pBt, 0);
- if( rc==SQLITE_OK ){
- rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot);
- }
- }
- }
-
- sqlite3_mutex_leave(db->mutex);
-#endif /* SQLITE_OMIT_WAL */
- return rc;
-}
-
-/*
-** Open a read-transaction on the snapshot idendified by pSnapshot.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3_snapshot_open(
- sqlite3 *db,
- const char *zDb,
- sqlite3_snapshot *pSnapshot
-){
- int rc = SQLITE_ERROR;
-#ifndef SQLITE_OMIT_WAL
-
-#ifdef SQLITE_ENABLE_API_ARMOR
- if( !sqlite3SafetyCheckOk(db) ){
- return SQLITE_MISUSE_BKPT;
- }
-#endif
- sqlite3_mutex_enter(db->mutex);
- if( db->autoCommit==0 ){
- int iDb;
- iDb = sqlite3FindDbName(db, zDb);
- if( iDb==0 || iDb>1 ){
- Btree *pBt = db->aDb[iDb].pBt;
- if( 0==sqlite3BtreeIsInReadTrans(pBt) ){
- rc = sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), pSnapshot);
- if( rc==SQLITE_OK ){
- rc = sqlite3BtreeBeginTrans(pBt, 0);
- sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), 0);
- }
- }
- }
- }
-
- sqlite3_mutex_leave(db->mutex);
-#endif /* SQLITE_OMIT_WAL */
- return rc;
-}
-
-/*
-** Free a snapshot handle obtained from sqlite3_snapshot_get().
-*/
-SQLITE_API void SQLITE_STDCALL sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){
- sqlite3_free(pSnapshot);
-}
-#endif /* SQLITE_ENABLE_SNAPSHOT */
-
/************** End of main.c ************************************************/
/************** Begin file notify.c ******************************************/
/*
@@ -139653,8 +131787,6 @@ SQLITE_API void SQLITE_STDCALL sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot
** This file contains the implementation of the sqlite3_unlock_notify()
** API method and its associated functionality.
*/
-/* #include "sqliteInt.h" */
-/* #include "btreeInt.h" */
/* Omit this entire file if SQLITE_ENABLE_UNLOCK_NOTIFY is not defined. */
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
@@ -140285,12 +132417,6 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
# define NDEBUG 1
#endif
-/* FTS3/FTS4 require virtual tables */
-#ifdef SQLITE_OMIT_VIRTUALTABLE
-# undef SQLITE_ENABLE_FTS3
-# undef SQLITE_ENABLE_FTS4
-#endif
-
/*
** FTS4 is really an extension for FTS3. It is enabled using the
** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also all
@@ -140304,11 +132430,9 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
/* If not building as part of the core, include sqlite3ext.h. */
#ifndef SQLITE_CORE
-/* # include "sqlite3ext.h" */
SQLITE_EXTENSION_INIT3
#endif
-/* #include "sqlite3.h" */
/************** Include fts3_tokenizer.h in the middle of fts3Int.h **********/
/************** Begin file fts3_tokenizer.h **********************************/
/*
@@ -140337,7 +132461,6 @@ SQLITE_EXTENSION_INIT3
** If tokenizers are to be allowed to call sqlite3_*() functions, then
** we will need a way to register the API consistently.
*/
-/* #include "sqlite3.h" */
/*
** Structures used by the tokenizer interface. When a new tokenizer
@@ -140751,8 +132874,6 @@ typedef struct Fts3DeferredToken Fts3DeferredToken;
typedef struct Fts3SegReader Fts3SegReader;
typedef struct Fts3MultiSegReader Fts3MultiSegReader;
-typedef struct MatchinfoBuffer MatchinfoBuffer;
-
/*
** A connection to a fulltext index is an instance of the following
** structure. The xCreate and xConnect methods create an instance
@@ -140818,7 +132939,6 @@ struct Fts3Table {
int nPendingData; /* Current bytes of pending data */
sqlite_int64 iPrevDocid; /* Docid of most recently inserted document */
int iPrevLangid; /* Langid of recently inserted document */
- int bPrevDelete; /* True if last operation was a delete */
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
/* State variables used for validating that the transaction control
@@ -140863,7 +132983,9 @@ struct Fts3Cursor {
i64 iMinDocid; /* Minimum docid to return */
i64 iMaxDocid; /* Maximum docid to return */
int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */
- MatchinfoBuffer *pMIBuffer; /* Buffer for matchinfo data */
+ u32 *aMatchinfo; /* Information about most recent match */
+ int nMatchinfo; /* Number of elements in aMatchinfo[] */
+ char *zMatchinfo; /* Matchinfo specification */
};
#define FTS3_EVAL_FILTER 0
@@ -140983,9 +133105,7 @@ struct Fts3Expr {
u8 bStart; /* True if iDocid is valid */
u8 bDeferred; /* True if this expression is entirely deferred */
- /* The following are used by the fts3_snippet.c module. */
- int iPhrase; /* Index of this phrase in matchinfo() results */
- u32 *aMI; /* See above */
+ u32 *aMI;
};
/*
@@ -141106,7 +133226,6 @@ SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,i
SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *);
SQLITE_PRIVATE int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *);
SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int*, Fts3Table*);
-SQLITE_PRIVATE int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc);
/* fts3_tokenizer.c */
SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *);
@@ -141122,7 +133241,6 @@ SQLITE_PRIVATE void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const ch
const char *, const char *, int, int
);
SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *);
-SQLITE_PRIVATE void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p);
/* fts3_expr.c */
SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *, int,
@@ -141179,9 +133297,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int);
/* #include <string.h> */
/* #include <stdarg.h> */
-/* #include "fts3.h" */
#ifndef SQLITE_CORE
-/* # include "sqlite3ext.h" */
SQLITE_EXTENSION_INIT1
#endif
@@ -142394,19 +134510,6 @@ static void fts3SetEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){
#endif
}
-/*
-** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this
-** extension is currently being used by a version of SQLite too old to
-** support index-info flags. In that case this function is a no-op.
-*/
-static void fts3SetUniqueFlag(sqlite3_index_info *pIdxInfo){
-#if SQLITE_VERSION_NUMBER>=3008012
- if( sqlite3_libversion_number()>=3008012 ){
- pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE;
- }
-#endif
-}
-
/*
** Implementation of the xBestIndex method for FTS3 tables. There
** are three possible strategies, in order of preference:
@@ -142497,9 +134600,6 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
}
}
- /* If using a docid=? or rowid=? strategy, set the UNIQUE flag. */
- if( pInfo->idxNum==FTS3_DOCID_SEARCH ) fts3SetUniqueFlag(pInfo);
-
iIdx = 1;
if( iCons>=0 ){
pInfo->aConstraintUsage[iCons].argvIndex = iIdx++;
@@ -142568,7 +134668,7 @@ static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){
sqlite3Fts3ExprFree(pCsr->pExpr);
sqlite3Fts3FreeDeferredTokens(pCsr);
sqlite3_free(pCsr->aDoclist);
- sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
+ sqlite3_free(pCsr->aMatchinfo);
assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
sqlite3_free(pCsr);
return SQLITE_OK;
@@ -144069,7 +136169,7 @@ static int fts3FilterMethod(
/* In case the cursor has been used before, clear it now. */
sqlite3_finalize(pCsr->pStmt);
sqlite3_free(pCsr->aDoclist);
- sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
+ sqlite3_free(pCsr->aMatchinfo);
sqlite3Fts3ExprFree(pCsr->pExpr);
memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));
@@ -145124,6 +137224,7 @@ static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){
int bIncrOk = (bOptOk
&& pCsr->bDesc==pTab->bDescIdx
&& p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0
+ && p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0
#ifdef SQLITE_TEST
&& pTab->bNoIncrDoclist==0
#endif
@@ -145243,7 +137344,6 @@ SQLITE_PRIVATE void sqlite3Fts3DoclistNext(
p += sqlite3Fts3GetVarint(p, piDocid);
}else{
fts3PoslistCopy(0, &p);
- while( p<&aDoclist[nDoclist] && *p==0 ) p++;
if( p>=&aDoclist[nDoclist] ){
*pbEof = 1;
}else{
@@ -145967,7 +138067,7 @@ static int fts3EvalNearTrim(
** 2. NEAR is treated as AND. If the expression is "x NEAR y", it is
** advanced to point to the next row that matches "x AND y".
**
-** See sqlite3Fts3EvalTestDeferred() for details on testing if a row is
+** See fts3EvalTestDeferredAndNear() for details on testing if a row is
** really a match, taking into account deferred tokens and NEAR operators.
*/
static void fts3EvalNextRow(
@@ -146187,7 +138287,7 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
}
/*
-** This function is a helper function for sqlite3Fts3EvalTestDeferred().
+** This function is a helper function for fts3EvalTestDeferredAndNear().
** Assuming no error occurs or has occurred, It returns non-zero if the
** expression passed as the second argument matches the row that pCsr
** currently points to, or zero if it does not.
@@ -146308,7 +138408,7 @@ static int fts3EvalTestExpr(
** Or, if no error occurs and it seems the current row does match the FTS
** query, return 0.
*/
-SQLITE_PRIVATE int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc){
+static int fts3EvalTestDeferredAndNear(Fts3Cursor *pCsr, int *pRc){
int rc = *pRc;
int bMiss = 0;
if( rc==SQLITE_OK ){
@@ -146355,7 +138455,7 @@ static int fts3EvalNext(Fts3Cursor *pCsr){
pCsr->isRequireSeek = 1;
pCsr->isMatchinfoNeeded = 1;
pCsr->iPrevId = pExpr->iDocid;
- }while( pCsr->isEof==0 && sqlite3Fts3EvalTestDeferred(pCsr, &rc) );
+ }while( pCsr->isEof==0 && fts3EvalTestDeferredAndNear(pCsr, &rc) );
}
/* Check if the cursor is past the end of the docid range specified
@@ -146516,7 +138616,7 @@ static int fts3EvalGatherStats(
pCsr->iPrevId = pRoot->iDocid;
}while( pCsr->isEof==0
&& pRoot->eType==FTSQUERY_NEAR
- && sqlite3Fts3EvalTestDeferred(pCsr, &rc)
+ && fts3EvalTestDeferredAndNear(pCsr, &rc)
);
if( rc==SQLITE_OK && pCsr->isEof==0 ){
@@ -146541,6 +138641,7 @@ static int fts3EvalGatherStats(
fts3EvalNextRow(pCsr, pRoot, &rc);
assert( pRoot->bEof==0 );
}while( pRoot->iDocid!=iDocid && rc==SQLITE_OK );
+ fts3EvalTestDeferredAndNear(pCsr, &rc);
}
}
return rc;
@@ -146650,10 +138751,10 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
int rc = SQLITE_OK;
int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */
int bOr = 0;
+ u8 bEof = 0;
u8 bTreeEof = 0;
Fts3Expr *p; /* Used to iterate from pExpr to root */
Fts3Expr *pNear; /* Most senior NEAR ancestor (or pExpr) */
- int bMatch;
/* Check if this phrase descends from an OR expression node. If not,
** return NULL. Otherwise, the entry that corresponds to docid
@@ -146687,47 +138788,31 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
}
if( rc!=SQLITE_OK ) return rc;
- bMatch = 1;
- for(p=pNear; p; p=p->pLeft){
- u8 bEof = 0;
- Fts3Expr *pTest = p;
- Fts3Phrase *pPh;
- assert( pTest->eType==FTSQUERY_NEAR || pTest->eType==FTSQUERY_PHRASE );
- if( pTest->eType==FTSQUERY_NEAR ) pTest = pTest->pRight;
- assert( pTest->eType==FTSQUERY_PHRASE );
- pPh = pTest->pPhrase;
-
- pIter = pPh->pOrPoslist;
- iDocid = pPh->iOrDocid;
- if( pCsr->bDesc==bDescDoclist ){
- bEof = !pPh->doclist.nAll ||
- (pIter >= (pPh->doclist.aAll + pPh->doclist.nAll));
- while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){
- sqlite3Fts3DoclistNext(
- bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll,
- &pIter, &iDocid, &bEof
- );
- }
- }else{
- bEof = !pPh->doclist.nAll || (pIter && pIter<=pPh->doclist.aAll);
- while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){
- int dummy;
- sqlite3Fts3DoclistPrev(
- bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll,
- &pIter, &iDocid, &dummy, &bEof
- );
- }
+ pIter = pPhrase->pOrPoslist;
+ iDocid = pPhrase->iOrDocid;
+ if( pCsr->bDesc==bDescDoclist ){
+ bEof = !pPhrase->doclist.nAll ||
+ (pIter >= (pPhrase->doclist.aAll + pPhrase->doclist.nAll));
+ while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){
+ sqlite3Fts3DoclistNext(
+ bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
+ &pIter, &iDocid, &bEof
+ );
}
- pPh->pOrPoslist = pIter;
- pPh->iOrDocid = iDocid;
- if( bEof || iDocid!=pCsr->iPrevId ) bMatch = 0;
- }
-
- if( bMatch ){
- pIter = pPhrase->pOrPoslist;
}else{
- pIter = 0;
+ bEof = !pPhrase->doclist.nAll || (pIter && pIter<=pPhrase->doclist.aAll);
+ while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){
+ int dummy;
+ sqlite3Fts3DoclistPrev(
+ bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
+ &pIter, &iDocid, &dummy, &bEof
+ );
+ }
}
+ pPhrase->pOrPoslist = pIter;
+ pPhrase->iOrDocid = iDocid;
+
+ if( bEof || iDocid!=pCsr->iPrevId ) pIter = 0;
}
if( pIter==0 ) return SQLITE_OK;
@@ -146815,7 +138900,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_fts3_init(
******************************************************************************
**
*/
-/* #include "fts3Int.h" */
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
/* #include <string.h> */
@@ -147372,7 +139456,6 @@ SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){
** syntax is relatively simple, the whole tokenizer/parser system is
** hand-coded.
*/
-/* #include "fts3Int.h" */
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
/*
@@ -148150,151 +140233,125 @@ static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){
rc = SQLITE_ERROR;
}
- if( rc==SQLITE_OK ){
- if( (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){
- Fts3Expr **apLeaf;
- apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth);
- if( 0==apLeaf ){
- rc = SQLITE_NOMEM;
- }else{
- memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth);
+ if( rc==SQLITE_OK && (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){
+ Fts3Expr **apLeaf;
+ apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth);
+ if( 0==apLeaf ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth);
+ }
+
+ if( rc==SQLITE_OK ){
+ int i;
+ Fts3Expr *p;
+
+ /* Set $p to point to the left-most leaf in the tree of eType nodes. */
+ for(p=pRoot; p->eType==eType; p=p->pLeft){
+ assert( p->pParent==0 || p->pParent->pLeft==p );
+ assert( p->pLeft && p->pRight );
}
- if( rc==SQLITE_OK ){
- int i;
- Fts3Expr *p;
+ /* This loop runs once for each leaf in the tree of eType nodes. */
+ while( 1 ){
+ int iLvl;
+ Fts3Expr *pParent = p->pParent; /* Current parent of p */
- /* Set $p to point to the left-most leaf in the tree of eType nodes. */
- for(p=pRoot; p->eType==eType; p=p->pLeft){
- assert( p->pParent==0 || p->pParent->pLeft==p );
- assert( p->pLeft && p->pRight );
+ assert( pParent==0 || pParent->pLeft==p );
+ p->pParent = 0;
+ if( pParent ){
+ pParent->pLeft = 0;
+ }else{
+ pRoot = 0;
}
+ rc = fts3ExprBalance(&p, nMaxDepth-1);
+ if( rc!=SQLITE_OK ) break;
- /* This loop runs once for each leaf in the tree of eType nodes. */
- while( 1 ){
- int iLvl;
- Fts3Expr *pParent = p->pParent; /* Current parent of p */
-
- assert( pParent==0 || pParent->pLeft==p );
- p->pParent = 0;
- if( pParent ){
- pParent->pLeft = 0;
+ for(iLvl=0; p && iLvl<nMaxDepth; iLvl++){
+ if( apLeaf[iLvl]==0 ){
+ apLeaf[iLvl] = p;
+ p = 0;
}else{
- pRoot = 0;
+ assert( pFree );
+ pFree->pLeft = apLeaf[iLvl];
+ pFree->pRight = p;
+ pFree->pLeft->pParent = pFree;
+ pFree->pRight->pParent = pFree;
+
+ p = pFree;
+ pFree = pFree->pParent;
+ p->pParent = 0;
+ apLeaf[iLvl] = 0;
}
- rc = fts3ExprBalance(&p, nMaxDepth-1);
- if( rc!=SQLITE_OK ) break;
+ }
+ if( p ){
+ sqlite3Fts3ExprFree(p);
+ rc = SQLITE_TOOBIG;
+ break;
+ }
+
+ /* If that was the last leaf node, break out of the loop */
+ if( pParent==0 ) break;
+
+ /* Set $p to point to the next leaf in the tree of eType nodes */
+ for(p=pParent->pRight; p->eType==eType; p=p->pLeft);
- for(iLvl=0; p && iLvl<nMaxDepth; iLvl++){
- if( apLeaf[iLvl]==0 ){
- apLeaf[iLvl] = p;
- p = 0;
+ /* Remove pParent from the original tree. */
+ assert( pParent->pParent==0 || pParent->pParent->pLeft==pParent );
+ pParent->pRight->pParent = pParent->pParent;
+ if( pParent->pParent ){
+ pParent->pParent->pLeft = pParent->pRight;
+ }else{
+ assert( pParent==pRoot );
+ pRoot = pParent->pRight;
+ }
+
+ /* Link pParent into the free node list. It will be used as an
+ ** internal node of the new tree. */
+ pParent->pParent = pFree;
+ pFree = pParent;
+ }
+
+ if( rc==SQLITE_OK ){
+ p = 0;
+ for(i=0; i<nMaxDepth; i++){
+ if( apLeaf[i] ){
+ if( p==0 ){
+ p = apLeaf[i];
+ p->pParent = 0;
}else{
- assert( pFree );
- pFree->pLeft = apLeaf[iLvl];
+ assert( pFree!=0 );
pFree->pRight = p;
+ pFree->pLeft = apLeaf[i];
pFree->pLeft->pParent = pFree;
pFree->pRight->pParent = pFree;
p = pFree;
pFree = pFree->pParent;
p->pParent = 0;
- apLeaf[iLvl] = 0;
}
}
- if( p ){
- sqlite3Fts3ExprFree(p);
- rc = SQLITE_TOOBIG;
- break;
- }
-
- /* If that was the last leaf node, break out of the loop */
- if( pParent==0 ) break;
-
- /* Set $p to point to the next leaf in the tree of eType nodes */
- for(p=pParent->pRight; p->eType==eType; p=p->pLeft);
-
- /* Remove pParent from the original tree. */
- assert( pParent->pParent==0 || pParent->pParent->pLeft==pParent );
- pParent->pRight->pParent = pParent->pParent;
- if( pParent->pParent ){
- pParent->pParent->pLeft = pParent->pRight;
- }else{
- assert( pParent==pRoot );
- pRoot = pParent->pRight;
- }
-
- /* Link pParent into the free node list. It will be used as an
- ** internal node of the new tree. */
- pParent->pParent = pFree;
- pFree = pParent;
}
-
- if( rc==SQLITE_OK ){
- p = 0;
- for(i=0; i<nMaxDepth; i++){
- if( apLeaf[i] ){
- if( p==0 ){
- p = apLeaf[i];
- p->pParent = 0;
- }else{
- assert( pFree!=0 );
- pFree->pRight = p;
- pFree->pLeft = apLeaf[i];
- pFree->pLeft->pParent = pFree;
- pFree->pRight->pParent = pFree;
-
- p = pFree;
- pFree = pFree->pParent;
- p->pParent = 0;
- }
- }
- }
- pRoot = p;
- }else{
- /* An error occurred. Delete the contents of the apLeaf[] array
- ** and pFree list. Everything else is cleaned up by the call to
- ** sqlite3Fts3ExprFree(pRoot) below. */
- Fts3Expr *pDel;
- for(i=0; i<nMaxDepth; i++){
- sqlite3Fts3ExprFree(apLeaf[i]);
- }
- while( (pDel=pFree)!=0 ){
- pFree = pDel->pParent;
- sqlite3_free(pDel);
- }
+ pRoot = p;
+ }else{
+ /* An error occurred. Delete the contents of the apLeaf[] array
+ ** and pFree list. Everything else is cleaned up by the call to
+ ** sqlite3Fts3ExprFree(pRoot) below. */
+ Fts3Expr *pDel;
+ for(i=0; i<nMaxDepth; i++){
+ sqlite3Fts3ExprFree(apLeaf[i]);
+ }
+ while( (pDel=pFree)!=0 ){
+ pFree = pDel->pParent;
+ sqlite3_free(pDel);
}
-
- assert( pFree==0 );
- sqlite3_free( apLeaf );
- }
- }else if( eType==FTSQUERY_NOT ){
- Fts3Expr *pLeft = pRoot->pLeft;
- Fts3Expr *pRight = pRoot->pRight;
-
- pRoot->pLeft = 0;
- pRoot->pRight = 0;
- pLeft->pParent = 0;
- pRight->pParent = 0;
-
- rc = fts3ExprBalance(&pLeft, nMaxDepth-1);
- if( rc==SQLITE_OK ){
- rc = fts3ExprBalance(&pRight, nMaxDepth-1);
}
- if( rc!=SQLITE_OK ){
- sqlite3Fts3ExprFree(pRight);
- sqlite3Fts3ExprFree(pLeft);
- }else{
- assert( pLeft && pRight );
- pRoot->pLeft = pLeft;
- pLeft->pParent = pRoot;
- pRoot->pRight = pRight;
- pRight->pParent = pRoot;
- }
+ assert( pFree==0 );
+ sqlite3_free( apLeaf );
}
}
-
+
if( rc!=SQLITE_OK ){
sqlite3Fts3ExprFree(pRoot);
pRoot = 0;
@@ -148692,14 +140749,12 @@ SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3* db){
** * The FTS3 module is being built into the core of
** SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
*/
-/* #include "fts3Int.h" */
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
/* #include <assert.h> */
/* #include <stdlib.h> */
/* #include <string.h> */
-/* #include "fts3_hash.h" */
/*
** Malloc and Free functions
@@ -149077,7 +141132,6 @@ SQLITE_PRIVATE void *sqlite3Fts3HashInsert(
** * The FTS3 module is being built into the core of
** SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
*/
-/* #include "fts3Int.h" */
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
/* #include <assert.h> */
@@ -149085,7 +141139,6 @@ SQLITE_PRIVATE void *sqlite3Fts3HashInsert(
/* #include <stdio.h> */
/* #include <string.h> */
-/* #include "fts3_tokenizer.h" */
/*
** Class derived from sqlite3_tokenizer
@@ -149743,25 +141796,12 @@ SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(
** * The FTS3 module is being built into the core of
** SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
*/
-/* #include "fts3Int.h" */
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
/* #include <assert.h> */
/* #include <string.h> */
/*
-** Return true if the two-argument version of fts3_tokenizer()
-** has been activated via a prior call to sqlite3_db_config(db,
-** SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, 0);
-*/
-static int fts3TokenizerEnabled(sqlite3_context *context){
- sqlite3 *db = sqlite3_context_db_handle(context);
- int isEnabled = 0;
- sqlite3_db_config(db,SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER,-1,&isEnabled);
- return isEnabled;
-}
-
-/*
** Implementation of the SQL scalar function for accessing the underlying
** hash table. This function may be called as follows:
**
@@ -149781,7 +141821,7 @@ static int fts3TokenizerEnabled(sqlite3_context *context){
** is a blob containing the pointer stored as the hash data corresponding
** to string <key-name> (after the hash-table is updated, if applicable).
*/
-static void fts3TokenizerFunc(
+static void scalarFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
@@ -149799,20 +141839,16 @@ static void fts3TokenizerFunc(
nName = sqlite3_value_bytes(argv[0])+1;
if( argc==2 ){
- if( fts3TokenizerEnabled(context) ){
- void *pOld;
- int n = sqlite3_value_bytes(argv[1]);
- if( zName==0 || n!=sizeof(pPtr) ){
- sqlite3_result_error(context, "argument type mismatch", -1);
- return;
- }
- pPtr = *(void **)sqlite3_value_blob(argv[1]);
- pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr);
- if( pOld==pPtr ){
- sqlite3_result_error(context, "out of memory", -1);
- }
- }else{
- sqlite3_result_error(context, "fts3tokenize disabled", -1);
+ void *pOld;
+ int n = sqlite3_value_bytes(argv[1]);
+ if( zName==0 || n!=sizeof(pPtr) ){
+ sqlite3_result_error(context, "argument type mismatch", -1);
+ return;
+ }
+ pPtr = *(void **)sqlite3_value_blob(argv[1]);
+ pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr);
+ if( pOld==pPtr ){
+ sqlite3_result_error(context, "out of memory", -1);
return;
}
}else{
@@ -149826,6 +141862,7 @@ static void fts3TokenizerFunc(
return;
}
}
+
sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT);
}
@@ -150085,7 +142122,6 @@ int registerTokenizer(
return sqlite3_finalize(pStmt);
}
-
static
int queryTokenizer(
sqlite3 *db,
@@ -150156,13 +142192,11 @@ static void intTestFunc(
assert( 0==strcmp(sqlite3_errmsg(db), "unknown tokenizer: nosuchtokenizer") );
/* Test the storage function */
- if( fts3TokenizerEnabled(context) ){
- rc = registerTokenizer(db, "nosuchtokenizer", p1);
- assert( rc==SQLITE_OK );
- rc = queryTokenizer(db, "nosuchtokenizer", &p2);
- assert( rc==SQLITE_OK );
- assert( p2==p1 );
- }
+ rc = registerTokenizer(db, "nosuchtokenizer", p1);
+ assert( rc==SQLITE_OK );
+ rc = queryTokenizer(db, "nosuchtokenizer", &p2);
+ assert( rc==SQLITE_OK );
+ assert( p2==p1 );
sqlite3_result_text(context, "ok", -1, SQLITE_STATIC);
}
@@ -150178,7 +142212,7 @@ static void intTestFunc(
** sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1);
**
** This function adds a scalar function (see header comment above
-** fts3TokenizerFunc() in this file for details) and, if ENABLE_TABLE is
+** scalarFunc() in this file for details) and, if ENABLE_TABLE is
** defined at compilation time, a temporary virtual table (see header
** comment above struct HashTableVtab) to the database schema. Both
** provide read/write access to the contents of *pHash.
@@ -150207,10 +142241,10 @@ SQLITE_PRIVATE int sqlite3Fts3InitHashTable(
#endif
if( SQLITE_OK==rc ){
- rc = sqlite3_create_function(db, zName, 1, any, p, fts3TokenizerFunc, 0, 0);
+ 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, fts3TokenizerFunc, 0, 0);
+ rc = sqlite3_create_function(db, zName, 2, any, p, scalarFunc, 0, 0);
}
#ifdef SQLITE_TEST
if( SQLITE_OK==rc ){
@@ -150257,7 +142291,6 @@ SQLITE_PRIVATE int sqlite3Fts3InitHashTable(
** * The FTS3 module is being built into the core of
** SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
*/
-/* #include "fts3Int.h" */
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
/* #include <assert.h> */
@@ -150265,7 +142298,6 @@ SQLITE_PRIVATE int sqlite3Fts3InitHashTable(
/* #include <stdio.h> */
/* #include <string.h> */
-/* #include "fts3_tokenizer.h" */
typedef struct simple_tokenizer {
sqlite3_tokenizer base;
@@ -150510,7 +142542,6 @@ SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(
** pos: Token offset of token within input.
**
*/
-/* #include "fts3Int.h" */
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
/* #include <string.h> */
@@ -150946,7 +142977,6 @@ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){
** code in fts3.c.
*/
-/* #include "fts3Int.h" */
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
/* #include <string.h> */
@@ -151262,8 +143292,7 @@ static int fts3SqlStmt(
** of the oldest level in the db that contains at least ? segments. Or,
** if no level in the FTS index contains more than ? segments, the statement
** returns zero rows. */
-/* 28 */ "SELECT level, count(*) AS cnt FROM %Q.'%q_segdir' "
- " GROUP BY level HAVING cnt>=?"
+/* 28 */ "SELECT level FROM %Q.'%q_segdir' GROUP BY level HAVING count(*)>=?"
" ORDER BY (level %% 1024) ASC LIMIT 1",
/* Estimate the upper limit on the number of leaf nodes in a new segment
@@ -151790,12 +143819,10 @@ static int fts3PendingTermsAdd(
*/
static int fts3PendingTermsDocid(
Fts3Table *p, /* Full-text table handle */
- int bDelete, /* True if this op is a delete */
int iLangid, /* Language id of row being written */
sqlite_int64 iDocid /* Docid of row being written */
){
assert( iLangid>=0 );
- assert( bDelete==1 || bDelete==0 );
/* TODO(shess) Explore whether partially flushing the buffer on
** forced-flush would provide better performance. I suspect that if
@@ -151803,8 +143830,7 @@ static int fts3PendingTermsDocid(
** buffer was half empty, that would let the less frequent terms
** generate longer doclists.
*/
- if( iDocid<p->iPrevDocid
- || (iDocid==p->iPrevDocid && p->bPrevDelete==0)
+ if( iDocid<=p->iPrevDocid
|| p->iPrevLangid!=iLangid
|| p->nPendingData>p->nMaxPendingData
){
@@ -151813,7 +143839,6 @@ static int fts3PendingTermsDocid(
}
p->iPrevDocid = iDocid;
p->iPrevLangid = iLangid;
- p->bPrevDelete = bDelete;
return SQLITE_OK;
}
@@ -152003,8 +144028,7 @@ static void fts3DeleteTerms(
if( SQLITE_ROW==sqlite3_step(pSelect) ){
int i;
int iLangid = langidFromSelect(p, pSelect);
- i64 iDocid = sqlite3_column_int64(pSelect, 0);
- rc = fts3PendingTermsDocid(p, 1, iLangid, iDocid);
+ rc = fts3PendingTermsDocid(p, iLangid, sqlite3_column_int64(pSelect, 0));
for(i=1; rc==SQLITE_OK && i<=p->nColumn; i++){
int iCol = i-1;
if( p->abNotindexed[iCol]==0 ){
@@ -152252,19 +144276,14 @@ static int fts3SegReaderNext(
if( fts3SegReaderIsPending(pReader) ){
Fts3HashElem *pElem = *(pReader->ppNextElem);
- sqlite3_free(pReader->aNode);
- pReader->aNode = 0;
- if( pElem ){
- char *aCopy;
+ if( pElem==0 ){
+ pReader->aNode = 0;
+ }else{
PendingList *pList = (PendingList *)fts3HashData(pElem);
- int nCopy = pList->nData+1;
pReader->zTerm = (char *)fts3HashKey(pElem);
pReader->nTerm = fts3HashKeysize(pElem);
- aCopy = (char*)sqlite3_malloc(nCopy);
- if( !aCopy ) return SQLITE_NOMEM;
- memcpy(aCopy, pList->aData, nCopy);
- pReader->nNode = pReader->nDoclist = nCopy;
- pReader->aNode = pReader->aDoclist = aCopy;
+ pReader->nNode = pReader->nDoclist = pList->nData + 1;
+ pReader->aNode = pReader->aDoclist = pList->aData;
pReader->ppNextElem++;
assert( pReader->aNode );
}
@@ -152504,14 +144523,12 @@ SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(
** second argument.
*/
SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){
- if( pReader ){
- if( !fts3SegReaderIsPending(pReader) ){
- sqlite3_free(pReader->zTerm);
- }
+ if( pReader && !fts3SegReaderIsPending(pReader) ){
+ sqlite3_free(pReader->zTerm);
if( !fts3SegReaderIsRootOnly(pReader) ){
sqlite3_free(pReader->aNode);
+ sqlite3_blob_close(pReader->pBlob);
}
- sqlite3_blob_close(pReader->pBlob);
}
sqlite3_free(pReader);
}
@@ -154124,7 +146141,7 @@ static int fts3SegmentMerge(
** segment. The level of the new segment is equal to the numerically
** greatest segment level currently present in the database for this
** index. The idx of the new segment is always 0. */
- if( csr.nSegment==1 && 0==fts3SegReaderIsPending(csr.apSegment[0]) ){
+ if( csr.nSegment==1 ){
rc = SQLITE_DONE;
goto finished;
}
@@ -154454,7 +146471,7 @@ static int fts3DoRebuild(Fts3Table *p){
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
int iCol;
int iLangid = langidFromSelect(p, pStmt);
- rc = fts3PendingTermsDocid(p, 0, iLangid, sqlite3_column_int64(pStmt, 0));
+ rc = fts3PendingTermsDocid(p, iLangid, sqlite3_column_int64(pStmt, 0));
memset(aSz, 0, sizeof(aSz[0]) * (p->nColumn+1));
for(iCol=0; rc==SQLITE_OK && iCol<p->nColumn; iCol++){
if( p->abNotindexed[iCol]==0 ){
@@ -155766,11 +147783,10 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
** set nSeg to -1.
*/
rc = fts3SqlStmt(p, SQL_FIND_MERGE_LEVEL, &pFindLevel, 0);
- sqlite3_bind_int(pFindLevel, 1, MAX(2, nMin));
+ sqlite3_bind_int(pFindLevel, 1, nMin);
if( sqlite3_step(pFindLevel)==SQLITE_ROW ){
iAbsLevel = sqlite3_column_int64(pFindLevel, 0);
- nSeg = sqlite3_column_int(pFindLevel, 1);
- assert( nSeg>=2 );
+ nSeg = nMin;
}else{
nSeg = -1;
}
@@ -156560,7 +148576,7 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
}
}
if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){
- rc = fts3PendingTermsDocid(p, 0, iLangid, *pRowid);
+ rc = fts3PendingTermsDocid(p, iLangid, *pRowid);
}
if( rc==SQLITE_OK ){
assert( p->iPrevDocid==*pRowid );
@@ -156621,7 +148637,6 @@ SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){
******************************************************************************
*/
-/* #include "fts3Int.h" */
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
/* #include <string.h> */
@@ -156638,7 +148653,6 @@ SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){
#define FTS3_MATCHINFO_LCS 's' /* nCol values */
#define FTS3_MATCHINFO_HITS 'x' /* 3*nCol*nPhrase values */
#define FTS3_MATCHINFO_LHITS 'y' /* nCol*nPhrase values */
-#define FTS3_MATCHINFO_LHITS_BM 'b' /* nCol*nPhrase values */
/*
** The default value for the second argument to matchinfo().
@@ -156700,22 +148714,9 @@ struct MatchInfo {
int nCol; /* Number of columns in table */
int nPhrase; /* Number of matchable phrases in query */
sqlite3_int64 nDoc; /* Number of docs in database */
- char flag;
u32 *aMatchinfo; /* Pre-allocated buffer */
};
-/*
-** An instance of this structure is used to manage a pair of buffers, each
-** (nElem * sizeof(u32)) bytes in size. See the MatchinfoBuffer code below
-** for details.
-*/
-struct MatchinfoBuffer {
- u8 aRef[3];
- int nElem;
- int bGlobal; /* Set if global data is loaded */
- char *zMatchinfo;
- u32 aMatchinfo[1];
-};
/*
@@ -156731,97 +148732,6 @@ struct StrBuffer {
};
-/*************************************************************************
-** Start of MatchinfoBuffer code.
-*/
-
-/*
-** Allocate a two-slot MatchinfoBuffer object.
-*/
-static MatchinfoBuffer *fts3MIBufferNew(int nElem, const char *zMatchinfo){
- MatchinfoBuffer *pRet;
- int nByte = sizeof(u32) * (2*nElem + 1) + sizeof(MatchinfoBuffer);
- int nStr = (int)strlen(zMatchinfo);
-
- pRet = sqlite3_malloc(nByte + nStr+1);
- if( pRet ){
- memset(pRet, 0, nByte);
- pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet;
- pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0] + sizeof(u32)*(nElem+1);
- pRet->nElem = nElem;
- pRet->zMatchinfo = ((char*)pRet) + nByte;
- memcpy(pRet->zMatchinfo, zMatchinfo, nStr+1);
- pRet->aRef[0] = 1;
- }
-
- return pRet;
-}
-
-static void fts3MIBufferFree(void *p){
- MatchinfoBuffer *pBuf = (MatchinfoBuffer*)((u8*)p - ((u32*)p)[-1]);
-
- assert( (u32*)p==&pBuf->aMatchinfo[1]
- || (u32*)p==&pBuf->aMatchinfo[pBuf->nElem+2]
- );
- if( (u32*)p==&pBuf->aMatchinfo[1] ){
- pBuf->aRef[1] = 0;
- }else{
- pBuf->aRef[2] = 0;
- }
-
- if( pBuf->aRef[0]==0 && pBuf->aRef[1]==0 && pBuf->aRef[2]==0 ){
- sqlite3_free(pBuf);
- }
-}
-
-static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){
- void (*xRet)(void*) = 0;
- u32 *aOut = 0;
-
- if( p->aRef[1]==0 ){
- p->aRef[1] = 1;
- aOut = &p->aMatchinfo[1];
- xRet = fts3MIBufferFree;
- }
- else if( p->aRef[2]==0 ){
- p->aRef[2] = 1;
- aOut = &p->aMatchinfo[p->nElem+2];
- xRet = fts3MIBufferFree;
- }else{
- aOut = (u32*)sqlite3_malloc(p->nElem * sizeof(u32));
- if( aOut ){
- xRet = sqlite3_free;
- if( p->bGlobal ) memcpy(aOut, &p->aMatchinfo[1], p->nElem*sizeof(u32));
- }
- }
-
- *paOut = aOut;
- return xRet;
-}
-
-static void fts3MIBufferSetGlobal(MatchinfoBuffer *p){
- p->bGlobal = 1;
- memcpy(&p->aMatchinfo[2+p->nElem], &p->aMatchinfo[1], p->nElem*sizeof(u32));
-}
-
-/*
-** Free a MatchinfoBuffer object allocated using fts3MIBufferNew()
-*/
-SQLITE_PRIVATE void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p){
- if( p ){
- assert( p->aRef[0]==1 );
- p->aRef[0] = 0;
- if( p->aRef[0]==0 && p->aRef[1]==0 && p->aRef[2]==0 ){
- sqlite3_free(p);
- }
- }
-}
-
-/*
-** End of MatchinfoBuffer code.
-*************************************************************************/
-
-
/*
** This function is used to help iterate through a position-list. A position
** list is a list of unique integers, sorted from smallest to largest. Each
@@ -156858,7 +148768,7 @@ static int fts3ExprIterate2(
void *pCtx /* Second argument to pass to callback */
){
int rc; /* Return code */
- int eType = pExpr->eType; /* Type of expression node pExpr */
+ int eType = pExpr->eType; /* Type of expression node pExpr */
if( eType!=FTSQUERY_PHRASE ){
assert( pExpr->pLeft && pExpr->pRight );
@@ -156892,7 +148802,6 @@ static int fts3ExprIterate(
return fts3ExprIterate2(pExpr, &iPhrase, x, pCtx);
}
-
/*
** This is an fts3ExprIterate() callback used while loading the doclists
** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
@@ -156937,7 +148846,8 @@ static int fts3ExprLoadDoclists(
static int fts3ExprPhraseCountCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
(*(int *)ctx)++;
- pExpr->iPhrase = iPhrase;
+ UNUSED_PARAMETER(pExpr);
+ UNUSED_PARAMETER(iPhrase);
return SQLITE_OK;
}
static int fts3ExprPhraseCount(Fts3Expr *pExpr){
@@ -157158,7 +149068,7 @@ static int fts3BestSnippet(
sIter.nSnippet = nSnippet;
sIter.nPhrase = nList;
sIter.iCurrent = -1;
- rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter);
+ rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void *)&sIter);
if( rc==SQLITE_OK ){
/* Set the *pmSeen output variable. */
@@ -157460,60 +149370,6 @@ static int fts3ColumnlistCount(char **ppCollist){
}
/*
-** This function gathers 'y' or 'b' data for a single phrase.
-*/
-static void fts3ExprLHits(
- Fts3Expr *pExpr, /* Phrase expression node */
- MatchInfo *p /* Matchinfo context */
-){
- Fts3Table *pTab = (Fts3Table *)p->pCursor->base.pVtab;
- int iStart;
- Fts3Phrase *pPhrase = pExpr->pPhrase;
- char *pIter = pPhrase->doclist.pList;
- int iCol = 0;
-
- assert( p->flag==FTS3_MATCHINFO_LHITS_BM || p->flag==FTS3_MATCHINFO_LHITS );
- if( p->flag==FTS3_MATCHINFO_LHITS ){
- iStart = pExpr->iPhrase * p->nCol;
- }else{
- iStart = pExpr->iPhrase * ((p->nCol + 31) / 32);
- }
-
- while( 1 ){
- int nHit = fts3ColumnlistCount(&pIter);
- if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){
- if( p->flag==FTS3_MATCHINFO_LHITS ){
- p->aMatchinfo[iStart + iCol] = (u32)nHit;
- }else if( nHit ){
- p->aMatchinfo[iStart + (iCol+1)/32] |= (1 << (iCol&0x1F));
- }
- }
- assert( *pIter==0x00 || *pIter==0x01 );
- if( *pIter!=0x01 ) break;
- pIter++;
- pIter += fts3GetVarint32(pIter, &iCol);
- }
-}
-
-/*
-** Gather the results for matchinfo directives 'y' and 'b'.
-*/
-static void fts3ExprLHitGather(
- Fts3Expr *pExpr,
- MatchInfo *p
-){
- assert( (pExpr->pLeft==0)==(pExpr->pRight==0) );
- if( pExpr->bEof==0 && pExpr->iDocid==p->pCursor->iPrevId ){
- if( pExpr->pLeft ){
- fts3ExprLHitGather(pExpr->pLeft, p);
- fts3ExprLHitGather(pExpr->pRight, p);
- }else{
- fts3ExprLHits(pExpr, p);
- }
- }
-}
-
-/*
** fts3ExprIterate() callback used to collect the "global" matchinfo stats
** for a single query.
**
@@ -157579,6 +149435,51 @@ static int fts3ExprLocalHitsCb(
return rc;
}
+/*
+** fts3ExprIterate() callback used to gather information for the matchinfo
+** directive 'y'.
+*/
+static int fts3ExprLHitsCb(
+ Fts3Expr *pExpr, /* Phrase expression node */
+ int iPhrase, /* Phrase number */
+ void *pCtx /* Pointer to MatchInfo structure */
+){
+ MatchInfo *p = (MatchInfo *)pCtx;
+ Fts3Table *pTab = (Fts3Table *)p->pCursor->base.pVtab;
+ int rc = SQLITE_OK;
+ int iStart = iPhrase * p->nCol;
+ Fts3Expr *pEof; /* Ancestor node already at EOF */
+
+ /* This must be a phrase */
+ assert( pExpr->pPhrase );
+
+ /* Initialize all output integers to zero. */
+ memset(&p->aMatchinfo[iStart], 0, sizeof(u32) * p->nCol);
+
+ /* Check if this or any parent node is at EOF. If so, then all output
+ ** values are zero. */
+ for(pEof=pExpr; pEof && pEof->bEof==0; pEof=pEof->pParent);
+
+ if( pEof==0 && pExpr->iDocid==p->pCursor->iPrevId ){
+ Fts3Phrase *pPhrase = pExpr->pPhrase;
+ char *pIter = pPhrase->doclist.pList;
+ int iCol = 0;
+
+ while( 1 ){
+ int nHit = fts3ColumnlistCount(&pIter);
+ if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){
+ p->aMatchinfo[iStart + iCol] = (u32)nHit;
+ }
+ assert( *pIter==0x00 || *pIter==0x01 );
+ if( *pIter!=0x01 ) break;
+ pIter++;
+ pIter += fts3GetVarint32(pIter, &iCol);
+ }
+ }
+
+ return rc;
+}
+
static int fts3MatchinfoCheck(
Fts3Table *pTab,
char cArg,
@@ -157592,7 +149493,6 @@ static int fts3MatchinfoCheck(
|| (cArg==FTS3_MATCHINFO_LCS)
|| (cArg==FTS3_MATCHINFO_HITS)
|| (cArg==FTS3_MATCHINFO_LHITS)
- || (cArg==FTS3_MATCHINFO_LHITS_BM)
){
return SQLITE_OK;
}
@@ -157620,10 +149520,6 @@ static int fts3MatchinfoSize(MatchInfo *pInfo, char cArg){
nVal = pInfo->nCol * pInfo->nPhrase;
break;
- case FTS3_MATCHINFO_LHITS_BM:
- nVal = pInfo->nPhrase * ((pInfo->nCol + 31) / 32);
- break;
-
default:
assert( cArg==FTS3_MATCHINFO_HITS );
nVal = pInfo->nCol * pInfo->nPhrase * 3;
@@ -157818,7 +149714,7 @@ static int fts3MatchinfoValues(
sqlite3_stmt *pSelect = 0;
for(i=0; rc==SQLITE_OK && zArg[i]; i++){
- pInfo->flag = zArg[i];
+
switch( zArg[i] ){
case FTS3_MATCHINFO_NPHRASE:
if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nPhrase;
@@ -157878,13 +149774,9 @@ static int fts3MatchinfoValues(
}
break;
- case FTS3_MATCHINFO_LHITS_BM:
- case FTS3_MATCHINFO_LHITS: {
- int nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32);
- memset(pInfo->aMatchinfo, 0, nZero);
- fts3ExprLHitGather(pCsr->pExpr, pInfo);
+ case FTS3_MATCHINFO_LHITS:
+ (void)fts3ExprIterate(pCsr->pExpr, fts3ExprLHitsCb, (void*)pInfo);
break;
- }
default: {
Fts3Expr *pExpr;
@@ -157898,7 +149790,6 @@ static int fts3MatchinfoValues(
if( rc!=SQLITE_OK ) break;
}
rc = fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo);
- sqlite3Fts3EvalTestDeferred(pCsr, &rc);
if( rc!=SQLITE_OK ) break;
}
(void)fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo);
@@ -157918,8 +149809,7 @@ static int fts3MatchinfoValues(
** Populate pCsr->aMatchinfo[] with data for the current row. The
** 'matchinfo' data is an array of 32-bit unsigned integers (C type u32).
*/
-static void fts3GetMatchinfo(
- sqlite3_context *pCtx, /* Return results here */
+static int fts3GetMatchinfo(
Fts3Cursor *pCsr, /* FTS3 Cursor object */
const char *zArg /* Second argument to matchinfo() function */
){
@@ -157928,9 +149818,6 @@ static void fts3GetMatchinfo(
int rc = SQLITE_OK;
int bGlobal = 0; /* Collect 'global' stats as well as local */
- u32 *aOut = 0;
- void (*xDestroyOut)(void*) = 0;
-
memset(&sInfo, 0, sizeof(MatchInfo));
sInfo.pCursor = pCsr;
sInfo.nCol = pTab->nColumn;
@@ -157938,18 +149825,21 @@ static void fts3GetMatchinfo(
/* 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->pMIBuffer && strcmp(pCsr->pMIBuffer->zMatchinfo, zArg) ){
- sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
- pCsr->pMIBuffer = 0;
+ if( pCsr->zMatchinfo && strcmp(pCsr->zMatchinfo, zArg) ){
+ assert( pCsr->aMatchinfo );
+ sqlite3_free(pCsr->aMatchinfo);
+ pCsr->zMatchinfo = 0;
+ pCsr->aMatchinfo = 0;
}
- /* If Fts3Cursor.pMIBuffer is NULL, then this is the first time the
+ /* 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->pMIBuffer==0 ){
+ if( pCsr->aMatchinfo==0 ){
int nMatchinfo = 0; /* Number of u32 elements in match-info */
+ int nArg; /* Bytes in zArg */
int i; /* Used to iterate through zArg */
/* Determine the number of phrases in the query */
@@ -157958,46 +149848,30 @@ static void fts3GetMatchinfo(
/* Determine the number of integers in the buffer returned by this call. */
for(i=0; zArg[i]; i++){
- char *zErr = 0;
- if( fts3MatchinfoCheck(pTab, zArg[i], &zErr) ){
- sqlite3_result_error(pCtx, zErr, -1);
- sqlite3_free(zErr);
- return;
- }
nMatchinfo += fts3MatchinfoSize(&sInfo, zArg[i]);
}
/* Allocate space for Fts3Cursor.aMatchinfo[] and Fts3Cursor.zMatchinfo. */
- pCsr->pMIBuffer = fts3MIBufferNew(nMatchinfo, zArg);
- if( !pCsr->pMIBuffer ) rc = SQLITE_NOMEM;
-
+ nArg = (int)strlen(zArg);
+ pCsr->aMatchinfo = (u32 *)sqlite3_malloc(sizeof(u32)*nMatchinfo + nArg + 1);
+ if( !pCsr->aMatchinfo ) return SQLITE_NOMEM;
+
+ 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;
}
- if( rc==SQLITE_OK ){
- xDestroyOut = fts3MIBufferAlloc(pCsr->pMIBuffer, &aOut);
- if( xDestroyOut==0 ){
- rc = SQLITE_NOMEM;
- }
- }
-
- if( rc==SQLITE_OK ){
- sInfo.aMatchinfo = aOut;
- sInfo.nPhrase = pCsr->nPhrase;
+ sInfo.aMatchinfo = pCsr->aMatchinfo;
+ sInfo.nPhrase = pCsr->nPhrase;
+ if( pCsr->isMatchinfoNeeded ){
rc = fts3MatchinfoValues(pCsr, bGlobal, &sInfo, zArg);
- if( bGlobal ){
- fts3MIBufferSetGlobal(pCsr->pMIBuffer);
- }
+ pCsr->isMatchinfoNeeded = 0;
}
- if( rc!=SQLITE_OK ){
- sqlite3_result_error_code(pCtx, rc);
- if( xDestroyOut ) xDestroyOut(aOut);
- }else{
- int n = pCsr->pMIBuffer->nElem * sizeof(u32);
- sqlite3_result_blob(pCtx, aOut, n, xDestroyOut);
- }
+ return rc;
}
/*
@@ -158203,7 +150077,7 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
*/
sCtx.iCol = iCol;
sCtx.iTerm = 0;
- (void)fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx);
+ (void)fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void *)&sCtx);
/* Retreive the text stored in column iCol. If an SQL NULL is stored
** in column iCol, jump immediately to the next iteration of the loop.
@@ -158295,9 +150169,19 @@ SQLITE_PRIVATE void sqlite3Fts3Matchinfo(
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;
@@ -158306,10 +150190,17 @@ SQLITE_PRIVATE void sqlite3Fts3Matchinfo(
if( !pCsr->pExpr ){
sqlite3_result_blob(pContext, "", 0, SQLITE_STATIC);
return;
+ }
+
+ /* Retrieve matchinfo() data. */
+ rc = fts3GetMatchinfo(pCsr, zFormat);
+ sqlite3Fts3SegmentsClose(pTab);
+
+ if( rc!=SQLITE_OK ){
+ sqlite3_result_error_code(pContext, rc);
}else{
- /* Retrieve matchinfo() data. */
- fts3GetMatchinfo(pContext, pCsr, zFormat);
- sqlite3Fts3SegmentsClose(pTab);
+ int n = pCsr->nMatchinfo * sizeof(u32);
+ sqlite3_result_blob(pContext, pCsr->aMatchinfo, n, SQLITE_TRANSIENT);
}
}
@@ -158334,7 +150225,6 @@ SQLITE_PRIVATE void sqlite3Fts3Matchinfo(
#ifndef SQLITE_DISABLE_FTS3_UNICODE
-/* #include "fts3Int.h" */
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
/* #include <assert.h> */
@@ -158342,7 +150232,6 @@ SQLITE_PRIVATE void sqlite3Fts3Matchinfo(
/* #include <stdio.h> */
/* #include <string.h> */
-/* #include "fts3_tokenizer.h" */
/*
** The following two macros - READ_UTF8 and WRITE_UTF8 - have been copied
@@ -159138,10 +151027,8 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RTREE)
#ifndef SQLITE_CORE
-/* #include "sqlite3ext.h" */
SQLITE_EXTENSION_INIT1
#else
-/* #include "sqlite3.h" */
#endif
/* #include <string.h> */
@@ -159434,7 +151321,6 @@ struct RtreeMatchArg {
u32 magic; /* Always RTREE_GEOMETRY_MAGIC */
RtreeGeomCallback cb; /* Info about the callback functions */
int nParam; /* Number of parameters to the SQL function */
- sqlite3_value **apSqlParam; /* Original SQL parameter values */
RtreeDValue aParam[1]; /* Values for parameters to the SQL function */
};
@@ -160566,7 +152452,9 @@ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){
/* Check that the blob is roughly the right size. */
nBlob = sqlite3_value_bytes(pValue);
- if( nBlob<(int)sizeof(RtreeMatchArg) ){
+ if( nBlob<(int)sizeof(RtreeMatchArg)
+ || ((nBlob-sizeof(RtreeMatchArg))%sizeof(RtreeDValue))!=0
+ ){
return SQLITE_ERROR;
}
@@ -160577,7 +152465,6 @@ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){
memcpy(pBlob, sqlite3_value_blob(pValue), nBlob);
nExpected = (int)(sizeof(RtreeMatchArg) +
- pBlob->nParam*sizeof(sqlite3_value*) +
(pBlob->nParam-1)*sizeof(RtreeDValue));
if( pBlob->magic!=RTREE_GEOMETRY_MAGIC || nBlob!=nExpected ){
sqlite3_free(pInfo);
@@ -160586,7 +152473,6 @@ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){
pInfo->pContext = pBlob->cb.pContext;
pInfo->nParam = pBlob->nParam;
pInfo->aParam = pBlob->aParam;
- pInfo->apSqlParam = pBlob->apSqlParam;
if( pBlob->cb.xGeom ){
pCons->u.xGeom = pBlob->cb.xGeom;
@@ -160625,7 +152511,7 @@ static int rtreeFilter(
if( idxNum==1 ){
/* Special case - lookup by rowid. */
RtreeNode *pLeaf; /* Leaf on which the required cell resides */
- RtreeSearchPoint *p; /* Search point for the the leaf */
+ RtreeSearchPoint *p; /* Search point for the leaf */
i64 iRowid = sqlite3_value_int64(argv[0]);
i64 iNode = 0;
rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode);
@@ -160753,30 +152639,17 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
Rtree *pRtree = (Rtree*)tab;
int rc = SQLITE_OK;
int ii;
- int bMatch = 0; /* True if there exists a MATCH constraint */
i64 nRow; /* Estimated rows returned by this scan */
int iIdx = 0;
char zIdxStr[RTREE_MAX_DIMENSIONS*8+1];
memset(zIdxStr, 0, sizeof(zIdxStr));
- /* Check if there exists a MATCH constraint - even an unusable one. If there
- ** is, do not consider the lookup-by-rowid plan as using such a plan would
- ** require the VDBE to evaluate the MATCH constraint, which is not currently
- ** possible. */
- for(ii=0; ii<pIdxInfo->nConstraint; ii++){
- if( pIdxInfo->aConstraint[ii].op==SQLITE_INDEX_CONSTRAINT_MATCH ){
- bMatch = 1;
- }
- }
-
assert( pIdxInfo->idxStr==0 );
for(ii=0; ii<pIdxInfo->nConstraint && iIdx<(int)(sizeof(zIdxStr)-1); ii++){
struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
- if( bMatch==0 && p->usable
- && p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ
- ){
+ if( p->usable && p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
/* We have an equality constraint on the rowid. Use strategy 1. */
int jj;
for(jj=0; jj<ii; jj++){
@@ -160824,7 +152697,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
return SQLITE_NOMEM;
}
- nRow = pRtree->nRowEst >> (iIdx/2);
+ nRow = pRtree->nRowEst / (iIdx + 1);
pIdxInfo->estimatedCost = (double)6.0 * (double)nRow;
setEstimatedRows(pIdxInfo, nRow);
@@ -162470,18 +154343,6 @@ static void rtreeFreeCallback(void *p){
}
/*
-** This routine frees the BLOB that is returned by geomCallback().
-*/
-static void rtreeMatchArgFree(void *pArg){
- int i;
- RtreeMatchArg *p = (RtreeMatchArg*)pArg;
- for(i=0; i<p->nParam; i++){
- sqlite3_value_free(p->apSqlParam[i]);
- }
- sqlite3_free(p);
-}
-
-/*
** Each call to sqlite3_rtree_geometry_callback() or
** sqlite3_rtree_query_callback() creates an ordinary SQLite
** scalar function that is implemented by this routine.
@@ -162499,10 +154360,8 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
RtreeGeomCallback *pGeomCtx = (RtreeGeomCallback *)sqlite3_user_data(ctx);
RtreeMatchArg *pBlob;
int nBlob;
- int memErr = 0;
- nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(RtreeDValue)
- + nArg*sizeof(sqlite3_value*);
+ nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(RtreeDValue);
pBlob = (RtreeMatchArg *)sqlite3_malloc(nBlob);
if( !pBlob ){
sqlite3_result_error_nomem(ctx);
@@ -162510,23 +154369,15 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
int i;
pBlob->magic = RTREE_GEOMETRY_MAGIC;
pBlob->cb = pGeomCtx[0];
- pBlob->apSqlParam = (sqlite3_value**)&pBlob->aParam[nArg];
pBlob->nParam = nArg;
for(i=0; i<nArg; i++){
- pBlob->apSqlParam[i] = sqlite3_value_dup(aArg[i]);
- if( pBlob->apSqlParam[i]==0 ) memErr = 1;
#ifdef SQLITE_RTREE_INT_ONLY
pBlob->aParam[i] = sqlite3_value_int64(aArg[i]);
#else
pBlob->aParam[i] = sqlite3_value_double(aArg[i]);
#endif
}
- if( memErr ){
- sqlite3_result_error_nomem(ctx);
- rtreeMatchArgFree(pBlob);
- }else{
- sqlite3_result_blob(ctx, pBlob, nBlob, rtreeMatchArgFree);
- }
+ sqlite3_result_blob(ctx, pBlob, nBlob, sqlite3_free);
}
}
@@ -162637,10 +154488,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rtree_init(
/* #include <assert.h> */
#ifndef SQLITE_CORE
-/* #include "sqlite3ext.h" */
SQLITE_EXTENSION_INIT1
#else
-/* #include "sqlite3.h" */
#endif
/*
@@ -162659,38 +154508,6 @@ static void xFree(void *p){
}
/*
-** This lookup table is used to help decode the first byte of
-** a multi-byte UTF8 character. It is copied here from SQLite source
-** code file utf8.c.
-*/
-static const unsigned char icuUtf8Trans1[] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
-};
-
-#define SQLITE_ICU_READ_UTF8(zIn, c) \
- c = *(zIn++); \
- if( c>=0xc0 ){ \
- c = icuUtf8Trans1[c-0xc0]; \
- while( (*zIn & 0xc0)==0x80 ){ \
- c = (c<<6) + (0x3f & *(zIn++)); \
- } \
- }
-
-#define SQLITE_ICU_SKIP_UTF8(zIn) \
- assert( *zIn ); \
- if( *(zIn++)>=0xc0 ){ \
- while( (*zIn & 0xc0)==0x80 ){zIn++;} \
- }
-
-
-/*
** Compare two UTF-8 strings for equality where the first string is
** a "LIKE" expression. Return true (1) if they are the same and
** false (0) if they are different.
@@ -162703,14 +154520,17 @@ static int icuLikeCompare(
static const int MATCH_ONE = (UChar32)'_';
static const int MATCH_ALL = (UChar32)'%';
+ int iPattern = 0; /* Current byte index in zPattern */
+ int iString = 0; /* Current byte index in zString */
+
int prevEscape = 0; /* True if the previous character was uEsc */
- while( 1 ){
+ while( zPattern[iPattern]!=0 ){
/* Read (and consume) the next character from the input pattern. */
UChar32 uPattern;
- SQLITE_ICU_READ_UTF8(zPattern, uPattern);
- if( uPattern==0 ) break;
+ U8_NEXT_UNSAFE(zPattern, iPattern, uPattern);
+ assert(uPattern!=0);
/* There are now 4 possibilities:
**
@@ -162727,28 +154547,28 @@ static int icuLikeCompare(
** MATCH_ALL. For each MATCH_ONE, skip one character in the
** test string.
*/
- while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){
+ while( (c=zPattern[iPattern]) == MATCH_ALL || c == MATCH_ONE ){
if( c==MATCH_ONE ){
- if( *zString==0 ) return 0;
- SQLITE_ICU_SKIP_UTF8(zString);
+ if( zString[iString]==0 ) return 0;
+ U8_FWD_1_UNSAFE(zString, iString);
}
- zPattern++;
+ iPattern++;
}
- if( *zPattern==0 ) return 1;
+ if( zPattern[iPattern]==0 ) return 1;
- while( *zString ){
- if( icuLikeCompare(zPattern, zString, uEsc) ){
+ while( zString[iString] ){
+ if( icuLikeCompare(&zPattern[iPattern], &zString[iString], uEsc) ){
return 1;
}
- SQLITE_ICU_SKIP_UTF8(zString);
+ U8_FWD_1_UNSAFE(zString, iString);
}
return 0;
}else if( !prevEscape && uPattern==MATCH_ONE ){
/* Case 2. */
- if( *zString==0 ) return 0;
- SQLITE_ICU_SKIP_UTF8(zString);
+ if( zString[iString]==0 ) return 0;
+ U8_FWD_1_UNSAFE(zString, iString);
}else if( !prevEscape && uPattern==uEsc){
/* Case 3. */
@@ -162757,7 +154577,7 @@ static int icuLikeCompare(
}else{
/* Case 4. */
UChar32 uString;
- SQLITE_ICU_READ_UTF8(zString, uString);
+ U8_NEXT_UNSAFE(zString, iString, uString);
uString = u_foldCase(uString, U_FOLD_CASE_DEFAULT);
uPattern = u_foldCase(uPattern, U_FOLD_CASE_DEFAULT);
if( uString!=uPattern ){
@@ -162767,7 +154587,7 @@ static int icuLikeCompare(
}
}
- return *zString==0;
+ return zString[iString]==0;
}
/*
@@ -162952,17 +154772,15 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
** http://www.icu-project.org/userguide/posix.html#case_mappings
*/
static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
- const UChar *zInput; /* Pointer to input string */
- UChar *zOutput = 0; /* Pointer to output buffer */
- int nInput; /* Size of utf-16 input string in bytes */
- int nOut; /* Size of output buffer in bytes */
- int cnt;
- int bToUpper; /* True for toupper(), false for tolower() */
- UErrorCode status;
+ const UChar *zInput;
+ UChar *zOutput;
+ int nInput;
+ int nOutput;
+
+ UErrorCode status = U_ZERO_ERROR;
const char *zLocale = 0;
assert(nArg==1 || nArg==2);
- bToUpper = (sqlite3_user_data(p)!=0);
if( nArg==2 ){
zLocale = (const char *)sqlite3_value_text(apArg[1]);
}
@@ -162971,38 +154789,26 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
if( !zInput ){
return;
}
- nOut = nInput = sqlite3_value_bytes16(apArg[0]);
- if( nOut==0 ){
- sqlite3_result_text16(p, "", 0, SQLITE_STATIC);
+ nInput = sqlite3_value_bytes16(apArg[0]);
+
+ nOutput = nInput * 2 + 2;
+ zOutput = sqlite3_malloc(nOutput);
+ if( !zOutput ){
return;
}
- for(cnt=0; cnt<2; cnt++){
- UChar *zNew = sqlite3_realloc(zOutput, nOut);
- if( zNew==0 ){
- sqlite3_free(zOutput);
- sqlite3_result_error_nomem(p);
- return;
- }
- zOutput = zNew;
- status = U_ZERO_ERROR;
- if( bToUpper ){
- nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
- }else{
- nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
- }
+ if( sqlite3_user_data(p) ){
+ u_strToUpper(zOutput, nOutput/2, zInput, nInput/2, zLocale, &status);
+ }else{
+ u_strToLower(zOutput, nOutput/2, zInput, nInput/2, zLocale, &status);
+ }
- if( U_SUCCESS(status) ){
- sqlite3_result_text16(p, zOutput, nOut, xFree);
- }else if( status==U_BUFFER_OVERFLOW_ERROR ){
- assert( cnt==0 );
- continue;
- }else{
- icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status);
- }
+ if( !U_SUCCESS(status) ){
+ icuFunctionError(p, "u_strToLower()/u_strToUpper", status);
return;
}
- assert( 0 ); /* Unreachable */
+
+ sqlite3_result_text16(p, zOutput, -1, xFree);
}
/*
@@ -163063,7 +154869,6 @@ static void icuLoadCollation(
int rc; /* Return code from sqlite3_create_collation_x() */
assert(nArg==2);
- (void)nArg; /* Unused parameter */
zLocale = (const char *)sqlite3_value_text(apArg[0]);
zName = (const char *)sqlite3_value_text(apArg[1]);
@@ -163160,13 +154965,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_icu_init(
*************************************************************************
** This file implements a tokenizer for fts3 based on the ICU library.
*/
-/* #include "fts3Int.h" */
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
#ifdef SQLITE_ENABLE_ICU
/* #include <assert.h> */
/* #include <string.h> */
-/* #include "fts3_tokenizer.h" */
#include <unicode/ubrk.h>
/* #include <unicode/ucol.h> */
@@ -163389,13 +155192,12 @@ static int icuNext(
** The set of routines that implement the simple tokenizer
*/
static const sqlite3_tokenizer_module icuTokenizerModule = {
- 0, /* iVersion */
- icuCreate, /* xCreate */
- icuDestroy, /* xCreate */
- icuOpen, /* xOpen */
- icuClose, /* xClose */
- icuNext, /* xNext */
- 0, /* xLanguageid */
+ 0, /* iVersion */
+ icuCreate, /* xCreate */
+ icuDestroy, /* xCreate */
+ icuOpen, /* xOpen */
+ icuClose, /* xClose */
+ icuNext, /* xNext */
};
/*
@@ -163411,5230 +155213,6 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */
/************** End of fts3_icu.c ********************************************/
-/************** Begin file sqlite3rbu.c **************************************/
-/*
-** 2014 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.
-**
-*************************************************************************
-**
-**
-** OVERVIEW
-**
-** The RBU extension requires that the RBU update be packaged as an
-** SQLite database. The tables it expects to find are described in
-** sqlite3rbu.h. Essentially, for each table xyz in the target database
-** that the user wishes to write to, a corresponding data_xyz table is
-** created in the RBU database and populated with one row for each row to
-** update, insert or delete from the target table.
-**
-** The update proceeds in three stages:
-**
-** 1) The database is updated. The modified database pages are written
-** to a *-oal file. A *-oal file is just like a *-wal file, except
-** that it is named "<database>-oal" instead of "<database>-wal".
-** Because regular SQLite clients do not look for file named
-** "<database>-oal", they go on using the original database in
-** rollback mode while the *-oal file is being generated.
-**
-** During this stage RBU does not update the database by writing
-** directly to the target tables. Instead it creates "imposter"
-** tables using the SQLITE_TESTCTRL_IMPOSTER interface that it uses
-** to update each b-tree individually. All updates required by each
-** b-tree are completed before moving on to the next, and all
-** updates are done in sorted key order.
-**
-** 2) The "<database>-oal" file is moved to the equivalent "<database>-wal"
-** location using a call to rename(2). Before doing this the RBU
-** module takes an EXCLUSIVE lock on the database file, ensuring
-** that there are no other active readers.
-**
-** Once the EXCLUSIVE lock is released, any other database readers
-** detect the new *-wal file and read the database in wal mode. At
-** this point they see the new version of the database - including
-** the updates made as part of the RBU update.
-**
-** 3) The new *-wal file is checkpointed. This proceeds in the same way
-** as a regular database checkpoint, except that a single frame is
-** checkpointed each time sqlite3rbu_step() is called. If the RBU
-** handle is closed before the entire *-wal file is checkpointed,
-** the checkpoint progress is saved in the RBU database and the
-** checkpoint can be resumed by another RBU client at some point in
-** the future.
-**
-** POTENTIAL PROBLEMS
-**
-** The rename() call might not be portable. And RBU is not currently
-** syncing the directory after renaming the file.
-**
-** When state is saved, any commit to the *-oal file and the commit to
-** the RBU update database are not atomic. So if the power fails at the
-** wrong moment they might get out of sync. As the main database will be
-** committed before the RBU update database this will likely either just
-** pass unnoticed, or result in SQLITE_CONSTRAINT errors (due to UNIQUE
-** constraint violations).
-**
-** If some client does modify the target database mid RBU update, or some
-** other error occurs, the RBU extension will keep throwing errors. It's
-** not really clear how to get out of this state. The system could just
-** by delete the RBU update database and *-oal file and have the device
-** download the update again and start over.
-**
-** At present, for an UPDATE, both the new.* and old.* records are
-** collected in the rbu_xyz table. And for both UPDATEs and DELETEs all
-** fields are collected. This means we're probably writing a lot more
-** data to disk when saving the state of an ongoing update to the RBU
-** update database than is strictly necessary.
-**
-*/
-
-/* #include <assert.h> */
-/* #include <string.h> */
-/* #include <stdio.h> */
-
-/* #include "sqlite3.h" */
-
-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU)
-/************** Include sqlite3rbu.h in the middle of sqlite3rbu.c ***********/
-/************** Begin file sqlite3rbu.h **************************************/
-/*
-** 2014 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.
-**
-*************************************************************************
-**
-** This file contains the public interface for the RBU extension.
-*/
-
-/*
-** SUMMARY
-**
-** Writing a transaction containing a large number of operations on
-** b-tree indexes that are collectively larger than the available cache
-** memory can be very inefficient.
-**
-** The problem is that in order to update a b-tree, the leaf page (at least)
-** containing the entry being inserted or deleted must be modified. If the
-** working set of leaves is larger than the available cache memory, then a
-** single leaf that is modified more than once as part of the transaction
-** may be loaded from or written to the persistent media multiple times.
-** Additionally, because the index updates are likely to be applied in
-** random order, access to pages within the database is also likely to be in
-** random order, which is itself quite inefficient.
-**
-** One way to improve the situation is to sort the operations on each index
-** by index key before applying them to the b-tree. This leads to an IO
-** pattern that resembles a single linear scan through the index b-tree,
-** and all but guarantees each modified leaf page is loaded and stored
-** exactly once. SQLite uses this trick to improve the performance of
-** CREATE INDEX commands. This extension allows it to be used to improve
-** the performance of large transactions on existing databases.
-**
-** Additionally, this extension allows the work involved in writing the
-** large transaction to be broken down into sub-transactions performed
-** sequentially by separate processes. This is useful if the system cannot
-** guarantee that a single update process will run for long enough to apply
-** the entire update, for example because the update is being applied on a
-** mobile device that is frequently rebooted. Even after the writer process
-** has committed one or more sub-transactions, other database clients continue
-** to read from the original database snapshot. In other words, partially
-** applied transactions are not visible to other clients.
-**
-** "RBU" stands for "Resumable Bulk Update". As in a large database update
-** transmitted via a wireless network to a mobile device. A transaction
-** applied using this extension is hence refered to as an "RBU update".
-**
-**
-** LIMITATIONS
-**
-** An "RBU update" transaction is subject to the following limitations:
-**
-** * The transaction must consist of INSERT, UPDATE and DELETE operations
-** only.
-**
-** * INSERT statements may not use any default values.
-**
-** * UPDATE and DELETE statements must identify their target rows by
-** non-NULL PRIMARY KEY values. Rows with NULL values stored in PRIMARY
-** KEY fields may not be updated or deleted. If the table being written
-** has no PRIMARY KEY, affected rows must be identified by rowid.
-**
-** * UPDATE statements may not modify PRIMARY KEY columns.
-**
-** * No triggers will be fired.
-**
-** * No foreign key violations are detected or reported.
-**
-** * CHECK constraints are not enforced.
-**
-** * No constraint handling mode except for "OR ROLLBACK" is supported.
-**
-**
-** PREPARATION
-**
-** An "RBU update" is stored as a separate SQLite database. A database
-** containing an RBU update is an "RBU database". For each table in the
-** target database to be updated, the RBU database should contain a table
-** named "data_<target name>" containing the same set of columns as the
-** target table, and one more - "rbu_control". The data_% table should
-** have no PRIMARY KEY or UNIQUE constraints, but each column should have
-** the same type as the corresponding column in the target database.
-** The "rbu_control" column should have no type at all. For example, if
-** the target database contains:
-**
-** CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c UNIQUE);
-**
-** Then the RBU database should contain:
-**
-** CREATE TABLE data_t1(a INTEGER, b TEXT, c, rbu_control);
-**
-** The order of the columns in the data_% table does not matter.
-**
-** Instead of a regular table, the RBU database may also contain virtual
-** tables or view named using the data_<target> naming scheme.
-**
-** Instead of the plain data_<target> naming scheme, RBU database tables
-** may also be named data<integer>_<target>, where <integer> is any sequence
-** of zero or more numeric characters (0-9). This can be significant because
-** tables within the RBU database are always processed in order sorted by
-** name. By judicious selection of the the <integer> portion of the names
-** of the RBU tables the user can therefore control the order in which they
-** are processed. This can be useful, for example, to ensure that "external
-** content" FTS4 tables are updated before their underlying content tables.
-**
-** If the target database table is a virtual table or a table that has no
-** PRIMARY KEY declaration, the data_% table must also contain a column
-** named "rbu_rowid". This column is mapped to the tables implicit primary
-** key column - "rowid". Virtual tables for which the "rowid" column does
-** not function like a primary key value cannot be updated using RBU. For
-** example, if the target db contains either of the following:
-**
-** CREATE VIRTUAL TABLE x1 USING fts3(a, b);
-** CREATE TABLE x1(a, b)
-**
-** then the RBU database should contain:
-**
-** CREATE TABLE data_x1(a, b, rbu_rowid, rbu_control);
-**
-** All non-hidden columns (i.e. all columns matched by "SELECT *") of the
-** target table must be present in the input table. For virtual tables,
-** hidden columns are optional - they are updated by RBU if present in
-** the input table, or not otherwise. For example, to write to an fts4
-** table with a hidden languageid column such as:
-**
-** CREATE VIRTUAL TABLE ft1 USING fts4(a, b, languageid='langid');
-**
-** Either of the following input table schemas may be used:
-**
-** CREATE TABLE data_ft1(a, b, langid, rbu_rowid, rbu_control);
-** CREATE TABLE data_ft1(a, b, rbu_rowid, rbu_control);
-**
-** For each row to INSERT into the target database as part of the RBU
-** update, the corresponding data_% table should contain a single record
-** with the "rbu_control" column set to contain integer value 0. The
-** other columns should be set to the values that make up the new record
-** to insert.
-**
-** If the target database table has an INTEGER PRIMARY KEY, it is not
-** possible to insert a NULL value into the IPK column. Attempting to
-** do so results in an SQLITE_MISMATCH error.
-**
-** For each row to DELETE from the target database as part of the RBU
-** update, the corresponding data_% table should contain a single record
-** with the "rbu_control" column set to contain integer value 1. The
-** real primary key values of the row to delete should be stored in the
-** corresponding columns of the data_% table. The values stored in the
-** other columns are not used.
-**
-** For each row to UPDATE from the target database as part of the RBU
-** update, the corresponding data_% table should contain a single record
-** with the "rbu_control" column set to contain a value of type text.
-** The real primary key values identifying the row to update should be
-** stored in the corresponding columns of the data_% table row, as should
-** the new values of all columns being update. The text value in the
-** "rbu_control" column must contain the same number of characters as
-** there are columns in the target database table, and must consist entirely
-** of 'x' and '.' characters (or in some special cases 'd' - see below). For
-** each column that is being updated, the corresponding character is set to
-** 'x'. For those that remain as they are, the corresponding character of the
-** rbu_control value should be set to '.'. For example, given the tables
-** above, the update statement:
-**
-** UPDATE t1 SET c = 'usa' WHERE a = 4;
-**
-** is represented by the data_t1 row created by:
-**
-** INSERT INTO data_t1(a, b, c, rbu_control) VALUES(4, NULL, 'usa', '..x');
-**
-** Instead of an 'x' character, characters of the rbu_control value specified
-** for UPDATEs may also be set to 'd'. In this case, instead of updating the
-** target table with the value stored in the corresponding data_% column, the
-** user-defined SQL function "rbu_delta()" is invoked and the result stored in
-** the target table column. rbu_delta() is invoked with two arguments - the
-** original value currently stored in the target table column and the
-** value specified in the data_xxx table.
-**
-** For example, this row:
-**
-** INSERT INTO data_t1(a, b, c, rbu_control) VALUES(4, NULL, 'usa', '..d');
-**
-** is similar to an UPDATE statement such as:
-**
-** UPDATE t1 SET c = rbu_delta(c, 'usa') WHERE a = 4;
-**
-** Finally, if an 'f' character appears in place of a 'd' or 's' in an
-** ota_control string, the contents of the data_xxx table column is assumed
-** to be a "fossil delta" - a patch to be applied to a blob value in the
-** format used by the fossil source-code management system. In this case
-** the existing value within the target database table must be of type BLOB.
-** It is replaced by the result of applying the specified fossil delta to
-** itself.
-**
-** If the target database table is a virtual table or a table with no PRIMARY
-** KEY, the rbu_control value should not include a character corresponding
-** to the rbu_rowid value. For example, this:
-**
-** INSERT INTO data_ft1(a, b, rbu_rowid, rbu_control)
-** VALUES(NULL, 'usa', 12, '.x');
-**
-** causes a result similar to:
-**
-** UPDATE ft1 SET b = 'usa' WHERE rowid = 12;
-**
-** The data_xxx tables themselves should have no PRIMARY KEY declarations.
-** However, RBU is more efficient if reading the rows in from each data_xxx
-** table in "rowid" order is roughly the same as reading them sorted by
-** the PRIMARY KEY of the corresponding target database table. In other
-** words, rows should be sorted using the destination table PRIMARY KEY
-** fields before they are inserted into the data_xxx tables.
-**
-** USAGE
-**
-** The API declared below allows an application to apply an RBU update
-** stored on disk to an existing target database. Essentially, the
-** application:
-**
-** 1) Opens an RBU handle using the sqlite3rbu_open() function.
-**
-** 2) Registers any required virtual table modules with the database
-** handle returned by sqlite3rbu_db(). Also, if required, register
-** the rbu_delta() implementation.
-**
-** 3) Calls the sqlite3rbu_step() function one or more times on
-** the new handle. Each call to sqlite3rbu_step() performs a single
-** b-tree operation, so thousands of calls may be required to apply
-** a complete update.
-**
-** 4) Calls sqlite3rbu_close() to close the RBU update handle. If
-** sqlite3rbu_step() has been called enough times to completely
-** apply the update to the target database, then the RBU database
-** is marked as fully applied. Otherwise, the state of the RBU
-** update application is saved in the RBU database for later
-** resumption.
-**
-** See comments below for more detail on APIs.
-**
-** If an update is only partially applied to the target database by the
-** time sqlite3rbu_close() is called, various state information is saved
-** within the RBU database. This allows subsequent processes to automatically
-** resume the RBU update from where it left off.
-**
-** To remove all RBU extension state information, returning an RBU database
-** to its original contents, it is sufficient to drop all tables that begin
-** with the prefix "rbu_"
-**
-** DATABASE LOCKING
-**
-** An RBU update may not be applied to a database in WAL mode. Attempting
-** to do so is an error (SQLITE_ERROR).
-**
-** While an RBU handle is open, a SHARED lock may be held on the target
-** database file. This means it is possible for other clients to read the
-** database, but not to write it.
-**
-** If an RBU update is started and then suspended before it is completed,
-** then an external client writes to the database, then attempting to resume
-** the suspended RBU update is also an error (SQLITE_BUSY).
-*/
-
-#ifndef _SQLITE3RBU_H
-#define _SQLITE3RBU_H
-
-/* #include "sqlite3.h" ** Required for error code definitions ** */
-
-#if 0
-extern "C" {
-#endif
-
-typedef struct sqlite3rbu sqlite3rbu;
-
-/*
-** Open an RBU handle.
-**
-** Argument zTarget is the path to the target database. Argument zRbu is
-** the path to the RBU database. Each call to this function must be matched
-** by a call to sqlite3rbu_close(). When opening the databases, RBU passes
-** the SQLITE_CONFIG_URI flag to sqlite3_open_v2(). So if either zTarget
-** or zRbu begin with "file:", it will be interpreted as an SQLite
-** database URI, not a regular file name.
-**
-** If the zState argument is passed a NULL value, the RBU extension stores
-** the current state of the update (how many rows have been updated, which
-** indexes are yet to be updated etc.) within the RBU database itself. This
-** can be convenient, as it means that the RBU application does not need to
-** organize removing a separate state file after the update is concluded.
-** Or, if zState is non-NULL, it must be a path to a database file in which
-** the RBU extension can store the state of the update.
-**
-** When resuming an RBU update, the zState argument must be passed the same
-** value as when the RBU update was started.
-**
-** Once the RBU update is finished, the RBU extension does not
-** automatically remove any zState database file, even if it created it.
-**
-** By default, RBU uses the default VFS to access the files on disk. To
-** use a VFS other than the default, an SQLite "file:" URI containing a
-** "vfs=..." option may be passed as the zTarget option.
-**
-** IMPORTANT NOTE FOR ZIPVFS USERS: The RBU extension works with all of
-** SQLite's built-in VFSs, including the multiplexor VFS. However it does
-** not work out of the box with zipvfs. Refer to the comment describing
-** the zipvfs_create_vfs() API below for details on using RBU with zipvfs.
-*/
-SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
- const char *zTarget,
- const char *zRbu,
- const char *zState
-);
-
-/*
-** Open an RBU handle to perform an RBU vacuum on database file zTarget.
-** An RBU vacuum is similar to SQLite's built-in VACUUM command, except
-** that it can be suspended and resumed like an RBU update.
-**
-** The second argument to this function, which may not be NULL, identifies
-** a database in which to store the state of the RBU vacuum operation if
-** it is suspended. The first time sqlite3rbu_vacuum() is called, to start
-** an RBU vacuum operation, the state database should either not exist or
-** be empty (contain no tables). If an RBU vacuum is suspended by calling
-** sqlite3rbu_close() on the RBU handle before sqlite3rbu_step() has
-** returned SQLITE_DONE, the vacuum state is stored in the state database.
-** The vacuum can be resumed by calling this function to open a new RBU
-** handle specifying the same target and state databases.
-**
-** This function does not delete the state database after an RBU vacuum
-** is completed, even if it created it. However, if the call to
-** sqlite3rbu_close() returns any value other than SQLITE_OK, the contents
-** of the state tables within the state database are zeroed. This way,
-** the next call to sqlite3rbu_vacuum() opens a handle that starts a
-** new RBU vacuum operation.
-**
-** As with sqlite3rbu_open(), Zipvfs users should rever to the comment
-** describing the sqlite3rbu_create_vfs() API function below for
-** a description of the complications associated with using RBU with
-** zipvfs databases.
-*/
-SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_vacuum(
- const char *zTarget,
- const char *zState
-);
-
-/*
-** Internally, each RBU connection uses a separate SQLite database
-** connection to access the target and rbu update databases. This
-** API allows the application direct access to these database handles.
-**
-** The first argument passed to this function must be a valid, open, RBU
-** handle. The second argument should be passed zero to access the target
-** database handle, or non-zero to access the rbu update database handle.
-** Accessing the underlying database handles may be useful in the
-** following scenarios:
-**
-** * If any target tables are virtual tables, it may be necessary to
-** call sqlite3_create_module() on the target database handle to
-** register the required virtual table implementations.
-**
-** * If the data_xxx tables in the RBU source database are virtual
-** tables, the application may need to call sqlite3_create_module() on
-** the rbu update db handle to any required virtual table
-** implementations.
-**
-** * If the application uses the "rbu_delta()" feature described above,
-** it must use sqlite3_create_function() or similar to register the
-** rbu_delta() implementation with the target database handle.
-**
-** If an error has occurred, either while opening or stepping the RBU object,
-** this function may return NULL. The error code and message may be collected
-** when sqlite3rbu_close() is called.
-**
-** Database handles returned by this function remain valid until the next
-** call to any sqlite3rbu_xxx() function other than sqlite3rbu_db().
-*/
-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3rbu_db(sqlite3rbu*, int bRbu);
-
-/*
-** Do some work towards applying the RBU update to the target db.
-**
-** Return SQLITE_DONE if the update has been completely applied, or
-** SQLITE_OK if no error occurs but there remains work to do to apply
-** the RBU update. If an error does occur, some other error code is
-** returned.
-**
-** Once a call to sqlite3rbu_step() has returned a value other than
-** SQLITE_OK, all subsequent calls on the same RBU handle are no-ops
-** that immediately return the same value.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *pRbu);
-
-/*
-** Force RBU to save its state to disk.
-**
-** If a power failure or application crash occurs during an update, following
-** system recovery RBU may resume the update from the point at which the state
-** was last saved. In other words, from the most recent successful call to
-** sqlite3rbu_close() or this function.
-**
-** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *pRbu);
-
-/*
-** Close an RBU handle.
-**
-** If the RBU update has been completely applied, mark the RBU database
-** as fully applied. Otherwise, assuming no error has occurred, save the
-** current state of the RBU update appliation to the RBU database.
-**
-** If an error has already occurred as part of an sqlite3rbu_step()
-** or sqlite3rbu_open() call, or if one occurs within this function, an
-** SQLite error code is returned. Additionally, *pzErrmsg may be set to
-** point to a buffer containing a utf-8 formatted English language error
-** message. It is the responsibility of the caller to eventually free any
-** such buffer using sqlite3_free().
-**
-** Otherwise, if no error occurs, this function returns SQLITE_OK if the
-** update has been partially applied, or SQLITE_DONE if it has been
-** completely applied.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg);
-
-/*
-** Return the total number of key-value operations (inserts, deletes or
-** updates) that have been performed on the target database since the
-** current RBU update was started.
-*/
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3rbu_progress(sqlite3rbu *pRbu);
-
-/*
-** Obtain permyriadage (permyriadage is to 10000 as percentage is to 100)
-** progress indications for the two stages of an RBU update. This API may
-** be useful for driving GUI progress indicators and similar.
-**
-** An RBU update is divided into two stages:
-**
-** * Stage 1, in which changes are accumulated in an oal/wal file, and
-** * Stage 2, in which the contents of the wal file are copied into the
-** main database.
-**
-** The update is visible to non-RBU clients during stage 2. During stage 1
-** non-RBU reader clients may see the original database.
-**
-** If this API is called during stage 2 of the update, output variable
-** (*pnOne) is set to 10000 to indicate that stage 1 has finished and (*pnTwo)
-** to a value between 0 and 10000 to indicate the permyriadage progress of
-** stage 2. A value of 5000 indicates that stage 2 is half finished,
-** 9000 indicates that it is 90% finished, and so on.
-**
-** If this API is called during stage 1 of the update, output variable
-** (*pnTwo) is set to 0 to indicate that stage 2 has not yet started. The
-** value to which (*pnOne) is set depends on whether or not the RBU
-** database contains an "rbu_count" table. The rbu_count table, if it
-** exists, must contain the same columns as the following:
-**
-** CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
-**
-** There must be one row in the table for each source (data_xxx) table within
-** the RBU database. The 'tbl' column should contain the name of the source
-** table. The 'cnt' column should contain the number of rows within the
-** source table.
-**
-** If the rbu_count table is present and populated correctly and this
-** API is called during stage 1, the *pnOne output variable is set to the
-** permyriadage progress of the same stage. If the rbu_count table does
-** not exist, then (*pnOne) is set to -1 during stage 1. If the rbu_count
-** table exists but is not correctly populated, the value of the *pnOne
-** output variable during stage 1 is undefined.
-*/
-SQLITE_API void SQLITE_STDCALL sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int *pnTwo);
-
-/*
-** Create an RBU VFS named zName that accesses the underlying file-system
-** via existing VFS zParent. Or, if the zParent parameter is passed NULL,
-** then the new RBU VFS uses the default system VFS to access the file-system.
-** The new object is registered as a non-default VFS with SQLite before
-** returning.
-**
-** Part of the RBU implementation uses a custom VFS object. Usually, this
-** object is created and deleted automatically by RBU.
-**
-** The exception is for applications that also use zipvfs. In this case,
-** the custom VFS must be explicitly created by the user before the RBU
-** handle is opened. The RBU VFS should be installed so that the zipvfs
-** VFS uses the RBU VFS, which in turn uses any other VFS layers in use
-** (for example multiplexor) to access the file-system. For example,
-** to assemble an RBU enabled VFS stack that uses both zipvfs and
-** multiplexor (error checking omitted):
-**
-** // Create a VFS named "multiplex" (not the default).
-** sqlite3_multiplex_initialize(0, 0);
-**
-** // Create an rbu VFS named "rbu" that uses multiplexor. If the
-** // second argument were replaced with NULL, the "rbu" VFS would
-** // access the file-system via the system default VFS, bypassing the
-** // multiplexor.
-** sqlite3rbu_create_vfs("rbu", "multiplex");
-**
-** // Create a zipvfs VFS named "zipvfs" that uses rbu.
-** zipvfs_create_vfs_v3("zipvfs", "rbu", 0, xCompressorAlgorithmDetector);
-**
-** // Make zipvfs the default VFS.
-** sqlite3_vfs_register(sqlite3_vfs_find("zipvfs"), 1);
-**
-** Because the default VFS created above includes a RBU functionality, it
-** may be used by RBU clients. Attempting to use RBU with a zipvfs VFS stack
-** that does not include the RBU layer results in an error.
-**
-** The overhead of adding the "rbu" VFS to the system is negligible for
-** non-RBU users. There is no harm in an application accessing the
-** file-system via "rbu" all the time, even if it only uses RBU functionality
-** occasionally.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const char *zParent);
-
-/*
-** Deregister and destroy an RBU vfs created by an earlier call to
-** sqlite3rbu_create_vfs().
-**
-** VFS objects are not reference counted. If a VFS object is destroyed
-** before all database handles that use it have been closed, the results
-** are undefined.
-*/
-SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName);
-
-#if 0
-} /* end of the 'extern "C"' block */
-#endif
-
-#endif /* _SQLITE3RBU_H */
-
-/************** End of sqlite3rbu.h ******************************************/
-/************** Continuing where we left off in sqlite3rbu.c *****************/
-
-#if defined(_WIN32_WCE)
-/* #include "windows.h" */
-#endif
-
-/* Maximum number of prepared UPDATE statements held by this module */
-#define SQLITE_RBU_UPDATE_CACHESIZE 16
-
-/*
-** Swap two objects of type TYPE.
-*/
-#if !defined(SQLITE_AMALGAMATION)
-# define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;}
-#endif
-
-/*
-** The rbu_state table is used to save the state of a partially applied
-** update so that it can be resumed later. The table consists of integer
-** keys mapped to values as follows:
-**
-** RBU_STATE_STAGE:
-** May be set to integer values 1, 2, 4 or 5. As follows:
-** 1: the *-rbu file is currently under construction.
-** 2: the *-rbu file has been constructed, but not yet moved
-** to the *-wal path.
-** 4: the checkpoint is underway.
-** 5: the rbu update has been checkpointed.
-**
-** RBU_STATE_TBL:
-** Only valid if STAGE==1. The target database name of the table
-** currently being written.
-**
-** RBU_STATE_IDX:
-** Only valid if STAGE==1. The target database name of the index
-** currently being written, or NULL if the main table is currently being
-** updated.
-**
-** RBU_STATE_ROW:
-** Only valid if STAGE==1. Number of rows already processed for the current
-** table/index.
-**
-** RBU_STATE_PROGRESS:
-** Trbul number of sqlite3rbu_step() calls made so far as part of this
-** rbu update.
-**
-** RBU_STATE_CKPT:
-** Valid if STAGE==4. The 64-bit checksum associated with the wal-index
-** header created by recovering the *-wal file. This is used to detect
-** cases when another client appends frames to the *-wal file in the
-** middle of an incremental checkpoint (an incremental checkpoint cannot
-** be continued if this happens).
-**
-** RBU_STATE_COOKIE:
-** Valid if STAGE==1. The current change-counter cookie value in the
-** target db file.
-**
-** RBU_STATE_OALSZ:
-** Valid if STAGE==1. The size in bytes of the *-oal file.
-*/
-#define RBU_STATE_STAGE 1
-#define RBU_STATE_TBL 2
-#define RBU_STATE_IDX 3
-#define RBU_STATE_ROW 4
-#define RBU_STATE_PROGRESS 5
-#define RBU_STATE_CKPT 6
-#define RBU_STATE_COOKIE 7
-#define RBU_STATE_OALSZ 8
-#define RBU_STATE_PHASEONESTEP 9
-
-#define RBU_STAGE_OAL 1
-#define RBU_STAGE_MOVE 2
-#define RBU_STAGE_CAPTURE 3
-#define RBU_STAGE_CKPT 4
-#define RBU_STAGE_DONE 5
-
-
-#define RBU_CREATE_STATE \
- "CREATE TABLE IF NOT EXISTS %s.rbu_state(k INTEGER PRIMARY KEY, v)"
-
-typedef struct RbuFrame RbuFrame;
-typedef struct RbuObjIter RbuObjIter;
-typedef struct RbuState RbuState;
-typedef struct rbu_vfs rbu_vfs;
-typedef struct rbu_file rbu_file;
-typedef struct RbuUpdateStmt RbuUpdateStmt;
-
-#if !defined(SQLITE_AMALGAMATION)
-typedef unsigned int u32;
-typedef unsigned short u16;
-typedef unsigned char u8;
-typedef sqlite3_int64 i64;
-#endif
-
-/*
-** These values must match the values defined in wal.c for the equivalent
-** locks. These are not magic numbers as they are part of the SQLite file
-** format.
-*/
-#define WAL_LOCK_WRITE 0
-#define WAL_LOCK_CKPT 1
-#define WAL_LOCK_READ0 3
-
-#define SQLITE_FCNTL_RBUCNT 5149216
-
-/*
-** A structure to store values read from the rbu_state table in memory.
-*/
-struct RbuState {
- int eStage;
- char *zTbl;
- char *zIdx;
- i64 iWalCksum;
- int nRow;
- i64 nProgress;
- u32 iCookie;
- i64 iOalSz;
- i64 nPhaseOneStep;
-};
-
-struct RbuUpdateStmt {
- char *zMask; /* Copy of update mask used with pUpdate */
- sqlite3_stmt *pUpdate; /* Last update statement (or NULL) */
- RbuUpdateStmt *pNext;
-};
-
-/*
-** An iterator of this type is used to iterate through all objects in
-** the target database that require updating. For each such table, the
-** iterator visits, in order:
-**
-** * the table itself,
-** * each index of the table (zero or more points to visit), and
-** * a special "cleanup table" state.
-**
-** abIndexed:
-** If the table has no indexes on it, abIndexed is set to NULL. Otherwise,
-** it points to an array of flags nTblCol elements in size. The flag is
-** set for each column that is either a part of the PK or a part of an
-** index. Or clear otherwise.
-**
-*/
-struct RbuObjIter {
- sqlite3_stmt *pTblIter; /* Iterate through tables */
- sqlite3_stmt *pIdxIter; /* Index iterator */
- int nTblCol; /* Size of azTblCol[] array */
- char **azTblCol; /* Array of unquoted target column names */
- char **azTblType; /* Array of target column types */
- int *aiSrcOrder; /* src table col -> target table col */
- u8 *abTblPk; /* Array of flags, set on target PK columns */
- u8 *abNotNull; /* Array of flags, set on NOT NULL columns */
- u8 *abIndexed; /* Array of flags, set on indexed & PK cols */
- int eType; /* Table type - an RBU_PK_XXX value */
-
- /* Output variables. zTbl==0 implies EOF. */
- int bCleanup; /* True in "cleanup" state */
- const char *zTbl; /* Name of target db table */
- const char *zDataTbl; /* Name of rbu db table (or null) */
- const char *zIdx; /* Name of target db index (or null) */
- int iTnum; /* Root page of current object */
- int iPkTnum; /* If eType==EXTERNAL, root of PK index */
- int bUnique; /* Current index is unique */
- int nIndex; /* Number of aux. indexes on table zTbl */
-
- /* Statements created by rbuObjIterPrepareAll() */
- int nCol; /* Number of columns in current object */
- sqlite3_stmt *pSelect; /* Source data */
- sqlite3_stmt *pInsert; /* Statement for INSERT operations */
- sqlite3_stmt *pDelete; /* Statement for DELETE ops */
- sqlite3_stmt *pTmpInsert; /* Insert into rbu_tmp_$zDataTbl */
-
- /* Last UPDATE used (for PK b-tree updates only), or NULL. */
- RbuUpdateStmt *pRbuUpdate;
-};
-
-/*
-** Values for RbuObjIter.eType
-**
-** 0: Table does not exist (error)
-** 1: Table has an implicit rowid.
-** 2: Table has an explicit IPK column.
-** 3: Table has an external PK index.
-** 4: Table is WITHOUT ROWID.
-** 5: Table is a virtual table.
-*/
-#define RBU_PK_NOTABLE 0
-#define RBU_PK_NONE 1
-#define RBU_PK_IPK 2
-#define RBU_PK_EXTERNAL 3
-#define RBU_PK_WITHOUT_ROWID 4
-#define RBU_PK_VTAB 5
-
-
-/*
-** Within the RBU_STAGE_OAL stage, each call to sqlite3rbu_step() performs
-** one of the following operations.
-*/
-#define RBU_INSERT 1 /* Insert on a main table b-tree */
-#define RBU_DELETE 2 /* Delete a row from a main table b-tree */
-#define RBU_REPLACE 3 /* Delete and then insert a row */
-#define RBU_IDX_DELETE 4 /* Delete a row from an aux. index b-tree */
-#define RBU_IDX_INSERT 5 /* Insert on an aux. index b-tree */
-
-#define RBU_UPDATE 6 /* Update a row in a main table b-tree */
-
-/*
-** A single step of an incremental checkpoint - frame iWalFrame of the wal
-** file should be copied to page iDbPage of the database file.
-*/
-struct RbuFrame {
- u32 iDbPage;
- u32 iWalFrame;
-};
-
-/*
-** RBU handle.
-**
-** nPhaseOneStep:
-** If the RBU database contains an rbu_count table, this value is set to
-** a running estimate of the number of b-tree operations required to
-** finish populating the *-oal file. This allows the sqlite3_bp_progress()
-** API to calculate the permyriadage progress of populating the *-oal file
-** using the formula:
-**
-** permyriadage = (10000 * nProgress) / nPhaseOneStep
-**
-** nPhaseOneStep is initialized to the sum of:
-**
-** nRow * (nIndex + 1)
-**
-** for all source tables in the RBU database, where nRow is the number
-** of rows in the source table and nIndex the number of indexes on the
-** corresponding target database table.
-**
-** This estimate is accurate if the RBU update consists entirely of
-** INSERT operations. However, it is inaccurate if:
-**
-** * the RBU update contains any UPDATE operations. If the PK specified
-** for an UPDATE operation does not exist in the target table, then
-** no b-tree operations are required on index b-trees. Or if the
-** specified PK does exist, then (nIndex*2) such operations are
-** required (one delete and one insert on each index b-tree).
-**
-** * the RBU update contains any DELETE operations for which the specified
-** PK does not exist. In this case no operations are required on index
-** b-trees.
-**
-** * the RBU update contains REPLACE operations. These are similar to
-** UPDATE operations.
-**
-** nPhaseOneStep is updated to account for the conditions above during the
-** first pass of each source table. The updated nPhaseOneStep value is
-** stored in the rbu_state table if the RBU update is suspended.
-*/
-struct sqlite3rbu {
- int eStage; /* Value of RBU_STATE_STAGE field */
- sqlite3 *dbMain; /* target database handle */
- sqlite3 *dbRbu; /* rbu database handle */
- char *zTarget; /* Path to target db */
- char *zRbu; /* Path to rbu db */
- char *zState; /* Path to state db (or NULL if zRbu) */
- char zStateDb[5]; /* Db name for state ("stat" or "main") */
- int rc; /* Value returned by last rbu_step() call */
- char *zErrmsg; /* Error message if rc!=SQLITE_OK */
- int nStep; /* Rows processed for current object */
- int nProgress; /* Rows processed for all objects */
- RbuObjIter objiter; /* Iterator for skipping through tbl/idx */
- const char *zVfsName; /* Name of automatically created rbu vfs */
- rbu_file *pTargetFd; /* File handle open on target db */
- i64 iOalSz;
- i64 nPhaseOneStep;
-
- /* The following state variables are used as part of the incremental
- ** checkpoint stage (eStage==RBU_STAGE_CKPT). See comments surrounding
- ** function rbuSetupCheckpoint() for details. */
- u32 iMaxFrame; /* Largest iWalFrame value in aFrame[] */
- u32 mLock;
- int nFrame; /* Entries in aFrame[] array */
- int nFrameAlloc; /* Allocated size of aFrame[] array */
- RbuFrame *aFrame;
- int pgsz;
- u8 *aBuf;
- i64 iWalCksum;
-
- /* Used in RBU vacuum mode only */
- int nRbu; /* Number of RBU VFS in the stack */
- rbu_file *pRbuFd; /* Fd for main db of dbRbu */
-};
-
-/*
-** An rbu VFS is implemented using an instance of this structure.
-*/
-struct rbu_vfs {
- sqlite3_vfs base; /* rbu VFS shim methods */
- sqlite3_vfs *pRealVfs; /* Underlying VFS */
- sqlite3_mutex *mutex; /* Mutex to protect pMain */
- rbu_file *pMain; /* Linked list of main db files */
-};
-
-/*
-** Each file opened by an rbu VFS is represented by an instance of
-** the following structure.
-*/
-struct rbu_file {
- sqlite3_file base; /* sqlite3_file methods */
- sqlite3_file *pReal; /* Underlying file handle */
- rbu_vfs *pRbuVfs; /* Pointer to the rbu_vfs object */
- sqlite3rbu *pRbu; /* Pointer to rbu object (rbu target only) */
-
- int openFlags; /* Flags this file was opened with */
- u32 iCookie; /* Cookie value for main db files */
- u8 iWriteVer; /* "write-version" value for main db files */
- u8 bNolock; /* True to fail EXCLUSIVE locks */
-
- int nShm; /* Number of entries in apShm[] array */
- char **apShm; /* Array of mmap'd *-shm regions */
- char *zDel; /* Delete this when closing file */
-
- const char *zWal; /* Wal filename for this main db file */
- rbu_file *pWalFd; /* Wal file descriptor for this main db */
- rbu_file *pMainNext; /* Next MAIN_DB file */
-};
-
-/*
-** True for an RBU vacuum handle, or false otherwise.
-*/
-#define rbuIsVacuum(p) ((p)->zTarget==0)
-
-
-/*************************************************************************
-** The following three functions, found below:
-**
-** rbuDeltaGetInt()
-** rbuDeltaChecksum()
-** rbuDeltaApply()
-**
-** are lifted from the fossil source code (http://fossil-scm.org). They
-** are used to implement the scalar SQL function rbu_fossil_delta().
-*/
-
-/*
-** Read bytes from *pz and convert them into a positive integer. When
-** finished, leave *pz pointing to the first character past the end of
-** the integer. The *pLen parameter holds the length of the string
-** in *pz and is decremented once for each character in the integer.
-*/
-static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){
- static const signed char zValue[] = {
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
- -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
- 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 36,
- -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, -1, -1, -1, 63, -1,
- };
- unsigned int v = 0;
- int c;
- unsigned char *z = (unsigned char*)*pz;
- unsigned char *zStart = z;
- while( (c = zValue[0x7f&*(z++)])>=0 ){
- v = (v<<6) + c;
- }
- z--;
- *pLen -= z - zStart;
- *pz = (char*)z;
- return v;
-}
-
-/*
-** Compute a 32-bit checksum on the N-byte buffer. Return the result.
-*/
-static unsigned int rbuDeltaChecksum(const char *zIn, size_t N){
- const unsigned char *z = (const unsigned char *)zIn;
- unsigned sum0 = 0;
- unsigned sum1 = 0;
- unsigned sum2 = 0;
- unsigned sum3 = 0;
- while(N >= 16){
- sum0 += ((unsigned)z[0] + z[4] + z[8] + z[12]);
- sum1 += ((unsigned)z[1] + z[5] + z[9] + z[13]);
- sum2 += ((unsigned)z[2] + z[6] + z[10]+ z[14]);
- sum3 += ((unsigned)z[3] + z[7] + z[11]+ z[15]);
- z += 16;
- N -= 16;
- }
- while(N >= 4){
- sum0 += z[0];
- sum1 += z[1];
- sum2 += z[2];
- sum3 += z[3];
- z += 4;
- N -= 4;
- }
- sum3 += (sum2 << 8) + (sum1 << 16) + (sum0 << 24);
- switch(N){
- case 3: sum3 += (z[2] << 8);
- case 2: sum3 += (z[1] << 16);
- case 1: sum3 += (z[0] << 24);
- default: ;
- }
- return sum3;
-}
-
-/*
-** Apply a delta.
-**
-** The output buffer should be big enough to hold the whole output
-** file and a NUL terminator at the end. The delta_output_size()
-** routine will determine this size for you.
-**
-** The delta string should be null-terminated. But the delta string
-** may contain embedded NUL characters (if the input and output are
-** binary files) so we also have to pass in the length of the delta in
-** the lenDelta parameter.
-**
-** This function returns the size of the output file in bytes (excluding
-** the final NUL terminator character). Except, if the delta string is
-** malformed or intended for use with a source file other than zSrc,
-** then this routine returns -1.
-**
-** Refer to the delta_create() documentation above for a description
-** of the delta file format.
-*/
-static int rbuDeltaApply(
- const char *zSrc, /* The source or pattern file */
- int lenSrc, /* Length of the source file */
- const char *zDelta, /* Delta to apply to the pattern */
- int lenDelta, /* Length of the delta */
- char *zOut /* Write the output into this preallocated buffer */
-){
- unsigned int limit;
- unsigned int total = 0;
-#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST
- char *zOrigOut = zOut;
-#endif
-
- limit = rbuDeltaGetInt(&zDelta, &lenDelta);
- if( *zDelta!='\n' ){
- /* ERROR: size integer not terminated by "\n" */
- return -1;
- }
- zDelta++; lenDelta--;
- while( *zDelta && lenDelta>0 ){
- unsigned int cnt, ofst;
- cnt = rbuDeltaGetInt(&zDelta, &lenDelta);
- switch( zDelta[0] ){
- case '@': {
- zDelta++; lenDelta--;
- ofst = rbuDeltaGetInt(&zDelta, &lenDelta);
- if( lenDelta>0 && zDelta[0]!=',' ){
- /* ERROR: copy command not terminated by ',' */
- return -1;
- }
- zDelta++; lenDelta--;
- total += cnt;
- if( total>limit ){
- /* ERROR: copy exceeds output file size */
- return -1;
- }
- if( (int)(ofst+cnt) > lenSrc ){
- /* ERROR: copy extends past end of input */
- return -1;
- }
- memcpy(zOut, &zSrc[ofst], cnt);
- zOut += cnt;
- break;
- }
- case ':': {
- zDelta++; lenDelta--;
- total += cnt;
- if( total>limit ){
- /* ERROR: insert command gives an output larger than predicted */
- return -1;
- }
- if( (int)cnt>lenDelta ){
- /* ERROR: insert count exceeds size of delta */
- return -1;
- }
- memcpy(zOut, zDelta, cnt);
- zOut += cnt;
- zDelta += cnt;
- lenDelta -= cnt;
- break;
- }
- case ';': {
- zDelta++; lenDelta--;
- zOut[0] = 0;
-#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST
- if( cnt!=rbuDeltaChecksum(zOrigOut, total) ){
- /* ERROR: bad checksum */
- return -1;
- }
-#endif
- if( total!=limit ){
- /* ERROR: generated size does not match predicted size */
- return -1;
- }
- return total;
- }
- default: {
- /* ERROR: unknown delta operator */
- return -1;
- }
- }
- }
- /* ERROR: unterminated delta */
- return -1;
-}
-
-static int rbuDeltaOutputSize(const char *zDelta, int lenDelta){
- int size;
- size = rbuDeltaGetInt(&zDelta, &lenDelta);
- if( *zDelta!='\n' ){
- /* ERROR: size integer not terminated by "\n" */
- return -1;
- }
- return size;
-}
-
-/*
-** End of code taken from fossil.
-*************************************************************************/
-
-/*
-** Implementation of SQL scalar function rbu_fossil_delta().
-**
-** This function applies a fossil delta patch to a blob. Exactly two
-** arguments must be passed to this function. The first is the blob to
-** patch and the second the patch to apply. If no error occurs, this
-** function returns the patched blob.
-*/
-static void rbuFossilDeltaFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- const char *aDelta;
- int nDelta;
- const char *aOrig;
- int nOrig;
-
- int nOut;
- int nOut2;
- char *aOut;
-
- assert( argc==2 );
-
- nOrig = sqlite3_value_bytes(argv[0]);
- aOrig = (const char*)sqlite3_value_blob(argv[0]);
- nDelta = sqlite3_value_bytes(argv[1]);
- aDelta = (const char*)sqlite3_value_blob(argv[1]);
-
- /* Figure out the size of the output */
- nOut = rbuDeltaOutputSize(aDelta, nDelta);
- if( nOut<0 ){
- sqlite3_result_error(context, "corrupt fossil delta", -1);
- return;
- }
-
- aOut = sqlite3_malloc(nOut+1);
- if( aOut==0 ){
- sqlite3_result_error_nomem(context);
- }else{
- nOut2 = rbuDeltaApply(aOrig, nOrig, aDelta, nDelta, aOut);
- if( nOut2!=nOut ){
- sqlite3_result_error(context, "corrupt fossil delta", -1);
- }else{
- sqlite3_result_blob(context, aOut, nOut, sqlite3_free);
- }
- }
-}
-
-
-/*
-** Prepare the SQL statement in buffer zSql against database handle db.
-** If successful, set *ppStmt to point to the new statement and return
-** SQLITE_OK.
-**
-** Otherwise, if an error does occur, set *ppStmt to NULL and return
-** an SQLite error code. Additionally, set output variable *pzErrmsg to
-** point to a buffer containing an error message. It is the responsibility
-** of the caller to (eventually) free this buffer using sqlite3_free().
-*/
-static int prepareAndCollectError(
- sqlite3 *db,
- sqlite3_stmt **ppStmt,
- char **pzErrmsg,
- const char *zSql
-){
- int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
- if( rc!=SQLITE_OK ){
- *pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
- *ppStmt = 0;
- }
- return rc;
-}
-
-/*
-** Reset the SQL statement passed as the first argument. Return a copy
-** of the value returned by sqlite3_reset().
-**
-** If an error has occurred, then set *pzErrmsg to point to a buffer
-** containing an error message. It is the responsibility of the caller
-** to eventually free this buffer using sqlite3_free().
-*/
-static int resetAndCollectError(sqlite3_stmt *pStmt, char **pzErrmsg){
- int rc = sqlite3_reset(pStmt);
- if( rc!=SQLITE_OK ){
- *pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(sqlite3_db_handle(pStmt)));
- }
- return rc;
-}
-
-/*
-** Unless it is NULL, argument zSql points to a buffer allocated using
-** sqlite3_malloc containing an SQL statement. This function prepares the SQL
-** statement against database db and frees the buffer. If statement
-** compilation is successful, *ppStmt is set to point to the new statement
-** handle and SQLITE_OK is returned.
-**
-** Otherwise, if an error occurs, *ppStmt is set to NULL and an error code
-** returned. In this case, *pzErrmsg may also be set to point to an error
-** message. It is the responsibility of the caller to free this error message
-** buffer using sqlite3_free().
-**
-** If argument zSql is NULL, this function assumes that an OOM has occurred.
-** In this case SQLITE_NOMEM is returned and *ppStmt set to NULL.
-*/
-static int prepareFreeAndCollectError(
- sqlite3 *db,
- sqlite3_stmt **ppStmt,
- char **pzErrmsg,
- char *zSql
-){
- int rc;
- assert( *pzErrmsg==0 );
- if( zSql==0 ){
- rc = SQLITE_NOMEM;
- *ppStmt = 0;
- }else{
- rc = prepareAndCollectError(db, ppStmt, pzErrmsg, zSql);
- sqlite3_free(zSql);
- }
- return rc;
-}
-
-/*
-** Free the RbuObjIter.azTblCol[] and RbuObjIter.abTblPk[] arrays allocated
-** by an earlier call to rbuObjIterCacheTableInfo().
-*/
-static void rbuObjIterFreeCols(RbuObjIter *pIter){
- int i;
- for(i=0; i<pIter->nTblCol; i++){
- sqlite3_free(pIter->azTblCol[i]);
- sqlite3_free(pIter->azTblType[i]);
- }
- sqlite3_free(pIter->azTblCol);
- pIter->azTblCol = 0;
- pIter->azTblType = 0;
- pIter->aiSrcOrder = 0;
- pIter->abTblPk = 0;
- pIter->abNotNull = 0;
- pIter->nTblCol = 0;
- pIter->eType = 0; /* Invalid value */
-}
-
-/*
-** Finalize all statements and free all allocations that are specific to
-** the current object (table/index pair).
-*/
-static void rbuObjIterClearStatements(RbuObjIter *pIter){
- RbuUpdateStmt *pUp;
-
- sqlite3_finalize(pIter->pSelect);
- sqlite3_finalize(pIter->pInsert);
- sqlite3_finalize(pIter->pDelete);
- sqlite3_finalize(pIter->pTmpInsert);
- pUp = pIter->pRbuUpdate;
- while( pUp ){
- RbuUpdateStmt *pTmp = pUp->pNext;
- sqlite3_finalize(pUp->pUpdate);
- sqlite3_free(pUp);
- pUp = pTmp;
- }
-
- pIter->pSelect = 0;
- pIter->pInsert = 0;
- pIter->pDelete = 0;
- pIter->pRbuUpdate = 0;
- pIter->pTmpInsert = 0;
- pIter->nCol = 0;
-}
-
-/*
-** Clean up any resources allocated as part of the iterator object passed
-** as the only argument.
-*/
-static void rbuObjIterFinalize(RbuObjIter *pIter){
- rbuObjIterClearStatements(pIter);
- sqlite3_finalize(pIter->pTblIter);
- sqlite3_finalize(pIter->pIdxIter);
- rbuObjIterFreeCols(pIter);
- memset(pIter, 0, sizeof(RbuObjIter));
-}
-
-/*
-** Advance the iterator to the next position.
-**
-** If no error occurs, SQLITE_OK is returned and the iterator is left
-** pointing to the next entry. Otherwise, an error code and message is
-** left in the RBU handle passed as the first argument. A copy of the
-** error code is returned.
-*/
-static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){
- int rc = p->rc;
- if( rc==SQLITE_OK ){
-
- /* Free any SQLite statements used while processing the previous object */
- rbuObjIterClearStatements(pIter);
- if( pIter->zIdx==0 ){
- rc = sqlite3_exec(p->dbMain,
- "DROP TRIGGER IF EXISTS temp.rbu_insert_tr;"
- "DROP TRIGGER IF EXISTS temp.rbu_update1_tr;"
- "DROP TRIGGER IF EXISTS temp.rbu_update2_tr;"
- "DROP TRIGGER IF EXISTS temp.rbu_delete_tr;"
- , 0, 0, &p->zErrmsg
- );
- }
-
- if( rc==SQLITE_OK ){
- if( pIter->bCleanup ){
- rbuObjIterFreeCols(pIter);
- pIter->bCleanup = 0;
- rc = sqlite3_step(pIter->pTblIter);
- if( rc!=SQLITE_ROW ){
- rc = resetAndCollectError(pIter->pTblIter, &p->zErrmsg);
- pIter->zTbl = 0;
- }else{
- pIter->zTbl = (const char*)sqlite3_column_text(pIter->pTblIter, 0);
- pIter->zDataTbl = (const char*)sqlite3_column_text(pIter->pTblIter,1);
- rc = (pIter->zDataTbl && pIter->zTbl) ? SQLITE_OK : SQLITE_NOMEM;
- }
- }else{
- if( pIter->zIdx==0 ){
- sqlite3_stmt *pIdx = pIter->pIdxIter;
- rc = sqlite3_bind_text(pIdx, 1, pIter->zTbl, -1, SQLITE_STATIC);
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3_step(pIter->pIdxIter);
- if( rc!=SQLITE_ROW ){
- rc = resetAndCollectError(pIter->pIdxIter, &p->zErrmsg);
- pIter->bCleanup = 1;
- pIter->zIdx = 0;
- }else{
- pIter->zIdx = (const char*)sqlite3_column_text(pIter->pIdxIter, 0);
- pIter->iTnum = sqlite3_column_int(pIter->pIdxIter, 1);
- pIter->bUnique = sqlite3_column_int(pIter->pIdxIter, 2);
- rc = pIter->zIdx ? SQLITE_OK : SQLITE_NOMEM;
- }
- }
- }
- }
- }
-
- if( rc!=SQLITE_OK ){
- rbuObjIterFinalize(pIter);
- p->rc = rc;
- }
- return rc;
-}
-
-
-/*
-** The implementation of the rbu_target_name() SQL function. This function
-** accepts one or two arguments. The first argument is the name of a table -
-** the name of a table in the RBU database. The second, if it is present, is 1
-** for a view or 0 for a table.
-**
-** For a non-vacuum RBU handle, if the table name matches the pattern:
-**
-** data[0-9]_<name>
-**
-** where <name> is any sequence of 1 or more characters, <name> is returned.
-** Otherwise, if the only argument does not match the above pattern, an SQL
-** NULL is returned.
-**
-** "data_t1" -> "t1"
-** "data0123_t2" -> "t2"
-** "dataAB_t3" -> NULL
-**
-** For an rbu vacuum handle, a copy of the first argument is returned if
-** the second argument is either missing or 0 (not a view).
-*/
-static void rbuTargetNameFunc(
- sqlite3_context *pCtx,
- int argc,
- sqlite3_value **argv
-){
- sqlite3rbu *p = sqlite3_user_data(pCtx);
- const char *zIn;
- assert( argc==1 || argc==2 );
-
- zIn = (const char*)sqlite3_value_text(argv[0]);
- if( zIn ){
- if( rbuIsVacuum(p) ){
- if( argc==1 || 0==sqlite3_value_int(argv[1]) ){
- sqlite3_result_text(pCtx, zIn, -1, SQLITE_STATIC);
- }
- }else{
- if( strlen(zIn)>4 && memcmp("data", zIn, 4)==0 ){
- int i;
- for(i=4; zIn[i]>='0' && zIn[i]<='9'; i++);
- if( zIn[i]=='_' && zIn[i+1] ){
- sqlite3_result_text(pCtx, &zIn[i+1], -1, SQLITE_STATIC);
- }
- }
- }
- }
-}
-
-/*
-** Initialize the iterator structure passed as the second argument.
-**
-** If no error occurs, SQLITE_OK is returned and the iterator is left
-** pointing to the first entry. Otherwise, an error code and message is
-** left in the RBU handle passed as the first argument. A copy of the
-** error code is returned.
-*/
-static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
- int rc;
- memset(pIter, 0, sizeof(RbuObjIter));
-
- rc = prepareAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg,
- "SELECT rbu_target_name(name, type='view') AS target, name "
- "FROM sqlite_master "
- "WHERE type IN ('table', 'view') AND target IS NOT NULL "
- "ORDER BY name"
- );
-
- if( rc==SQLITE_OK ){
- rc = prepareAndCollectError(p->dbMain, &pIter->pIdxIter, &p->zErrmsg,
- "SELECT name, rootpage, sql IS NULL OR substr(8, 6)=='UNIQUE' "
- " FROM main.sqlite_master "
- " WHERE type='index' AND tbl_name = ?"
- );
- }
-
- pIter->bCleanup = 1;
- p->rc = rc;
- return rbuObjIterNext(p, pIter);
-}
-
-/*
-** This is a wrapper around "sqlite3_mprintf(zFmt, ...)". If an OOM occurs,
-** an error code is stored in the RBU handle passed as the first argument.
-**
-** If an error has already occurred (p->rc is already set to something other
-** than SQLITE_OK), then this function returns NULL without modifying the
-** stored error code. In this case it still calls sqlite3_free() on any
-** printf() parameters associated with %z conversions.
-*/
-static char *rbuMPrintf(sqlite3rbu *p, const char *zFmt, ...){
- char *zSql = 0;
- va_list ap;
- va_start(ap, zFmt);
- zSql = sqlite3_vmprintf(zFmt, ap);
- if( p->rc==SQLITE_OK ){
- if( zSql==0 ) p->rc = SQLITE_NOMEM;
- }else{
- sqlite3_free(zSql);
- zSql = 0;
- }
- va_end(ap);
- return zSql;
-}
-
-/*
-** Argument zFmt is a sqlite3_mprintf() style format string. The trailing
-** arguments are the usual subsitution values. This function performs
-** the printf() style substitutions and executes the result as an SQL
-** statement on the RBU handles database.
-**
-** If an error occurs, an error code and error message is stored in the
-** RBU handle. If an error has already occurred when this function is
-** called, it is a no-op.
-*/
-static int rbuMPrintfExec(sqlite3rbu *p, sqlite3 *db, const char *zFmt, ...){
- va_list ap;
- char *zSql;
- va_start(ap, zFmt);
- zSql = sqlite3_vmprintf(zFmt, ap);
- if( p->rc==SQLITE_OK ){
- if( zSql==0 ){
- p->rc = SQLITE_NOMEM;
- }else{
- p->rc = sqlite3_exec(db, zSql, 0, 0, &p->zErrmsg);
- }
- }
- sqlite3_free(zSql);
- va_end(ap);
- return p->rc;
-}
-
-/*
-** Attempt to allocate and return a pointer to a zeroed block of nByte
-** bytes.
-**
-** If an error (i.e. an OOM condition) occurs, return NULL and leave an
-** error code in the rbu handle passed as the first argument. Or, if an
-** error has already occurred when this function is called, return NULL
-** immediately without attempting the allocation or modifying the stored
-** error code.
-*/
-static void *rbuMalloc(sqlite3rbu *p, int nByte){
- void *pRet = 0;
- if( p->rc==SQLITE_OK ){
- assert( nByte>0 );
- pRet = sqlite3_malloc64(nByte);
- if( pRet==0 ){
- p->rc = SQLITE_NOMEM;
- }else{
- memset(pRet, 0, nByte);
- }
- }
- return pRet;
-}
-
-
-/*
-** Allocate and zero the pIter->azTblCol[] and abTblPk[] arrays so that
-** there is room for at least nCol elements. If an OOM occurs, store an
-** error code in the RBU handle passed as the first argument.
-*/
-static void rbuAllocateIterArrays(sqlite3rbu *p, RbuObjIter *pIter, int nCol){
- int nByte = (2*sizeof(char*) + sizeof(int) + 3*sizeof(u8)) * nCol;
- char **azNew;
-
- azNew = (char**)rbuMalloc(p, nByte);
- if( azNew ){
- pIter->azTblCol = azNew;
- pIter->azTblType = &azNew[nCol];
- pIter->aiSrcOrder = (int*)&pIter->azTblType[nCol];
- pIter->abTblPk = (u8*)&pIter->aiSrcOrder[nCol];
- pIter->abNotNull = (u8*)&pIter->abTblPk[nCol];
- pIter->abIndexed = (u8*)&pIter->abNotNull[nCol];
- }
-}
-
-/*
-** The first argument must be a nul-terminated string. This function
-** returns a copy of the string in memory obtained from sqlite3_malloc().
-** It is the responsibility of the caller to eventually free this memory
-** using sqlite3_free().
-**
-** If an OOM condition is encountered when attempting to allocate memory,
-** output variable (*pRc) is set to SQLITE_NOMEM before returning. Otherwise,
-** if the allocation succeeds, (*pRc) is left unchanged.
-*/
-static char *rbuStrndup(const char *zStr, int *pRc){
- char *zRet = 0;
-
- assert( *pRc==SQLITE_OK );
- if( zStr ){
- size_t nCopy = strlen(zStr) + 1;
- zRet = (char*)sqlite3_malloc64(nCopy);
- if( zRet ){
- memcpy(zRet, zStr, nCopy);
- }else{
- *pRc = SQLITE_NOMEM;
- }
- }
-
- return zRet;
-}
-
-/*
-** Finalize the statement passed as the second argument.
-**
-** If the sqlite3_finalize() call indicates that an error occurs, and the
-** rbu handle error code is not already set, set the error code and error
-** message accordingly.
-*/
-static void rbuFinalize(sqlite3rbu *p, sqlite3_stmt *pStmt){
- sqlite3 *db = sqlite3_db_handle(pStmt);
- int rc = sqlite3_finalize(pStmt);
- if( p->rc==SQLITE_OK && rc!=SQLITE_OK ){
- p->rc = rc;
- p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
- }
-}
-
-/* Determine the type of a table.
-**
-** peType is of type (int*), a pointer to an output parameter of type
-** (int). This call sets the output parameter as follows, depending
-** on the type of the table specified by parameters dbName and zTbl.
-**
-** RBU_PK_NOTABLE: No such table.
-** RBU_PK_NONE: Table has an implicit rowid.
-** RBU_PK_IPK: Table has an explicit IPK column.
-** RBU_PK_EXTERNAL: Table has an external PK index.
-** RBU_PK_WITHOUT_ROWID: Table is WITHOUT ROWID.
-** RBU_PK_VTAB: Table is a virtual table.
-**
-** Argument *piPk is also of type (int*), and also points to an output
-** parameter. Unless the table has an external primary key index
-** (i.e. unless *peType is set to 3), then *piPk is set to zero. Or,
-** if the table does have an external primary key index, then *piPk
-** is set to the root page number of the primary key index before
-** returning.
-**
-** ALGORITHM:
-**
-** if( no entry exists in sqlite_master ){
-** return RBU_PK_NOTABLE
-** }else if( sql for the entry starts with "CREATE VIRTUAL" ){
-** return RBU_PK_VTAB
-** }else if( "PRAGMA index_list()" for the table contains a "pk" index ){
-** if( the index that is the pk exists in sqlite_master ){
-** *piPK = rootpage of that index.
-** return RBU_PK_EXTERNAL
-** }else{
-** return RBU_PK_WITHOUT_ROWID
-** }
-** }else if( "PRAGMA table_info()" lists one or more "pk" columns ){
-** return RBU_PK_IPK
-** }else{
-** return RBU_PK_NONE
-** }
-*/
-static void rbuTableType(
- sqlite3rbu *p,
- const char *zTab,
- int *peType,
- int *piTnum,
- int *piPk
-){
- /*
- ** 0) SELECT count(*) FROM sqlite_master where name=%Q AND IsVirtual(%Q)
- ** 1) PRAGMA index_list = ?
- ** 2) SELECT count(*) FROM sqlite_master where name=%Q
- ** 3) PRAGMA table_info = ?
- */
- sqlite3_stmt *aStmt[4] = {0, 0, 0, 0};
-
- *peType = RBU_PK_NOTABLE;
- *piPk = 0;
-
- assert( p->rc==SQLITE_OK );
- p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[0], &p->zErrmsg,
- sqlite3_mprintf(
- "SELECT (sql LIKE 'create virtual%%'), rootpage"
- " FROM sqlite_master"
- " WHERE name=%Q", zTab
- ));
- if( p->rc!=SQLITE_OK || sqlite3_step(aStmt[0])!=SQLITE_ROW ){
- /* Either an error, or no such table. */
- goto rbuTableType_end;
- }
- if( sqlite3_column_int(aStmt[0], 0) ){
- *peType = RBU_PK_VTAB; /* virtual table */
- goto rbuTableType_end;
- }
- *piTnum = sqlite3_column_int(aStmt[0], 1);
-
- p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[1], &p->zErrmsg,
- sqlite3_mprintf("PRAGMA index_list=%Q",zTab)
- );
- if( p->rc ) goto rbuTableType_end;
- while( sqlite3_step(aStmt[1])==SQLITE_ROW ){
- const u8 *zOrig = sqlite3_column_text(aStmt[1], 3);
- const u8 *zIdx = sqlite3_column_text(aStmt[1], 1);
- if( zOrig && zIdx && zOrig[0]=='p' ){
- p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[2], &p->zErrmsg,
- sqlite3_mprintf(
- "SELECT rootpage FROM sqlite_master WHERE name = %Q", zIdx
- ));
- if( p->rc==SQLITE_OK ){
- if( sqlite3_step(aStmt[2])==SQLITE_ROW ){
- *piPk = sqlite3_column_int(aStmt[2], 0);
- *peType = RBU_PK_EXTERNAL;
- }else{
- *peType = RBU_PK_WITHOUT_ROWID;
- }
- }
- goto rbuTableType_end;
- }
- }
-
- p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[3], &p->zErrmsg,
- sqlite3_mprintf("PRAGMA table_info=%Q",zTab)
- );
- if( p->rc==SQLITE_OK ){
- while( sqlite3_step(aStmt[3])==SQLITE_ROW ){
- if( sqlite3_column_int(aStmt[3],5)>0 ){
- *peType = RBU_PK_IPK; /* explicit IPK column */
- goto rbuTableType_end;
- }
- }
- *peType = RBU_PK_NONE;
- }
-
-rbuTableType_end: {
- unsigned int i;
- for(i=0; i<sizeof(aStmt)/sizeof(aStmt[0]); i++){
- rbuFinalize(p, aStmt[i]);
- }
- }
-}
-
-/*
-** This is a helper function for rbuObjIterCacheTableInfo(). It populates
-** the pIter->abIndexed[] array.
-*/
-static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){
- sqlite3_stmt *pList = 0;
- int bIndex = 0;
-
- if( p->rc==SQLITE_OK ){
- memcpy(pIter->abIndexed, pIter->abTblPk, sizeof(u8)*pIter->nTblCol);
- p->rc = prepareFreeAndCollectError(p->dbMain, &pList, &p->zErrmsg,
- sqlite3_mprintf("PRAGMA main.index_list = %Q", pIter->zTbl)
- );
- }
-
- pIter->nIndex = 0;
- while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){
- const char *zIdx = (const char*)sqlite3_column_text(pList, 1);
- sqlite3_stmt *pXInfo = 0;
- if( zIdx==0 ) break;
- p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg,
- sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx)
- );
- while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){
- int iCid = sqlite3_column_int(pXInfo, 1);
- if( iCid>=0 ) pIter->abIndexed[iCid] = 1;
- }
- rbuFinalize(p, pXInfo);
- bIndex = 1;
- pIter->nIndex++;
- }
-
- if( pIter->eType==RBU_PK_WITHOUT_ROWID ){
- /* "PRAGMA index_list" includes the main PK b-tree */
- pIter->nIndex--;
- }
-
- rbuFinalize(p, pList);
- if( bIndex==0 ) pIter->abIndexed = 0;
-}
-
-
-/*
-** If they are not already populated, populate the pIter->azTblCol[],
-** pIter->abTblPk[], pIter->nTblCol and pIter->bRowid variables according to
-** the table (not index) that the iterator currently points to.
-**
-** Return SQLITE_OK if successful, or an SQLite error code otherwise. If
-** an error does occur, an error code and error message are also left in
-** the RBU handle.
-*/
-static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
- if( pIter->azTblCol==0 ){
- sqlite3_stmt *pStmt = 0;
- int nCol = 0;
- int i; /* for() loop iterator variable */
- int bRbuRowid = 0; /* If input table has column "rbu_rowid" */
- int iOrder = 0;
- int iTnum = 0;
-
- /* Figure out the type of table this step will deal with. */
- assert( pIter->eType==0 );
- rbuTableType(p, pIter->zTbl, &pIter->eType, &iTnum, &pIter->iPkTnum);
- if( p->rc==SQLITE_OK && pIter->eType==RBU_PK_NOTABLE ){
- p->rc = SQLITE_ERROR;
- p->zErrmsg = sqlite3_mprintf("no such table: %s", pIter->zTbl);
- }
- if( p->rc ) return p->rc;
- if( pIter->zIdx==0 ) pIter->iTnum = iTnum;
-
- assert( pIter->eType==RBU_PK_NONE || pIter->eType==RBU_PK_IPK
- || pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_WITHOUT_ROWID
- || pIter->eType==RBU_PK_VTAB
- );
-
- /* Populate the azTblCol[] and nTblCol variables based on the columns
- ** of the input table. Ignore any input table columns that begin with
- ** "rbu_". */
- p->rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
- sqlite3_mprintf("SELECT * FROM '%q'", pIter->zDataTbl)
- );
- if( p->rc==SQLITE_OK ){
- nCol = sqlite3_column_count(pStmt);
- rbuAllocateIterArrays(p, pIter, nCol);
- }
- for(i=0; p->rc==SQLITE_OK && i<nCol; i++){
- const char *zName = (const char*)sqlite3_column_name(pStmt, i);
- if( sqlite3_strnicmp("rbu_", zName, 4) ){
- char *zCopy = rbuStrndup(zName, &p->rc);
- pIter->aiSrcOrder[pIter->nTblCol] = pIter->nTblCol;
- pIter->azTblCol[pIter->nTblCol++] = zCopy;
- }
- else if( 0==sqlite3_stricmp("rbu_rowid", zName) ){
- bRbuRowid = 1;
- }
- }
- sqlite3_finalize(pStmt);
- pStmt = 0;
-
- if( p->rc==SQLITE_OK
- && rbuIsVacuum(p)==0
- && bRbuRowid!=(pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE)
- ){
- p->rc = SQLITE_ERROR;
- p->zErrmsg = sqlite3_mprintf(
- "table %q %s rbu_rowid column", pIter->zDataTbl,
- (bRbuRowid ? "may not have" : "requires")
- );
- }
-
- /* Check that all non-HIDDEN columns in the destination table are also
- ** present in the input table. Populate the abTblPk[], azTblType[] and
- ** aiTblOrder[] arrays at the same time. */
- if( p->rc==SQLITE_OK ){
- p->rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &p->zErrmsg,
- sqlite3_mprintf("PRAGMA table_info(%Q)", pIter->zTbl)
- );
- }
- while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
- const char *zName = (const char*)sqlite3_column_text(pStmt, 1);
- if( zName==0 ) break; /* An OOM - finalize() below returns S_NOMEM */
- for(i=iOrder; i<pIter->nTblCol; i++){
- if( 0==strcmp(zName, pIter->azTblCol[i]) ) break;
- }
- if( i==pIter->nTblCol ){
- p->rc = SQLITE_ERROR;
- p->zErrmsg = sqlite3_mprintf("column missing from %q: %s",
- pIter->zDataTbl, zName
- );
- }else{
- int iPk = sqlite3_column_int(pStmt, 5);
- int bNotNull = sqlite3_column_int(pStmt, 3);
- const char *zType = (const char*)sqlite3_column_text(pStmt, 2);
-
- if( i!=iOrder ){
- SWAP(int, pIter->aiSrcOrder[i], pIter->aiSrcOrder[iOrder]);
- SWAP(char*, pIter->azTblCol[i], pIter->azTblCol[iOrder]);
- }
-
- pIter->azTblType[iOrder] = rbuStrndup(zType, &p->rc);
- pIter->abTblPk[iOrder] = (iPk!=0);
- pIter->abNotNull[iOrder] = (u8)bNotNull || (iPk!=0);
- iOrder++;
- }
- }
-
- rbuFinalize(p, pStmt);
- rbuObjIterCacheIndexedCols(p, pIter);
- assert( pIter->eType!=RBU_PK_VTAB || pIter->abIndexed==0 );
- assert( pIter->eType!=RBU_PK_VTAB || pIter->nIndex==0 );
- }
-
- return p->rc;
-}
-
-/*
-** This function constructs and returns a pointer to a nul-terminated
-** string containing some SQL clause or list based on one or more of the
-** column names currently stored in the pIter->azTblCol[] array.
-*/
-static char *rbuObjIterGetCollist(
- sqlite3rbu *p, /* RBU object */
- RbuObjIter *pIter /* Object iterator for column names */
-){
- char *zList = 0;
- const char *zSep = "";
- int i;
- for(i=0; i<pIter->nTblCol; i++){
- const char *z = pIter->azTblCol[i];
- zList = rbuMPrintf(p, "%z%s\"%w\"", zList, zSep, z);
- zSep = ", ";
- }
- return zList;
-}
-
-/*
-** This function is used to create a SELECT list (the list of SQL
-** expressions that follows a SELECT keyword) for a SELECT statement
-** used to read from an data_xxx or rbu_tmp_xxx table while updating the
-** index object currently indicated by the iterator object passed as the
-** second argument. A "PRAGMA index_xinfo = <idxname>" statement is used
-** to obtain the required information.
-**
-** If the index is of the following form:
-**
-** CREATE INDEX i1 ON t1(c, b COLLATE nocase);
-**
-** and "t1" is a table with an explicit INTEGER PRIMARY KEY column
-** "ipk", the returned string is:
-**
-** "`c` COLLATE 'BINARY', `b` COLLATE 'NOCASE', `ipk` COLLATE 'BINARY'"
-**
-** As well as the returned string, three other malloc'd strings are
-** returned via output parameters. As follows:
-**
-** pzImposterCols: ...
-** pzImposterPk: ...
-** pzWhere: ...
-*/
-static char *rbuObjIterGetIndexCols(
- sqlite3rbu *p, /* RBU object */
- RbuObjIter *pIter, /* Object iterator for column names */
- char **pzImposterCols, /* OUT: Columns for imposter table */
- char **pzImposterPk, /* OUT: Imposter PK clause */
- char **pzWhere, /* OUT: WHERE clause */
- int *pnBind /* OUT: Trbul number of columns */
-){
- int rc = p->rc; /* Error code */
- int rc2; /* sqlite3_finalize() return code */
- char *zRet = 0; /* String to return */
- char *zImpCols = 0; /* String to return via *pzImposterCols */
- char *zImpPK = 0; /* String to return via *pzImposterPK */
- char *zWhere = 0; /* String to return via *pzWhere */
- int nBind = 0; /* Value to return via *pnBind */
- const char *zCom = ""; /* Set to ", " later on */
- const char *zAnd = ""; /* Set to " AND " later on */
- sqlite3_stmt *pXInfo = 0; /* PRAGMA index_xinfo = ? */
-
- if( rc==SQLITE_OK ){
- assert( p->zErrmsg==0 );
- rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg,
- sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", pIter->zIdx)
- );
- }
-
- while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){
- int iCid = sqlite3_column_int(pXInfo, 1);
- int bDesc = sqlite3_column_int(pXInfo, 3);
- const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4);
- const char *zCol;
- const char *zType;
-
- if( iCid<0 ){
- /* An integer primary key. If the table has an explicit IPK, use
- ** its name. Otherwise, use "rbu_rowid". */
- if( pIter->eType==RBU_PK_IPK ){
- int i;
- for(i=0; pIter->abTblPk[i]==0; i++);
- assert( i<pIter->nTblCol );
- zCol = pIter->azTblCol[i];
- }else if( rbuIsVacuum(p) ){
- zCol = "_rowid_";
- }else{
- zCol = "rbu_rowid";
- }
- zType = "INTEGER";
- }else{
- zCol = pIter->azTblCol[iCid];
- zType = pIter->azTblType[iCid];
- }
-
- zRet = sqlite3_mprintf("%z%s\"%w\" COLLATE %Q", zRet, zCom, zCol, zCollate);
- if( pIter->bUnique==0 || sqlite3_column_int(pXInfo, 5) ){
- const char *zOrder = (bDesc ? " DESC" : "");
- zImpPK = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\"%s",
- zImpPK, zCom, nBind, zCol, zOrder
- );
- }
- zImpCols = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\" %s COLLATE %Q",
- zImpCols, zCom, nBind, zCol, zType, zCollate
- );
- zWhere = sqlite3_mprintf(
- "%z%s\"rbu_imp_%d%w\" IS ?", zWhere, zAnd, nBind, zCol
- );
- if( zRet==0 || zImpPK==0 || zImpCols==0 || zWhere==0 ) rc = SQLITE_NOMEM;
- zCom = ", ";
- zAnd = " AND ";
- nBind++;
- }
-
- rc2 = sqlite3_finalize(pXInfo);
- if( rc==SQLITE_OK ) rc = rc2;
-
- if( rc!=SQLITE_OK ){
- sqlite3_free(zRet);
- sqlite3_free(zImpCols);
- sqlite3_free(zImpPK);
- sqlite3_free(zWhere);
- zRet = 0;
- zImpCols = 0;
- zImpPK = 0;
- zWhere = 0;
- p->rc = rc;
- }
-
- *pzImposterCols = zImpCols;
- *pzImposterPk = zImpPK;
- *pzWhere = zWhere;
- *pnBind = nBind;
- return zRet;
-}
-
-/*
-** Assuming the current table columns are "a", "b" and "c", and the zObj
-** paramter is passed "old", return a string of the form:
-**
-** "old.a, old.b, old.b"
-**
-** With the column names escaped.
-**
-** For tables with implicit rowids - RBU_PK_EXTERNAL and RBU_PK_NONE, append
-** the text ", old._rowid_" to the returned value.
-*/
-static char *rbuObjIterGetOldlist(
- sqlite3rbu *p,
- RbuObjIter *pIter,
- const char *zObj
-){
- char *zList = 0;
- if( p->rc==SQLITE_OK && pIter->abIndexed ){
- const char *zS = "";
- int i;
- for(i=0; i<pIter->nTblCol; i++){
- if( pIter->abIndexed[i] ){
- const char *zCol = pIter->azTblCol[i];
- zList = sqlite3_mprintf("%z%s%s.\"%w\"", zList, zS, zObj, zCol);
- }else{
- zList = sqlite3_mprintf("%z%sNULL", zList, zS);
- }
- zS = ", ";
- if( zList==0 ){
- p->rc = SQLITE_NOMEM;
- break;
- }
- }
-
- /* For a table with implicit rowids, append "old._rowid_" to the list. */
- if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
- zList = rbuMPrintf(p, "%z, %s._rowid_", zList, zObj);
- }
- }
- return zList;
-}
-
-/*
-** Return an expression that can be used in a WHERE clause to match the
-** primary key of the current table. For example, if the table is:
-**
-** CREATE TABLE t1(a, b, c, PRIMARY KEY(b, c));
-**
-** Return the string:
-**
-** "b = ?1 AND c = ?2"
-*/
-static char *rbuObjIterGetWhere(
- sqlite3rbu *p,
- RbuObjIter *pIter
-){
- char *zList = 0;
- if( pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE ){
- zList = rbuMPrintf(p, "_rowid_ = ?%d", pIter->nTblCol+1);
- }else if( pIter->eType==RBU_PK_EXTERNAL ){
- const char *zSep = "";
- int i;
- for(i=0; i<pIter->nTblCol; i++){
- if( pIter->abTblPk[i] ){
- zList = rbuMPrintf(p, "%z%sc%d=?%d", zList, zSep, i, i+1);
- zSep = " AND ";
- }
- }
- zList = rbuMPrintf(p,
- "_rowid_ = (SELECT id FROM rbu_imposter2 WHERE %z)", zList
- );
-
- }else{
- const char *zSep = "";
- int i;
- for(i=0; i<pIter->nTblCol; i++){
- if( pIter->abTblPk[i] ){
- const char *zCol = pIter->azTblCol[i];
- zList = rbuMPrintf(p, "%z%s\"%w\"=?%d", zList, zSep, zCol, i+1);
- zSep = " AND ";
- }
- }
- }
- return zList;
-}
-
-/*
-** The SELECT statement iterating through the keys for the current object
-** (p->objiter.pSelect) currently points to a valid row. However, there
-** is something wrong with the rbu_control value in the rbu_control value
-** stored in the (p->nCol+1)'th column. Set the error code and error message
-** of the RBU handle to something reflecting this.
-*/
-static void rbuBadControlError(sqlite3rbu *p){
- p->rc = SQLITE_ERROR;
- p->zErrmsg = sqlite3_mprintf("invalid rbu_control value");
-}
-
-
-/*
-** Return a nul-terminated string containing the comma separated list of
-** assignments that should be included following the "SET" keyword of
-** an UPDATE statement used to update the table object that the iterator
-** passed as the second argument currently points to if the rbu_control
-** column of the data_xxx table entry is set to zMask.
-**
-** The memory for the returned string is obtained from sqlite3_malloc().
-** It is the responsibility of the caller to eventually free it using
-** sqlite3_free().
-**
-** If an OOM error is encountered when allocating space for the new
-** string, an error code is left in the rbu handle passed as the first
-** argument and NULL is returned. Or, if an error has already occurred
-** when this function is called, NULL is returned immediately, without
-** attempting the allocation or modifying the stored error code.
-*/
-static char *rbuObjIterGetSetlist(
- sqlite3rbu *p,
- RbuObjIter *pIter,
- const char *zMask
-){
- char *zList = 0;
- if( p->rc==SQLITE_OK ){
- int i;
-
- if( (int)strlen(zMask)!=pIter->nTblCol ){
- rbuBadControlError(p);
- }else{
- const char *zSep = "";
- for(i=0; i<pIter->nTblCol; i++){
- char c = zMask[pIter->aiSrcOrder[i]];
- if( c=='x' ){
- zList = rbuMPrintf(p, "%z%s\"%w\"=?%d",
- zList, zSep, pIter->azTblCol[i], i+1
- );
- zSep = ", ";
- }
- else if( c=='d' ){
- zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_delta(\"%w\", ?%d)",
- zList, zSep, pIter->azTblCol[i], pIter->azTblCol[i], i+1
- );
- zSep = ", ";
- }
- else if( c=='f' ){
- zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_fossil_delta(\"%w\", ?%d)",
- zList, zSep, pIter->azTblCol[i], pIter->azTblCol[i], i+1
- );
- zSep = ", ";
- }
- }
- }
- }
- return zList;
-}
-
-/*
-** Return a nul-terminated string consisting of nByte comma separated
-** "?" expressions. For example, if nByte is 3, return a pointer to
-** a buffer containing the string "?,?,?".
-**
-** The memory for the returned string is obtained from sqlite3_malloc().
-** It is the responsibility of the caller to eventually free it using
-** sqlite3_free().
-**
-** If an OOM error is encountered when allocating space for the new
-** string, an error code is left in the rbu handle passed as the first
-** argument and NULL is returned. Or, if an error has already occurred
-** when this function is called, NULL is returned immediately, without
-** attempting the allocation or modifying the stored error code.
-*/
-static char *rbuObjIterGetBindlist(sqlite3rbu *p, int nBind){
- char *zRet = 0;
- int nByte = nBind*2 + 1;
-
- zRet = (char*)rbuMalloc(p, nByte);
- if( zRet ){
- int i;
- for(i=0; i<nBind; i++){
- zRet[i*2] = '?';
- zRet[i*2+1] = (i+1==nBind) ? '\0' : ',';
- }
- }
- return zRet;
-}
-
-/*
-** The iterator currently points to a table (not index) of type
-** RBU_PK_WITHOUT_ROWID. This function creates the PRIMARY KEY
-** declaration for the corresponding imposter table. For example,
-** if the iterator points to a table created as:
-**
-** CREATE TABLE t1(a, b, c, PRIMARY KEY(b, a DESC)) WITHOUT ROWID
-**
-** this function returns:
-**
-** PRIMARY KEY("b", "a" DESC)
-*/
-static char *rbuWithoutRowidPK(sqlite3rbu *p, RbuObjIter *pIter){
- char *z = 0;
- assert( pIter->zIdx==0 );
- if( p->rc==SQLITE_OK ){
- const char *zSep = "PRIMARY KEY(";
- sqlite3_stmt *pXList = 0; /* PRAGMA index_list = (pIter->zTbl) */
- sqlite3_stmt *pXInfo = 0; /* PRAGMA index_xinfo = <pk-index> */
-
- p->rc = prepareFreeAndCollectError(p->dbMain, &pXList, &p->zErrmsg,
- sqlite3_mprintf("PRAGMA main.index_list = %Q", pIter->zTbl)
- );
- while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXList) ){
- const char *zOrig = (const char*)sqlite3_column_text(pXList,3);
- if( zOrig && strcmp(zOrig, "pk")==0 ){
- const char *zIdx = (const char*)sqlite3_column_text(pXList,1);
- if( zIdx ){
- p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg,
- sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx)
- );
- }
- break;
- }
- }
- rbuFinalize(p, pXList);
-
- while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){
- if( sqlite3_column_int(pXInfo, 5) ){
- /* int iCid = sqlite3_column_int(pXInfo, 0); */
- const char *zCol = (const char*)sqlite3_column_text(pXInfo, 2);
- const char *zDesc = sqlite3_column_int(pXInfo, 3) ? " DESC" : "";
- z = rbuMPrintf(p, "%z%s\"%w\"%s", z, zSep, zCol, zDesc);
- zSep = ", ";
- }
- }
- z = rbuMPrintf(p, "%z)", z);
- rbuFinalize(p, pXInfo);
- }
- return z;
-}
-
-/*
-** This function creates the second imposter table used when writing to
-** a table b-tree where the table has an external primary key. If the
-** iterator passed as the second argument does not currently point to
-** a table (not index) with an external primary key, this function is a
-** no-op.
-**
-** Assuming the iterator does point to a table with an external PK, this
-** function creates a WITHOUT ROWID imposter table named "rbu_imposter2"
-** used to access that PK index. For example, if the target table is
-** declared as follows:
-**
-** CREATE TABLE t1(a, b TEXT, c REAL, PRIMARY KEY(b, c));
-**
-** then the imposter table schema is:
-**
-** CREATE TABLE rbu_imposter2(c1 TEXT, c2 REAL, id INTEGER) WITHOUT ROWID;
-**
-*/
-static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){
- if( p->rc==SQLITE_OK && pIter->eType==RBU_PK_EXTERNAL ){
- int tnum = pIter->iPkTnum; /* Root page of PK index */
- sqlite3_stmt *pQuery = 0; /* SELECT name ... WHERE rootpage = $tnum */
- const char *zIdx = 0; /* Name of PK index */
- sqlite3_stmt *pXInfo = 0; /* PRAGMA main.index_xinfo = $zIdx */
- const char *zComma = "";
- char *zCols = 0; /* Used to build up list of table cols */
- char *zPk = 0; /* Used to build up table PK declaration */
-
- /* Figure out the name of the primary key index for the current table.
- ** This is needed for the argument to "PRAGMA index_xinfo". Set
- ** zIdx to point to a nul-terminated string containing this name. */
- p->rc = prepareAndCollectError(p->dbMain, &pQuery, &p->zErrmsg,
- "SELECT name FROM sqlite_master WHERE rootpage = ?"
- );
- if( p->rc==SQLITE_OK ){
- sqlite3_bind_int(pQuery, 1, tnum);
- if( SQLITE_ROW==sqlite3_step(pQuery) ){
- zIdx = (const char*)sqlite3_column_text(pQuery, 0);
- }
- }
- if( zIdx ){
- p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg,
- sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx)
- );
- }
- rbuFinalize(p, pQuery);
-
- while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){
- int bKey = sqlite3_column_int(pXInfo, 5);
- if( bKey ){
- int iCid = sqlite3_column_int(pXInfo, 1);
- int bDesc = sqlite3_column_int(pXInfo, 3);
- const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4);
- zCols = rbuMPrintf(p, "%z%sc%d %s COLLATE %s", zCols, zComma,
- iCid, pIter->azTblType[iCid], zCollate
- );
- zPk = rbuMPrintf(p, "%z%sc%d%s", zPk, zComma, iCid, bDesc?" DESC":"");
- zComma = ", ";
- }
- }
- zCols = rbuMPrintf(p, "%z, id INTEGER", zCols);
- rbuFinalize(p, pXInfo);
-
- sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1, tnum);
- rbuMPrintfExec(p, p->dbMain,
- "CREATE TABLE rbu_imposter2(%z, PRIMARY KEY(%z)) WITHOUT ROWID",
- zCols, zPk
- );
- sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 0);
- }
-}
-
-/*
-** If an error has already occurred when this function is called, it
-** immediately returns zero (without doing any work). Or, if an error
-** occurs during the execution of this function, it sets the error code
-** in the sqlite3rbu object indicated by the first argument and returns
-** zero.
-**
-** The iterator passed as the second argument is guaranteed to point to
-** a table (not an index) when this function is called. This function
-** attempts to create any imposter table required to write to the main
-** table b-tree of the table before returning. Non-zero is returned if
-** an imposter table are created, or zero otherwise.
-**
-** An imposter table is required in all cases except RBU_PK_VTAB. Only
-** virtual tables are written to directly. The imposter table has the
-** same schema as the actual target table (less any UNIQUE constraints).
-** More precisely, the "same schema" means the same columns, types,
-** collation sequences. For tables that do not have an external PRIMARY
-** KEY, it also means the same PRIMARY KEY declaration.
-*/
-static void rbuCreateImposterTable(sqlite3rbu *p, RbuObjIter *pIter){
- if( p->rc==SQLITE_OK && pIter->eType!=RBU_PK_VTAB ){
- int tnum = pIter->iTnum;
- const char *zComma = "";
- char *zSql = 0;
- int iCol;
- sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 1);
-
- for(iCol=0; p->rc==SQLITE_OK && iCol<pIter->nTblCol; iCol++){
- const char *zPk = "";
- const char *zCol = pIter->azTblCol[iCol];
- const char *zColl = 0;
-
- p->rc = sqlite3_table_column_metadata(
- p->dbMain, "main", pIter->zTbl, zCol, 0, &zColl, 0, 0, 0
- );
-
- if( pIter->eType==RBU_PK_IPK && pIter->abTblPk[iCol] ){
- /* If the target table column is an "INTEGER PRIMARY KEY", add
- ** "PRIMARY KEY" to the imposter table column declaration. */
- zPk = "PRIMARY KEY ";
- }
- zSql = rbuMPrintf(p, "%z%s\"%w\" %s %sCOLLATE %s%s",
- zSql, zComma, zCol, pIter->azTblType[iCol], zPk, zColl,
- (pIter->abNotNull[iCol] ? " NOT NULL" : "")
- );
- zComma = ", ";
- }
-
- if( pIter->eType==RBU_PK_WITHOUT_ROWID ){
- char *zPk = rbuWithoutRowidPK(p, pIter);
- if( zPk ){
- zSql = rbuMPrintf(p, "%z, %z", zSql, zPk);
- }
- }
-
- sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1, tnum);
- rbuMPrintfExec(p, p->dbMain, "CREATE TABLE \"rbu_imp_%w\"(%z)%s",
- pIter->zTbl, zSql,
- (pIter->eType==RBU_PK_WITHOUT_ROWID ? " WITHOUT ROWID" : "")
- );
- sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 0);
- }
-}
-
-/*
-** Prepare a statement used to insert rows into the "rbu_tmp_xxx" table.
-** Specifically a statement of the form:
-**
-** INSERT INTO rbu_tmp_xxx VALUES(?, ?, ? ...);
-**
-** The number of bound variables is equal to the number of columns in
-** the target table, plus one (for the rbu_control column), plus one more
-** (for the rbu_rowid column) if the target table is an implicit IPK or
-** virtual table.
-*/
-static void rbuObjIterPrepareTmpInsert(
- sqlite3rbu *p,
- RbuObjIter *pIter,
- const char *zCollist,
- const char *zRbuRowid
-){
- int bRbuRowid = (pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE);
- char *zBind = rbuObjIterGetBindlist(p, pIter->nTblCol + 1 + bRbuRowid);
- if( zBind ){
- assert( pIter->pTmpInsert==0 );
- p->rc = prepareFreeAndCollectError(
- p->dbRbu, &pIter->pTmpInsert, &p->zErrmsg, sqlite3_mprintf(
- "INSERT INTO %s.'rbu_tmp_%q'(rbu_control,%s%s) VALUES(%z)",
- p->zStateDb, pIter->zDataTbl, zCollist, zRbuRowid, zBind
- ));
- }
-}
-
-static void rbuTmpInsertFunc(
- sqlite3_context *pCtx,
- int nVal,
- sqlite3_value **apVal
-){
- sqlite3rbu *p = sqlite3_user_data(pCtx);
- int rc = SQLITE_OK;
- int i;
-
- assert( sqlite3_value_int(apVal[0])!=0
- || p->objiter.eType==RBU_PK_EXTERNAL
- || p->objiter.eType==RBU_PK_NONE
- );
- if( sqlite3_value_int(apVal[0])!=0 ){
- p->nPhaseOneStep += p->objiter.nIndex;
- }
-
- for(i=0; rc==SQLITE_OK && i<nVal; i++){
- rc = sqlite3_bind_value(p->objiter.pTmpInsert, i+1, apVal[i]);
- }
- if( rc==SQLITE_OK ){
- sqlite3_step(p->objiter.pTmpInsert);
- rc = sqlite3_reset(p->objiter.pTmpInsert);
- }
-
- if( rc!=SQLITE_OK ){
- sqlite3_result_error_code(pCtx, rc);
- }
-}
-
-/*
-** Ensure that the SQLite statement handles required to update the
-** target database object currently indicated by the iterator passed
-** as the second argument are available.
-*/
-static int rbuObjIterPrepareAll(
- sqlite3rbu *p,
- RbuObjIter *pIter,
- int nOffset /* Add "LIMIT -1 OFFSET $nOffset" to SELECT */
-){
- assert( pIter->bCleanup==0 );
- if( pIter->pSelect==0 && rbuObjIterCacheTableInfo(p, pIter)==SQLITE_OK ){
- const int tnum = pIter->iTnum;
- char *zCollist = 0; /* List of indexed columns */
- char **pz = &p->zErrmsg;
- const char *zIdx = pIter->zIdx;
- char *zLimit = 0;
-
- if( nOffset ){
- zLimit = sqlite3_mprintf(" LIMIT -1 OFFSET %d", nOffset);
- if( !zLimit ) p->rc = SQLITE_NOMEM;
- }
-
- if( zIdx ){
- const char *zTbl = pIter->zTbl;
- char *zImposterCols = 0; /* Columns for imposter table */
- char *zImposterPK = 0; /* Primary key declaration for imposter */
- char *zWhere = 0; /* WHERE clause on PK columns */
- char *zBind = 0;
- int nBind = 0;
-
- assert( pIter->eType!=RBU_PK_VTAB );
- zCollist = rbuObjIterGetIndexCols(
- p, pIter, &zImposterCols, &zImposterPK, &zWhere, &nBind
- );
- zBind = rbuObjIterGetBindlist(p, nBind);
-
- /* Create the imposter table used to write to this index. */
- sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 1);
- sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1,tnum);
- rbuMPrintfExec(p, p->dbMain,
- "CREATE TABLE \"rbu_imp_%w\"( %s, PRIMARY KEY( %s ) ) WITHOUT ROWID",
- zTbl, zImposterCols, zImposterPK
- );
- sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 0);
-
- /* Create the statement to insert index entries */
- pIter->nCol = nBind;
- if( p->rc==SQLITE_OK ){
- p->rc = prepareFreeAndCollectError(
- p->dbMain, &pIter->pInsert, &p->zErrmsg,
- sqlite3_mprintf("INSERT INTO \"rbu_imp_%w\" VALUES(%s)", zTbl, zBind)
- );
- }
-
- /* And to delete index entries */
- if( rbuIsVacuum(p)==0 && p->rc==SQLITE_OK ){
- p->rc = prepareFreeAndCollectError(
- p->dbMain, &pIter->pDelete, &p->zErrmsg,
- sqlite3_mprintf("DELETE FROM \"rbu_imp_%w\" WHERE %s", zTbl, zWhere)
- );
- }
-
- /* Create the SELECT statement to read keys in sorted order */
- if( p->rc==SQLITE_OK ){
- char *zSql;
- if( rbuIsVacuum(p) ){
- zSql = sqlite3_mprintf(
- "SELECT %s, 0 AS rbu_control FROM '%q' ORDER BY %s%s",
- zCollist,
- pIter->zDataTbl,
- zCollist, zLimit
- );
- }else
-
- if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
- zSql = sqlite3_mprintf(
- "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' ORDER BY %s%s",
- zCollist, p->zStateDb, pIter->zDataTbl,
- zCollist, zLimit
- );
- }else{
- zSql = sqlite3_mprintf(
- "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' "
- "UNION ALL "
- "SELECT %s, rbu_control FROM '%q' "
- "WHERE typeof(rbu_control)='integer' AND rbu_control!=1 "
- "ORDER BY %s%s",
- zCollist, p->zStateDb, pIter->zDataTbl,
- zCollist, pIter->zDataTbl,
- zCollist, zLimit
- );
- }
- p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, zSql);
- }
-
- sqlite3_free(zImposterCols);
- sqlite3_free(zImposterPK);
- sqlite3_free(zWhere);
- sqlite3_free(zBind);
- }else{
- int bRbuRowid = (pIter->eType==RBU_PK_VTAB)
- ||(pIter->eType==RBU_PK_NONE)
- ||(pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p));
- const char *zTbl = pIter->zTbl; /* Table this step applies to */
- const char *zWrite; /* Imposter table name */
-
- char *zBindings = rbuObjIterGetBindlist(p, pIter->nTblCol + bRbuRowid);
- char *zWhere = rbuObjIterGetWhere(p, pIter);
- char *zOldlist = rbuObjIterGetOldlist(p, pIter, "old");
- char *zNewlist = rbuObjIterGetOldlist(p, pIter, "new");
-
- zCollist = rbuObjIterGetCollist(p, pIter);
- pIter->nCol = pIter->nTblCol;
-
- /* Create the imposter table or tables (if required). */
- rbuCreateImposterTable(p, pIter);
- rbuCreateImposterTable2(p, pIter);
- zWrite = (pIter->eType==RBU_PK_VTAB ? "" : "rbu_imp_");
-
- /* Create the INSERT statement to write to the target PK b-tree */
- if( p->rc==SQLITE_OK ){
- p->rc = prepareFreeAndCollectError(p->dbMain, &pIter->pInsert, pz,
- sqlite3_mprintf(
- "INSERT INTO \"%s%w\"(%s%s) VALUES(%s)",
- zWrite, zTbl, zCollist, (bRbuRowid ? ", _rowid_" : ""), zBindings
- )
- );
- }
-
- /* Create the DELETE statement to write to the target PK b-tree.
- ** Because it only performs INSERT operations, this is not required for
- ** an rbu vacuum handle. */
- if( rbuIsVacuum(p)==0 && p->rc==SQLITE_OK ){
- p->rc = prepareFreeAndCollectError(p->dbMain, &pIter->pDelete, pz,
- sqlite3_mprintf(
- "DELETE FROM \"%s%w\" WHERE %s", zWrite, zTbl, zWhere
- )
- );
- }
-
- if( rbuIsVacuum(p)==0 && pIter->abIndexed ){
- const char *zRbuRowid = "";
- if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
- zRbuRowid = ", rbu_rowid";
- }
-
- /* Create the rbu_tmp_xxx table and the triggers to populate it. */
- rbuMPrintfExec(p, p->dbRbu,
- "CREATE TABLE IF NOT EXISTS %s.'rbu_tmp_%q' AS "
- "SELECT *%s FROM '%q' WHERE 0;"
- , p->zStateDb, pIter->zDataTbl
- , (pIter->eType==RBU_PK_EXTERNAL ? ", 0 AS rbu_rowid" : "")
- , pIter->zDataTbl
- );
-
- rbuMPrintfExec(p, p->dbMain,
- "CREATE TEMP TRIGGER rbu_delete_tr BEFORE DELETE ON \"%s%w\" "
- "BEGIN "
- " SELECT rbu_tmp_insert(3, %s);"
- "END;"
-
- "CREATE TEMP TRIGGER rbu_update1_tr BEFORE UPDATE ON \"%s%w\" "
- "BEGIN "
- " SELECT rbu_tmp_insert(3, %s);"
- "END;"
-
- "CREATE TEMP TRIGGER rbu_update2_tr AFTER UPDATE ON \"%s%w\" "
- "BEGIN "
- " SELECT rbu_tmp_insert(4, %s);"
- "END;",
- zWrite, zTbl, zOldlist,
- zWrite, zTbl, zOldlist,
- zWrite, zTbl, zNewlist
- );
-
- if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
- rbuMPrintfExec(p, p->dbMain,
- "CREATE TEMP TRIGGER rbu_insert_tr AFTER INSERT ON \"%s%w\" "
- "BEGIN "
- " SELECT rbu_tmp_insert(0, %s);"
- "END;",
- zWrite, zTbl, zNewlist
- );
- }
-
- rbuObjIterPrepareTmpInsert(p, pIter, zCollist, zRbuRowid);
- }
-
- /* Create the SELECT statement to read keys from data_xxx */
- if( p->rc==SQLITE_OK ){
- const char *zRbuRowid = "";
- if( bRbuRowid ){
- zRbuRowid = rbuIsVacuum(p) ? ",_rowid_ " : ",rbu_rowid";
- }
- p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz,
- sqlite3_mprintf(
- "SELECT %s,%s rbu_control%s FROM '%q'%s",
- zCollist,
- (rbuIsVacuum(p) ? "0 AS " : ""),
- zRbuRowid,
- pIter->zDataTbl, zLimit
- )
- );
- }
-
- sqlite3_free(zWhere);
- sqlite3_free(zOldlist);
- sqlite3_free(zNewlist);
- sqlite3_free(zBindings);
- }
- sqlite3_free(zCollist);
- sqlite3_free(zLimit);
- }
-
- return p->rc;
-}
-
-/*
-** Set output variable *ppStmt to point to an UPDATE statement that may
-** be used to update the imposter table for the main table b-tree of the
-** table object that pIter currently points to, assuming that the
-** rbu_control column of the data_xyz table contains zMask.
-**
-** If the zMask string does not specify any columns to update, then this
-** is not an error. Output variable *ppStmt is set to NULL in this case.
-*/
-static int rbuGetUpdateStmt(
- sqlite3rbu *p, /* RBU handle */
- RbuObjIter *pIter, /* Object iterator */
- const char *zMask, /* rbu_control value ('x.x.') */
- sqlite3_stmt **ppStmt /* OUT: UPDATE statement handle */
-){
- RbuUpdateStmt **pp;
- RbuUpdateStmt *pUp = 0;
- int nUp = 0;
-
- /* In case an error occurs */
- *ppStmt = 0;
-
- /* Search for an existing statement. If one is found, shift it to the front
- ** of the LRU queue and return immediately. Otherwise, leave nUp pointing
- ** to the number of statements currently in the cache and pUp to the
- ** last object in the list. */
- for(pp=&pIter->pRbuUpdate; *pp; pp=&((*pp)->pNext)){
- pUp = *pp;
- if( strcmp(pUp->zMask, zMask)==0 ){
- *pp = pUp->pNext;
- pUp->pNext = pIter->pRbuUpdate;
- pIter->pRbuUpdate = pUp;
- *ppStmt = pUp->pUpdate;
- return SQLITE_OK;
- }
- nUp++;
- }
- assert( pUp==0 || pUp->pNext==0 );
-
- if( nUp>=SQLITE_RBU_UPDATE_CACHESIZE ){
- for(pp=&pIter->pRbuUpdate; *pp!=pUp; pp=&((*pp)->pNext));
- *pp = 0;
- sqlite3_finalize(pUp->pUpdate);
- pUp->pUpdate = 0;
- }else{
- pUp = (RbuUpdateStmt*)rbuMalloc(p, sizeof(RbuUpdateStmt)+pIter->nTblCol+1);
- }
-
- if( pUp ){
- char *zWhere = rbuObjIterGetWhere(p, pIter);
- char *zSet = rbuObjIterGetSetlist(p, pIter, zMask);
- char *zUpdate = 0;
-
- pUp->zMask = (char*)&pUp[1];
- memcpy(pUp->zMask, zMask, pIter->nTblCol);
- pUp->pNext = pIter->pRbuUpdate;
- pIter->pRbuUpdate = pUp;
-
- if( zSet ){
- const char *zPrefix = "";
-
- if( pIter->eType!=RBU_PK_VTAB ) zPrefix = "rbu_imp_";
- zUpdate = sqlite3_mprintf("UPDATE \"%s%w\" SET %s WHERE %s",
- zPrefix, pIter->zTbl, zSet, zWhere
- );
- p->rc = prepareFreeAndCollectError(
- p->dbMain, &pUp->pUpdate, &p->zErrmsg, zUpdate
- );
- *ppStmt = pUp->pUpdate;
- }
- sqlite3_free(zWhere);
- sqlite3_free(zSet);
- }
-
- return p->rc;
-}
-
-static sqlite3 *rbuOpenDbhandle(
- sqlite3rbu *p,
- const char *zName,
- int bUseVfs
-){
- sqlite3 *db = 0;
- if( p->rc==SQLITE_OK ){
- const int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_URI;
- p->rc = sqlite3_open_v2(zName, &db, flags, bUseVfs ? p->zVfsName : 0);
- if( p->rc ){
- p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
- sqlite3_close(db);
- db = 0;
- }
- }
- return db;
-}
-
-/*
-** Free an RbuState object allocated by rbuLoadState().
-*/
-static void rbuFreeState(RbuState *p){
- if( p ){
- sqlite3_free(p->zTbl);
- sqlite3_free(p->zIdx);
- sqlite3_free(p);
- }
-}
-
-/*
-** Allocate an RbuState object and load the contents of the rbu_state
-** table into it. Return a pointer to the new object. It is the
-** responsibility of the caller to eventually free the object using
-** sqlite3_free().
-**
-** If an error occurs, leave an error code and message in the rbu handle
-** and return NULL.
-*/
-static RbuState *rbuLoadState(sqlite3rbu *p){
- RbuState *pRet = 0;
- sqlite3_stmt *pStmt = 0;
- int rc;
- int rc2;
-
- pRet = (RbuState*)rbuMalloc(p, sizeof(RbuState));
- if( pRet==0 ) return 0;
-
- rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
- sqlite3_mprintf("SELECT k, v FROM %s.rbu_state", p->zStateDb)
- );
- while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
- switch( sqlite3_column_int(pStmt, 0) ){
- case RBU_STATE_STAGE:
- pRet->eStage = sqlite3_column_int(pStmt, 1);
- if( pRet->eStage!=RBU_STAGE_OAL
- && pRet->eStage!=RBU_STAGE_MOVE
- && pRet->eStage!=RBU_STAGE_CKPT
- ){
- p->rc = SQLITE_CORRUPT;
- }
- break;
-
- case RBU_STATE_TBL:
- pRet->zTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
- break;
-
- case RBU_STATE_IDX:
- pRet->zIdx = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
- break;
-
- case RBU_STATE_ROW:
- pRet->nRow = sqlite3_column_int(pStmt, 1);
- break;
-
- case RBU_STATE_PROGRESS:
- pRet->nProgress = sqlite3_column_int64(pStmt, 1);
- break;
-
- case RBU_STATE_CKPT:
- pRet->iWalCksum = sqlite3_column_int64(pStmt, 1);
- break;
-
- case RBU_STATE_COOKIE:
- pRet->iCookie = (u32)sqlite3_column_int64(pStmt, 1);
- break;
-
- case RBU_STATE_OALSZ:
- pRet->iOalSz = (u32)sqlite3_column_int64(pStmt, 1);
- break;
-
- case RBU_STATE_PHASEONESTEP:
- pRet->nPhaseOneStep = sqlite3_column_int64(pStmt, 1);
- break;
-
- default:
- rc = SQLITE_CORRUPT;
- break;
- }
- }
- rc2 = sqlite3_finalize(pStmt);
- if( rc==SQLITE_OK ) rc = rc2;
-
- p->rc = rc;
- return pRet;
-}
-
-
-/*
-** Open the database handle and attach the RBU database as "rbu". If an
-** error occurs, leave an error code and message in the RBU handle.
-*/
-static void rbuOpenDatabase(sqlite3rbu *p){
- assert( p->rc==SQLITE_OK );
- assert( p->dbMain==0 && p->dbRbu==0 );
- assert( rbuIsVacuum(p) || p->zTarget!=0 );
-
- /* Open the RBU database */
- p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1);
-
- if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
- sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p);
- }
-
- /* If using separate RBU and state databases, attach the state database to
- ** the RBU db handle now. */
- if( p->zState ){
- rbuMPrintfExec(p, p->dbRbu, "ATTACH %Q AS stat", p->zState);
- memcpy(p->zStateDb, "stat", 4);
- }else{
- memcpy(p->zStateDb, "main", 4);
- }
-
-#if 0
- if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
- p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, 0);
- }
-#endif
-
- /* If it has not already been created, create the rbu_state table */
- rbuMPrintfExec(p, p->dbRbu, RBU_CREATE_STATE, p->zStateDb);
-
-#if 0
- if( rbuIsVacuum(p) ){
- if( p->rc==SQLITE_OK ){
- int rc2;
- int bOk = 0;
- sqlite3_stmt *pCnt = 0;
- p->rc = prepareAndCollectError(p->dbRbu, &pCnt, &p->zErrmsg,
- "SELECT count(*) FROM stat.sqlite_master"
- );
- if( p->rc==SQLITE_OK
- && sqlite3_step(pCnt)==SQLITE_ROW
- && 1==sqlite3_column_int(pCnt, 0)
- ){
- bOk = 1;
- }
- rc2 = sqlite3_finalize(pCnt);
- if( p->rc==SQLITE_OK ) p->rc = rc2;
-
- if( p->rc==SQLITE_OK && bOk==0 ){
- p->rc = SQLITE_ERROR;
- p->zErrmsg = sqlite3_mprintf("invalid state database");
- }
-
- if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0);
- }
- }
- }
-#endif
-
- if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
- int bOpen = 0;
- int rc;
- p->nRbu = 0;
- p->pRbuFd = 0;
- rc = sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p);
- if( rc!=SQLITE_NOTFOUND ) p->rc = rc;
- if( p->eStage>=RBU_STAGE_MOVE ){
- bOpen = 1;
- }else{
- RbuState *pState = rbuLoadState(p);
- if( pState ){
- bOpen = (pState->eStage>RBU_STAGE_MOVE);
- rbuFreeState(pState);
- }
- }
- if( bOpen ) p->dbMain = rbuOpenDbhandle(p, p->zRbu, p->nRbu<=1);
- }
-
- p->eStage = 0;
- if( p->rc==SQLITE_OK && p->dbMain==0 ){
- if( !rbuIsVacuum(p) ){
- p->dbMain = rbuOpenDbhandle(p, p->zTarget, 1);
- }else if( p->pRbuFd->pWalFd ){
- p->rc = SQLITE_ERROR;
- p->zErrmsg = sqlite3_mprintf("cannot vacuum wal mode database");
- }else{
- char *zTarget;
- char *zExtra = 0;
- if( strlen(p->zRbu)>=5 && 0==memcmp("file:", p->zRbu, 5) ){
- zExtra = &p->zRbu[5];
- while( *zExtra ){
- if( *zExtra++=='?' ) break;
- }
- if( *zExtra=='\0' ) zExtra = 0;
- }
-
- zTarget = sqlite3_mprintf("file:%s-vacuum?rbu_memory=1%s%s",
- sqlite3_db_filename(p->dbRbu, "main"),
- (zExtra==0 ? "" : "&"), (zExtra==0 ? "" : zExtra)
- );
-
- if( zTarget==0 ){
- p->rc = SQLITE_NOMEM;
- return;
- }
- p->dbMain = rbuOpenDbhandle(p, zTarget, p->nRbu<=1);
- sqlite3_free(zTarget);
- }
- }
-
- if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_create_function(p->dbMain,
- "rbu_tmp_insert", -1, SQLITE_UTF8, (void*)p, rbuTmpInsertFunc, 0, 0
- );
- }
-
- if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_create_function(p->dbMain,
- "rbu_fossil_delta", 2, SQLITE_UTF8, 0, rbuFossilDeltaFunc, 0, 0
- );
- }
-
- if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_create_function(p->dbRbu,
- "rbu_target_name", -1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0
- );
- }
-
- if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p);
- }
- rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlite_master");
-
- /* Mark the database file just opened as an RBU target database. If
- ** this call returns SQLITE_NOTFOUND, then the RBU vfs is not in use.
- ** This is an error. */
- if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p);
- }
-
- if( p->rc==SQLITE_NOTFOUND ){
- p->rc = SQLITE_ERROR;
- p->zErrmsg = sqlite3_mprintf("rbu vfs not found");
- }
-}
-
-/*
-** This routine is a copy of the sqlite3FileSuffix3() routine from the core.
-** It is a no-op unless SQLITE_ENABLE_8_3_NAMES is defined.
-**
-** If SQLITE_ENABLE_8_3_NAMES is set at compile-time and if the database
-** filename in zBaseFilename is a URI with the "8_3_names=1" parameter and
-** if filename in z[] has a suffix (a.k.a. "extension") that is longer than
-** three characters, then shorten the suffix on z[] to be the last three
-** characters of the original suffix.
-**
-** If SQLITE_ENABLE_8_3_NAMES is set to 2 at compile-time, then always
-** do the suffix shortening regardless of URI parameter.
-**
-** Examples:
-**
-** test.db-journal => test.nal
-** test.db-wal => test.wal
-** test.db-shm => test.shm
-** test.db-mj7f3319fa => test.9fa
-*/
-static void rbuFileSuffix3(const char *zBase, char *z){
-#ifdef SQLITE_ENABLE_8_3_NAMES
-#if SQLITE_ENABLE_8_3_NAMES<2
- if( sqlite3_uri_boolean(zBase, "8_3_names", 0) )
-#endif
- {
- int i, sz;
- sz = sqlite3Strlen30(z);
- for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
- if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4);
- }
-#endif
-}
-
-/*
-** Return the current wal-index header checksum for the target database
-** as a 64-bit integer.
-**
-** The checksum is store in the first page of xShmMap memory as an 8-byte
-** blob starting at byte offset 40.
-*/
-static i64 rbuShmChecksum(sqlite3rbu *p){
- i64 iRet = 0;
- if( p->rc==SQLITE_OK ){
- sqlite3_file *pDb = p->pTargetFd->pReal;
- u32 volatile *ptr;
- p->rc = pDb->pMethods->xShmMap(pDb, 0, 32*1024, 0, (void volatile**)&ptr);
- if( p->rc==SQLITE_OK ){
- iRet = ((i64)ptr[10] << 32) + ptr[11];
- }
- }
- return iRet;
-}
-
-/*
-** This function is called as part of initializing or reinitializing an
-** incremental checkpoint.
-**
-** It populates the sqlite3rbu.aFrame[] array with the set of
-** (wal frame -> db page) copy operations required to checkpoint the
-** current wal file, and obtains the set of shm locks required to safely
-** perform the copy operations directly on the file-system.
-**
-** If argument pState is not NULL, then the incremental checkpoint is
-** being resumed. In this case, if the checksum of the wal-index-header
-** following recovery is not the same as the checksum saved in the RbuState
-** object, then the rbu handle is set to DONE state. This occurs if some
-** other client appends a transaction to the wal file in the middle of
-** an incremental checkpoint.
-*/
-static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
-
- /* If pState is NULL, then the wal file may not have been opened and
- ** recovered. Running a read-statement here to ensure that doing so
- ** does not interfere with the "capture" process below. */
- if( pState==0 ){
- p->eStage = 0;
- if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlite_master", 0, 0, 0);
- }
- }
-
- /* Assuming no error has occurred, run a "restart" checkpoint with the
- ** sqlite3rbu.eStage variable set to CAPTURE. This turns on the following
- ** special behaviour in the rbu VFS:
- **
- ** * If the exclusive shm WRITER or READ0 lock cannot be obtained,
- ** the checkpoint fails with SQLITE_BUSY (normally SQLite would
- ** proceed with running a passive checkpoint instead of failing).
- **
- ** * Attempts to read from the *-wal file or write to the database file
- ** do not perform any IO. Instead, the frame/page combinations that
- ** would be read/written are recorded in the sqlite3rbu.aFrame[]
- ** array.
- **
- ** * Calls to xShmLock(UNLOCK) to release the exclusive shm WRITER,
- ** READ0 and CHECKPOINT locks taken as part of the checkpoint are
- ** no-ops. These locks will not be released until the connection
- ** is closed.
- **
- ** * Attempting to xSync() the database file causes an SQLITE_INTERNAL
- ** error.
- **
- ** As a result, unless an error (i.e. OOM or SQLITE_BUSY) occurs, the
- ** checkpoint below fails with SQLITE_INTERNAL, and leaves the aFrame[]
- ** array populated with a set of (frame -> page) mappings. Because the
- ** WRITER, CHECKPOINT and READ0 locks are still held, it is safe to copy
- ** data from the wal file into the database file according to the
- ** contents of aFrame[].
- */
- if( p->rc==SQLITE_OK ){
- int rc2;
- p->eStage = RBU_STAGE_CAPTURE;
- rc2 = sqlite3_exec(p->dbMain, "PRAGMA main.wal_checkpoint=restart", 0, 0,0);
- if( rc2!=SQLITE_INTERNAL ) p->rc = rc2;
- }
-
- if( p->rc==SQLITE_OK ){
- p->eStage = RBU_STAGE_CKPT;
- p->nStep = (pState ? pState->nRow : 0);
- p->aBuf = rbuMalloc(p, p->pgsz);
- p->iWalCksum = rbuShmChecksum(p);
- }
-
- if( p->rc==SQLITE_OK && pState && pState->iWalCksum!=p->iWalCksum ){
- p->rc = SQLITE_DONE;
- p->eStage = RBU_STAGE_DONE;
- }
-}
-
-/*
-** Called when iAmt bytes are read from offset iOff of the wal file while
-** the rbu object is in capture mode. Record the frame number of the frame
-** being read in the aFrame[] array.
-*/
-static int rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){
- const u32 mReq = (1<<WAL_LOCK_WRITE)|(1<<WAL_LOCK_CKPT)|(1<<WAL_LOCK_READ0);
- u32 iFrame;
-
- if( pRbu->mLock!=mReq ){
- pRbu->rc = SQLITE_BUSY;
- return SQLITE_INTERNAL;
- }
-
- pRbu->pgsz = iAmt;
- if( pRbu->nFrame==pRbu->nFrameAlloc ){
- int nNew = (pRbu->nFrameAlloc ? pRbu->nFrameAlloc : 64) * 2;
- RbuFrame *aNew;
- aNew = (RbuFrame*)sqlite3_realloc64(pRbu->aFrame, nNew * sizeof(RbuFrame));
- if( aNew==0 ) return SQLITE_NOMEM;
- pRbu->aFrame = aNew;
- pRbu->nFrameAlloc = nNew;
- }
-
- iFrame = (u32)((iOff-32) / (i64)(iAmt+24)) + 1;
- if( pRbu->iMaxFrame<iFrame ) pRbu->iMaxFrame = iFrame;
- pRbu->aFrame[pRbu->nFrame].iWalFrame = iFrame;
- pRbu->aFrame[pRbu->nFrame].iDbPage = 0;
- pRbu->nFrame++;
- return SQLITE_OK;
-}
-
-/*
-** Called when a page of data is written to offset iOff of the database
-** file while the rbu handle is in capture mode. Record the page number
-** of the page being written in the aFrame[] array.
-*/
-static int rbuCaptureDbWrite(sqlite3rbu *pRbu, i64 iOff){
- pRbu->aFrame[pRbu->nFrame-1].iDbPage = (u32)(iOff / pRbu->pgsz) + 1;
- return SQLITE_OK;
-}
-
-/*
-** This is called as part of an incremental checkpoint operation. Copy
-** a single frame of data from the wal file into the database file, as
-** indicated by the RbuFrame object.
-*/
-static void rbuCheckpointFrame(sqlite3rbu *p, RbuFrame *pFrame){
- sqlite3_file *pWal = p->pTargetFd->pWalFd->pReal;
- sqlite3_file *pDb = p->pTargetFd->pReal;
- i64 iOff;
-
- assert( p->rc==SQLITE_OK );
- iOff = (i64)(pFrame->iWalFrame-1) * (p->pgsz + 24) + 32 + 24;
- p->rc = pWal->pMethods->xRead(pWal, p->aBuf, p->pgsz, iOff);
- if( p->rc ) return;
-
- iOff = (i64)(pFrame->iDbPage-1) * p->pgsz;
- p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff);
-}
-
-
-/*
-** Take an EXCLUSIVE lock on the database file.
-*/
-static void rbuLockDatabase(sqlite3rbu *p){
- sqlite3_file *pReal = p->pTargetFd->pReal;
- assert( p->rc==SQLITE_OK );
- p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_SHARED);
- if( p->rc==SQLITE_OK ){
- p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_EXCLUSIVE);
- }
-}
-
-#if defined(_WIN32_WCE)
-static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){
- int nChar;
- LPWSTR zWideFilename;
-
- nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
- if( nChar==0 ){
- return 0;
- }
- zWideFilename = sqlite3_malloc64( nChar*sizeof(zWideFilename[0]) );
- if( zWideFilename==0 ){
- return 0;
- }
- memset(zWideFilename, 0, nChar*sizeof(zWideFilename[0]));
- nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename,
- nChar);
- if( nChar==0 ){
- sqlite3_free(zWideFilename);
- zWideFilename = 0;
- }
- return zWideFilename;
-}
-#endif
-
-/*
-** The RBU handle is currently in RBU_STAGE_OAL state, with a SHARED lock
-** on the database file. This proc moves the *-oal file to the *-wal path,
-** then reopens the database file (this time in vanilla, non-oal, WAL mode).
-** If an error occurs, leave an error code and error message in the rbu
-** handle.
-*/
-static void rbuMoveOalFile(sqlite3rbu *p){
- const char *zBase = sqlite3_db_filename(p->dbMain, "main");
- const char *zMove = zBase;
- char *zOal;
- char *zWal;
-
- if( rbuIsVacuum(p) ){
- zMove = sqlite3_db_filename(p->dbRbu, "main");
- }
- zOal = sqlite3_mprintf("%s-oal", zMove);
- zWal = sqlite3_mprintf("%s-wal", zMove);
-
- assert( p->eStage==RBU_STAGE_MOVE );
- assert( p->rc==SQLITE_OK && p->zErrmsg==0 );
- if( zWal==0 || zOal==0 ){
- p->rc = SQLITE_NOMEM;
- }else{
- /* Move the *-oal file to *-wal. At this point connection p->db is
- ** holding a SHARED lock on the target database file (because it is
- ** in WAL mode). So no other connection may be writing the db.
- **
- ** In order to ensure that there are no database readers, an EXCLUSIVE
- ** lock is obtained here before the *-oal is moved to *-wal.
- */
- rbuLockDatabase(p);
- if( p->rc==SQLITE_OK ){
- rbuFileSuffix3(zBase, zWal);
- rbuFileSuffix3(zBase, zOal);
-
- /* Re-open the databases. */
- rbuObjIterFinalize(&p->objiter);
- sqlite3_close(p->dbRbu);
- sqlite3_close(p->dbMain);
- p->dbMain = 0;
- p->dbRbu = 0;
-
-#if defined(_WIN32_WCE)
- {
- LPWSTR zWideOal;
- LPWSTR zWideWal;
-
- zWideOal = rbuWinUtf8ToUnicode(zOal);
- if( zWideOal ){
- zWideWal = rbuWinUtf8ToUnicode(zWal);
- if( zWideWal ){
- if( MoveFileW(zWideOal, zWideWal) ){
- p->rc = SQLITE_OK;
- }else{
- p->rc = SQLITE_IOERR;
- }
- sqlite3_free(zWideWal);
- }else{
- p->rc = SQLITE_IOERR_NOMEM;
- }
- sqlite3_free(zWideOal);
- }else{
- p->rc = SQLITE_IOERR_NOMEM;
- }
- }
-#else
- p->rc = rename(zOal, zWal) ? SQLITE_IOERR : SQLITE_OK;
-#endif
-
- if( p->rc==SQLITE_OK ){
- rbuOpenDatabase(p);
- rbuSetupCheckpoint(p, 0);
- }
- }
- }
-
- sqlite3_free(zWal);
- sqlite3_free(zOal);
-}
-
-/*
-** The SELECT statement iterating through the keys for the current object
-** (p->objiter.pSelect) currently points to a valid row. This function
-** determines the type of operation requested by this row and returns
-** one of the following values to indicate the result:
-**
-** * RBU_INSERT
-** * RBU_DELETE
-** * RBU_IDX_DELETE
-** * RBU_UPDATE
-**
-** If RBU_UPDATE is returned, then output variable *pzMask is set to
-** point to the text value indicating the columns to update.
-**
-** If the rbu_control field contains an invalid value, an error code and
-** message are left in the RBU handle and zero returned.
-*/
-static int rbuStepType(sqlite3rbu *p, const char **pzMask){
- int iCol = p->objiter.nCol; /* Index of rbu_control column */
- int res = 0; /* Return value */
-
- switch( sqlite3_column_type(p->objiter.pSelect, iCol) ){
- case SQLITE_INTEGER: {
- int iVal = sqlite3_column_int(p->objiter.pSelect, iCol);
- switch( iVal ){
- case 0: res = RBU_INSERT; break;
- case 1: res = RBU_DELETE; break;
- case 2: res = RBU_REPLACE; break;
- case 3: res = RBU_IDX_DELETE; break;
- case 4: res = RBU_IDX_INSERT; break;
- }
- break;
- }
-
- case SQLITE_TEXT: {
- const unsigned char *z = sqlite3_column_text(p->objiter.pSelect, iCol);
- if( z==0 ){
- p->rc = SQLITE_NOMEM;
- }else{
- *pzMask = (const char*)z;
- }
- res = RBU_UPDATE;
-
- break;
- }
-
- default:
- break;
- }
-
- if( res==0 ){
- rbuBadControlError(p);
- }
- return res;
-}
-
-#ifdef SQLITE_DEBUG
-/*
-** Assert that column iCol of statement pStmt is named zName.
-*/
-static void assertColumnName(sqlite3_stmt *pStmt, int iCol, const char *zName){
- const char *zCol = sqlite3_column_name(pStmt, iCol);
- assert( 0==sqlite3_stricmp(zName, zCol) );
-}
-#else
-# define assertColumnName(x,y,z)
-#endif
-
-/*
-** Argument eType must be one of RBU_INSERT, RBU_DELETE, RBU_IDX_INSERT or
-** RBU_IDX_DELETE. This function performs the work of a single
-** sqlite3rbu_step() call for the type of operation specified by eType.
-*/
-static void rbuStepOneOp(sqlite3rbu *p, int eType){
- RbuObjIter *pIter = &p->objiter;
- sqlite3_value *pVal;
- sqlite3_stmt *pWriter;
- int i;
-
- assert( p->rc==SQLITE_OK );
- assert( eType!=RBU_DELETE || pIter->zIdx==0 );
- assert( eType==RBU_DELETE || eType==RBU_IDX_DELETE
- || eType==RBU_INSERT || eType==RBU_IDX_INSERT
- );
-
- /* If this is a delete, decrement nPhaseOneStep by nIndex. If the DELETE
- ** statement below does actually delete a row, nPhaseOneStep will be
- ** incremented by the same amount when SQL function rbu_tmp_insert()
- ** is invoked by the trigger. */
- if( eType==RBU_DELETE ){
- p->nPhaseOneStep -= p->objiter.nIndex;
- }
-
- if( eType==RBU_IDX_DELETE || eType==RBU_DELETE ){
- pWriter = pIter->pDelete;
- }else{
- pWriter = pIter->pInsert;
- }
-
- for(i=0; i<pIter->nCol; i++){
- /* If this is an INSERT into a table b-tree and the table has an
- ** explicit INTEGER PRIMARY KEY, check that this is not an attempt
- ** to write a NULL into the IPK column. That is not permitted. */
- if( eType==RBU_INSERT
- && pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i]
- && sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL
- ){
- p->rc = SQLITE_MISMATCH;
- p->zErrmsg = sqlite3_mprintf("datatype mismatch");
- return;
- }
-
- if( eType==RBU_DELETE && pIter->abTblPk[i]==0 ){
- continue;
- }
-
- pVal = sqlite3_column_value(pIter->pSelect, i);
- p->rc = sqlite3_bind_value(pWriter, i+1, pVal);
- if( p->rc ) return;
- }
- if( pIter->zIdx==0 ){
- if( pIter->eType==RBU_PK_VTAB
- || pIter->eType==RBU_PK_NONE
- || (pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p))
- ){
- /* For a virtual table, or a table with no primary key, the
- ** SELECT statement is:
- **
- ** SELECT <cols>, rbu_control, rbu_rowid FROM ....
- **
- ** Hence column_value(pIter->nCol+1).
- */
- assertColumnName(pIter->pSelect, pIter->nCol+1,
- rbuIsVacuum(p) ? "rowid" : "rbu_rowid"
- );
- pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
- p->rc = sqlite3_bind_value(pWriter, pIter->nCol+1, pVal);
- }
- }
- if( p->rc==SQLITE_OK ){
- sqlite3_step(pWriter);
- p->rc = resetAndCollectError(pWriter, &p->zErrmsg);
- }
-}
-
-/*
-** This function does the work for an sqlite3rbu_step() call.
-**
-** The object-iterator (p->objiter) currently points to a valid object,
-** and the input cursor (p->objiter.pSelect) currently points to a valid
-** input row. Perform whatever processing is required and return.
-**
-** If no error occurs, SQLITE_OK is returned. Otherwise, an error code
-** and message is left in the RBU handle and a copy of the error code
-** returned.
-*/
-static int rbuStep(sqlite3rbu *p){
- RbuObjIter *pIter = &p->objiter;
- const char *zMask = 0;
- int eType = rbuStepType(p, &zMask);
-
- if( eType ){
- assert( eType==RBU_INSERT || eType==RBU_DELETE
- || eType==RBU_REPLACE || eType==RBU_IDX_DELETE
- || eType==RBU_IDX_INSERT || eType==RBU_UPDATE
- );
- assert( eType!=RBU_UPDATE || pIter->zIdx==0 );
-
- if( pIter->zIdx==0 && (eType==RBU_IDX_DELETE || eType==RBU_IDX_INSERT) ){
- rbuBadControlError(p);
- }
- else if( eType==RBU_REPLACE ){
- if( pIter->zIdx==0 ){
- p->nPhaseOneStep += p->objiter.nIndex;
- rbuStepOneOp(p, RBU_DELETE);
- }
- if( p->rc==SQLITE_OK ) rbuStepOneOp(p, RBU_INSERT);
- }
- else if( eType!=RBU_UPDATE ){
- rbuStepOneOp(p, eType);
- }
- else{
- sqlite3_value *pVal;
- sqlite3_stmt *pUpdate = 0;
- assert( eType==RBU_UPDATE );
- p->nPhaseOneStep -= p->objiter.nIndex;
- rbuGetUpdateStmt(p, pIter, zMask, &pUpdate);
- if( pUpdate ){
- int i;
- for(i=0; p->rc==SQLITE_OK && i<pIter->nCol; i++){
- char c = zMask[pIter->aiSrcOrder[i]];
- pVal = sqlite3_column_value(pIter->pSelect, i);
- if( pIter->abTblPk[i] || c!='.' ){
- p->rc = sqlite3_bind_value(pUpdate, i+1, pVal);
- }
- }
- if( p->rc==SQLITE_OK
- && (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE)
- ){
- /* Bind the rbu_rowid value to column _rowid_ */
- assertColumnName(pIter->pSelect, pIter->nCol+1, "rbu_rowid");
- pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
- p->rc = sqlite3_bind_value(pUpdate, pIter->nCol+1, pVal);
- }
- if( p->rc==SQLITE_OK ){
- sqlite3_step(pUpdate);
- p->rc = resetAndCollectError(pUpdate, &p->zErrmsg);
- }
- }
- }
- }
- return p->rc;
-}
-
-/*
-** Increment the schema cookie of the main database opened by p->dbMain.
-**
-** Or, if this is an RBU vacuum, set the schema cookie of the main db
-** opened by p->dbMain to one more than the schema cookie of the main
-** db opened by p->dbRbu.
-*/
-static void rbuIncrSchemaCookie(sqlite3rbu *p){
- if( p->rc==SQLITE_OK ){
- sqlite3 *dbread = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain);
- int iCookie = 1000000;
- sqlite3_stmt *pStmt;
-
- p->rc = prepareAndCollectError(dbread, &pStmt, &p->zErrmsg,
- "PRAGMA schema_version"
- );
- if( p->rc==SQLITE_OK ){
- /* Coverage: it may be that this sqlite3_step() cannot fail. There
- ** is already a transaction open, so the prepared statement cannot
- ** throw an SQLITE_SCHEMA exception. The only database page the
- ** statement reads is page 1, which is guaranteed to be in the cache.
- ** And no memory allocations are required. */
- if( SQLITE_ROW==sqlite3_step(pStmt) ){
- iCookie = sqlite3_column_int(pStmt, 0);
- }
- rbuFinalize(p, pStmt);
- }
- if( p->rc==SQLITE_OK ){
- rbuMPrintfExec(p, p->dbMain, "PRAGMA schema_version = %d", iCookie+1);
- }
- }
-}
-
-/*
-** Update the contents of the rbu_state table within the rbu database. The
-** value stored in the RBU_STATE_STAGE column is eStage. All other values
-** are determined by inspecting the rbu handle passed as the first argument.
-*/
-static void rbuSaveState(sqlite3rbu *p, int eStage){
- if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){
- sqlite3_stmt *pInsert = 0;
- rbu_file *pFd = (rbuIsVacuum(p) ? p->pRbuFd : p->pTargetFd);
- int rc;
-
- assert( p->zErrmsg==0 );
- rc = prepareFreeAndCollectError(p->dbRbu, &pInsert, &p->zErrmsg,
- sqlite3_mprintf(
- "INSERT OR REPLACE INTO %s.rbu_state(k, v) VALUES "
- "(%d, %d), "
- "(%d, %Q), "
- "(%d, %Q), "
- "(%d, %d), "
- "(%d, %d), "
- "(%d, %lld), "
- "(%d, %lld), "
- "(%d, %lld), "
- "(%d, %lld) ",
- p->zStateDb,
- RBU_STATE_STAGE, eStage,
- RBU_STATE_TBL, p->objiter.zTbl,
- RBU_STATE_IDX, p->objiter.zIdx,
- RBU_STATE_ROW, p->nStep,
- RBU_STATE_PROGRESS, p->nProgress,
- RBU_STATE_CKPT, p->iWalCksum,
- RBU_STATE_COOKIE, (i64)pFd->iCookie,
- RBU_STATE_OALSZ, p->iOalSz,
- RBU_STATE_PHASEONESTEP, p->nPhaseOneStep
- )
- );
- assert( pInsert==0 || rc==SQLITE_OK );
-
- if( rc==SQLITE_OK ){
- sqlite3_step(pInsert);
- rc = sqlite3_finalize(pInsert);
- }
- if( rc!=SQLITE_OK ) p->rc = rc;
- }
-}
-
-
-/*
-** The second argument passed to this function is the name of a PRAGMA
-** setting - "page_size", "auto_vacuum", "user_version" or "application_id".
-** This function executes the following on sqlite3rbu.dbRbu:
-**
-** "PRAGMA main.$zPragma"
-**
-** where $zPragma is the string passed as the second argument, then
-** on sqlite3rbu.dbMain:
-**
-** "PRAGMA main.$zPragma = $val"
-**
-** where $val is the value returned by the first PRAGMA invocation.
-**
-** In short, it copies the value of the specified PRAGMA setting from
-** dbRbu to dbMain.
-*/
-static void rbuCopyPragma(sqlite3rbu *p, const char *zPragma){
- if( p->rc==SQLITE_OK ){
- sqlite3_stmt *pPragma = 0;
- p->rc = prepareFreeAndCollectError(p->dbRbu, &pPragma, &p->zErrmsg,
- sqlite3_mprintf("PRAGMA main.%s", zPragma)
- );
- if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPragma) ){
- p->rc = rbuMPrintfExec(p, p->dbMain, "PRAGMA main.%s = %d",
- zPragma, sqlite3_column_int(pPragma, 0)
- );
- }
- rbuFinalize(p, pPragma);
- }
-}
-
-/*
-** The RBU handle passed as the only argument has just been opened and
-** the state database is empty. If this RBU handle was opened for an
-** RBU vacuum operation, create the schema in the target db.
-*/
-static void rbuCreateTargetSchema(sqlite3rbu *p){
- sqlite3_stmt *pSql = 0;
- sqlite3_stmt *pInsert = 0;
-
- assert( rbuIsVacuum(p) );
- p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=1", 0,0, &p->zErrmsg);
- if( p->rc==SQLITE_OK ){
- p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
- "SELECT sql FROM sqlite_master WHERE sql!='' AND rootpage!=0"
- " AND name!='sqlite_sequence' "
- " ORDER BY type DESC"
- );
- }
-
- while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){
- const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
- p->rc = sqlite3_exec(p->dbMain, zSql, 0, 0, &p->zErrmsg);
- }
- rbuFinalize(p, pSql);
- if( p->rc!=SQLITE_OK ) return;
-
- if( p->rc==SQLITE_OK ){
- p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
- "SELECT * FROM sqlite_master WHERE rootpage=0 OR rootpage IS NULL"
- );
- }
-
- if( p->rc==SQLITE_OK ){
- p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg,
- "INSERT INTO sqlite_master VALUES(?,?,?,?,?)"
- );
- }
-
- while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){
- int i;
- for(i=0; i<5; i++){
- sqlite3_bind_value(pInsert, i+1, sqlite3_column_value(pSql, i));
- }
- sqlite3_step(pInsert);
- p->rc = sqlite3_reset(pInsert);
- }
- if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=0",0,0,&p->zErrmsg);
- }
-
- rbuFinalize(p, pSql);
- rbuFinalize(p, pInsert);
-}
-
-/*
-** Step the RBU object.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *p){
- if( p ){
- switch( p->eStage ){
- case RBU_STAGE_OAL: {
- RbuObjIter *pIter = &p->objiter;
-
- /* If this is an RBU vacuum operation and the state table was empty
- ** when this handle was opened, create the target database schema. */
- if( rbuIsVacuum(p) && p->nProgress==0 && p->rc==SQLITE_OK ){
- rbuCreateTargetSchema(p);
- rbuCopyPragma(p, "user_version");
- rbuCopyPragma(p, "application_id");
- }
-
- while( p->rc==SQLITE_OK && pIter->zTbl ){
-
- if( pIter->bCleanup ){
- /* Clean up the rbu_tmp_xxx table for the previous table. It
- ** cannot be dropped as there are currently active SQL statements.
- ** But the contents can be deleted. */
- if( rbuIsVacuum(p)==0 && pIter->abIndexed ){
- rbuMPrintfExec(p, p->dbRbu,
- "DELETE FROM %s.'rbu_tmp_%q'", p->zStateDb, pIter->zDataTbl
- );
- }
- }else{
- rbuObjIterPrepareAll(p, pIter, 0);
-
- /* Advance to the next row to process. */
- if( p->rc==SQLITE_OK ){
- int rc = sqlite3_step(pIter->pSelect);
- if( rc==SQLITE_ROW ){
- p->nProgress++;
- p->nStep++;
- return rbuStep(p);
- }
- p->rc = sqlite3_reset(pIter->pSelect);
- p->nStep = 0;
- }
- }
-
- rbuObjIterNext(p, pIter);
- }
-
- if( p->rc==SQLITE_OK ){
- assert( pIter->zTbl==0 );
- rbuSaveState(p, RBU_STAGE_MOVE);
- rbuIncrSchemaCookie(p);
- if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, &p->zErrmsg);
- }
- if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, &p->zErrmsg);
- }
- p->eStage = RBU_STAGE_MOVE;
- }
- break;
- }
-
- case RBU_STAGE_MOVE: {
- if( p->rc==SQLITE_OK ){
- rbuMoveOalFile(p);
- p->nProgress++;
- }
- break;
- }
-
- case RBU_STAGE_CKPT: {
- if( p->rc==SQLITE_OK ){
- if( p->nStep>=p->nFrame ){
- sqlite3_file *pDb = p->pTargetFd->pReal;
-
- /* Sync the db file */
- p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
-
- /* Update nBackfill */
- if( p->rc==SQLITE_OK ){
- void volatile *ptr;
- p->rc = pDb->pMethods->xShmMap(pDb, 0, 32*1024, 0, &ptr);
- if( p->rc==SQLITE_OK ){
- ((u32 volatile*)ptr)[24] = p->iMaxFrame;
- }
- }
-
- if( p->rc==SQLITE_OK ){
- p->eStage = RBU_STAGE_DONE;
- p->rc = SQLITE_DONE;
- }
- }else{
- RbuFrame *pFrame = &p->aFrame[p->nStep];
- rbuCheckpointFrame(p, pFrame);
- p->nStep++;
- }
- p->nProgress++;
- }
- break;
- }
-
- default:
- break;
- }
- return p->rc;
- }else{
- return SQLITE_NOMEM;
- }
-}
-
-/*
-** Compare strings z1 and z2, returning 0 if they are identical, or non-zero
-** otherwise. Either or both argument may be NULL. Two NULL values are
-** considered equal, and NULL is considered distinct from all other values.
-*/
-static int rbuStrCompare(const char *z1, const char *z2){
- if( z1==0 && z2==0 ) return 0;
- if( z1==0 || z2==0 ) return 1;
- return (sqlite3_stricmp(z1, z2)!=0);
-}
-
-/*
-** This function is called as part of sqlite3rbu_open() when initializing
-** an rbu handle in OAL stage. If the rbu update has not started (i.e.
-** the rbu_state table was empty) it is a no-op. Otherwise, it arranges
-** things so that the next call to sqlite3rbu_step() continues on from
-** where the previous rbu handle left off.
-**
-** If an error occurs, an error code and error message are left in the
-** rbu handle passed as the first argument.
-*/
-static void rbuSetupOal(sqlite3rbu *p, RbuState *pState){
- assert( p->rc==SQLITE_OK );
- if( pState->zTbl ){
- RbuObjIter *pIter = &p->objiter;
- int rc = SQLITE_OK;
-
- while( rc==SQLITE_OK && pIter->zTbl && (pIter->bCleanup
- || rbuStrCompare(pIter->zIdx, pState->zIdx)
- || rbuStrCompare(pIter->zTbl, pState->zTbl)
- )){
- rc = rbuObjIterNext(p, pIter);
- }
-
- if( rc==SQLITE_OK && !pIter->zTbl ){
- rc = SQLITE_ERROR;
- p->zErrmsg = sqlite3_mprintf("rbu_state mismatch error");
- }
-
- if( rc==SQLITE_OK ){
- p->nStep = pState->nRow;
- rc = rbuObjIterPrepareAll(p, &p->objiter, p->nStep);
- }
-
- p->rc = rc;
- }
-}
-
-/*
-** If there is a "*-oal" file in the file-system corresponding to the
-** target database in the file-system, delete it. If an error occurs,
-** leave an error code and error message in the rbu handle.
-*/
-static void rbuDeleteOalFile(sqlite3rbu *p){
- char *zOal = rbuMPrintf(p, "%s-oal", p->zTarget);
- if( zOal ){
- sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
- assert( pVfs && p->rc==SQLITE_OK && p->zErrmsg==0 );
- pVfs->xDelete(pVfs, zOal, 0);
- sqlite3_free(zOal);
- }
-}
-
-/*
-** Allocate a private rbu VFS for the rbu handle passed as the only
-** argument. This VFS will be used unless the call to sqlite3rbu_open()
-** specified a URI with a vfs=? option in place of a target database
-** file name.
-*/
-static void rbuCreateVfs(sqlite3rbu *p){
- int rnd;
- char zRnd[64];
-
- assert( p->rc==SQLITE_OK );
- sqlite3_randomness(sizeof(int), (void*)&rnd);
- sqlite3_snprintf(sizeof(zRnd), zRnd, "rbu_vfs_%d", rnd);
- p->rc = sqlite3rbu_create_vfs(zRnd, 0);
- if( p->rc==SQLITE_OK ){
- sqlite3_vfs *pVfs = sqlite3_vfs_find(zRnd);
- assert( pVfs );
- p->zVfsName = pVfs->zName;
- }
-}
-
-/*
-** Destroy the private VFS created for the rbu handle passed as the only
-** argument by an earlier call to rbuCreateVfs().
-*/
-static void rbuDeleteVfs(sqlite3rbu *p){
- if( p->zVfsName ){
- sqlite3rbu_destroy_vfs(p->zVfsName);
- p->zVfsName = 0;
- }
-}
-
-/*
-** This user-defined SQL function is invoked with a single argument - the
-** name of a table expected to appear in the target database. It returns
-** the number of auxilliary indexes on the table.
-*/
-static void rbuIndexCntFunc(
- sqlite3_context *pCtx,
- int nVal,
- sqlite3_value **apVal
-){
- sqlite3rbu *p = (sqlite3rbu*)sqlite3_user_data(pCtx);
- sqlite3_stmt *pStmt = 0;
- char *zErrmsg = 0;
- int rc;
-
- assert( nVal==1 );
-
- rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &zErrmsg,
- sqlite3_mprintf("SELECT count(*) FROM sqlite_master "
- "WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0]))
- );
- if( rc!=SQLITE_OK ){
- sqlite3_result_error(pCtx, zErrmsg, -1);
- }else{
- int nIndex = 0;
- if( SQLITE_ROW==sqlite3_step(pStmt) ){
- nIndex = sqlite3_column_int(pStmt, 0);
- }
- rc = sqlite3_finalize(pStmt);
- if( rc==SQLITE_OK ){
- sqlite3_result_int(pCtx, nIndex);
- }else{
- sqlite3_result_error(pCtx, sqlite3_errmsg(p->dbMain), -1);
- }
- }
-
- sqlite3_free(zErrmsg);
-}
-
-/*
-** If the RBU database contains the rbu_count table, use it to initialize
-** the sqlite3rbu.nPhaseOneStep variable. The schema of the rbu_count table
-** is assumed to contain the same columns as:
-**
-** CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
-**
-** There should be one row in the table for each data_xxx table in the
-** database. The 'tbl' column should contain the name of a data_xxx table,
-** and the cnt column the number of rows it contains.
-**
-** sqlite3rbu.nPhaseOneStep is initialized to the sum of (1 + nIndex) * cnt
-** for all rows in the rbu_count table, where nIndex is the number of
-** indexes on the corresponding target database table.
-*/
-static void rbuInitPhaseOneSteps(sqlite3rbu *p){
- if( p->rc==SQLITE_OK ){
- sqlite3_stmt *pStmt = 0;
- int bExists = 0; /* True if rbu_count exists */
-
- p->nPhaseOneStep = -1;
-
- p->rc = sqlite3_create_function(p->dbRbu,
- "rbu_index_cnt", 1, SQLITE_UTF8, (void*)p, rbuIndexCntFunc, 0, 0
- );
-
- /* Check for the rbu_count table. If it does not exist, or if an error
- ** occurs, nPhaseOneStep will be left set to -1. */
- if( p->rc==SQLITE_OK ){
- p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
- "SELECT 1 FROM sqlite_master WHERE tbl_name = 'rbu_count'"
- );
- }
- if( p->rc==SQLITE_OK ){
- if( SQLITE_ROW==sqlite3_step(pStmt) ){
- bExists = 1;
- }
- p->rc = sqlite3_finalize(pStmt);
- }
-
- if( p->rc==SQLITE_OK && bExists ){
- p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
- "SELECT sum(cnt * (1 + rbu_index_cnt(rbu_target_name(tbl))))"
- "FROM rbu_count"
- );
- if( p->rc==SQLITE_OK ){
- if( SQLITE_ROW==sqlite3_step(pStmt) ){
- p->nPhaseOneStep = sqlite3_column_int64(pStmt, 0);
- }
- p->rc = sqlite3_finalize(pStmt);
- }
- }
- }
-}
-
-
-static sqlite3rbu *openRbuHandle(
- const char *zTarget,
- const char *zRbu,
- const char *zState
-){
- sqlite3rbu *p;
- size_t nTarget = zTarget ? strlen(zTarget) : 0;
- size_t nRbu = strlen(zRbu);
- size_t nState = zState ? strlen(zState) : 0;
- size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1+ nState+1;
-
- p = (sqlite3rbu*)sqlite3_malloc64(nByte);
- if( p ){
- RbuState *pState = 0;
-
- /* Create the custom VFS. */
- memset(p, 0, sizeof(sqlite3rbu));
- rbuCreateVfs(p);
-
- /* Open the target, RBU and state databases */
- if( p->rc==SQLITE_OK ){
- char *pCsr = (char*)&p[1];
- if( zTarget ){
- p->zTarget = pCsr;
- memcpy(p->zTarget, zTarget, nTarget+1);
- pCsr += nTarget+1;
- }
- p->zRbu = pCsr;
- memcpy(p->zRbu, zRbu, nRbu+1);
- pCsr += nRbu+1;
- if( zState ){
- p->zState = pCsr;
- memcpy(p->zState, zState, nState+1);
- }
- rbuOpenDatabase(p);
- }
-
- if( p->rc==SQLITE_OK ){
- pState = rbuLoadState(p);
- assert( pState || p->rc!=SQLITE_OK );
- if( p->rc==SQLITE_OK ){
-
- if( pState->eStage==0 ){
- rbuDeleteOalFile(p);
- rbuInitPhaseOneSteps(p);
- p->eStage = RBU_STAGE_OAL;
- }else{
- p->eStage = pState->eStage;
- p->nPhaseOneStep = pState->nPhaseOneStep;
- }
- p->nProgress = pState->nProgress;
- p->iOalSz = pState->iOalSz;
- }
- }
- assert( p->rc!=SQLITE_OK || p->eStage!=0 );
-
- if( p->rc==SQLITE_OK && p->pTargetFd->pWalFd ){
- if( p->eStage==RBU_STAGE_OAL ){
- p->rc = SQLITE_ERROR;
- p->zErrmsg = sqlite3_mprintf("cannot update wal mode database");
- }else if( p->eStage==RBU_STAGE_MOVE ){
- p->eStage = RBU_STAGE_CKPT;
- p->nStep = 0;
- }
- }
-
- if( p->rc==SQLITE_OK
- && (p->eStage==RBU_STAGE_OAL || p->eStage==RBU_STAGE_MOVE)
- && pState->eStage!=0
- ){
- rbu_file *pFd = (rbuIsVacuum(p) ? p->pRbuFd : p->pTargetFd);
- if( pFd->iCookie!=pState->iCookie ){
- /* At this point (pTargetFd->iCookie) contains the value of the
- ** change-counter cookie (the thing that gets incremented when a
- ** transaction is committed in rollback mode) currently stored on
- ** page 1 of the database file. */
- p->rc = SQLITE_BUSY;
- p->zErrmsg = sqlite3_mprintf("database modified during rbu %s",
- (rbuIsVacuum(p) ? "vacuum" : "update")
- );
- }
- }
-
- if( p->rc==SQLITE_OK ){
- if( p->eStage==RBU_STAGE_OAL ){
- sqlite3 *db = p->dbMain;
-
- if( pState->eStage==0 && rbuIsVacuum(p) ){
- rbuCopyPragma(p, "page_size");
- rbuCopyPragma(p, "auto_vacuum");
- }
-
- /* Open transactions both databases. The *-oal file is opened or
- ** created at this point. */
- if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
- }
- if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, &p->zErrmsg);
- }
-
- /* Check if the main database is a zipvfs db. If it is, set the upper
- ** level pager to use "journal_mode=off". This prevents it from
- ** generating a large journal using a temp file. */
- if( p->rc==SQLITE_OK ){
- int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0);
- if( frc==SQLITE_OK ){
- p->rc = sqlite3_exec(db, "PRAGMA journal_mode=off",0,0,&p->zErrmsg);
- }
- }
-
- /* Point the object iterator at the first object */
- if( p->rc==SQLITE_OK ){
- p->rc = rbuObjIterFirst(p, &p->objiter);
- }
-
- /* If the RBU database contains no data_xxx tables, declare the RBU
- ** update finished. */
- if( p->rc==SQLITE_OK && p->objiter.zTbl==0 ){
- p->rc = SQLITE_DONE;
- }
-
- if( p->rc==SQLITE_OK ){
- rbuSetupOal(p, pState);
- }
-
- }else if( p->eStage==RBU_STAGE_MOVE ){
- /* no-op */
- }else if( p->eStage==RBU_STAGE_CKPT ){
- rbuSetupCheckpoint(p, pState);
- }else if( p->eStage==RBU_STAGE_DONE ){
- p->rc = SQLITE_DONE;
- }else{
- p->rc = SQLITE_CORRUPT;
- }
- }
-
- rbuFreeState(pState);
- }
-
- return p;
-}
-
-/*
-** Open and return a new RBU handle.
-*/
-SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
- const char *zTarget,
- const char *zRbu,
- const char *zState
-){
- /* TODO: Check that zTarget and zRbu are non-NULL */
- return openRbuHandle(zTarget, zRbu, zState);
-}
-
-/*
-** Open a handle to begin or resume an RBU VACUUM operation.
-*/
-SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_vacuum(
- const char *zTarget,
- const char *zState
-){
- /* TODO: Check that both arguments are non-NULL */
- return openRbuHandle(0, zTarget, zState);
-}
-
-/*
-** Return the database handle used by pRbu.
-*/
-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3rbu_db(sqlite3rbu *pRbu, int bRbu){
- sqlite3 *db = 0;
- if( pRbu ){
- db = (bRbu ? pRbu->dbRbu : pRbu->dbMain);
- }
- return db;
-}
-
-
-/*
-** If the error code currently stored in the RBU handle is SQLITE_CONSTRAINT,
-** then edit any error message string so as to remove all occurrences of
-** the pattern "rbu_imp_[0-9]*".
-*/
-static void rbuEditErrmsg(sqlite3rbu *p){
- if( p->rc==SQLITE_CONSTRAINT && p->zErrmsg ){
- unsigned int i;
- size_t nErrmsg = strlen(p->zErrmsg);
- for(i=0; i<(nErrmsg-8); i++){
- if( memcmp(&p->zErrmsg[i], "rbu_imp_", 8)==0 ){
- int nDel = 8;
- while( p->zErrmsg[i+nDel]>='0' && p->zErrmsg[i+nDel]<='9' ) nDel++;
- memmove(&p->zErrmsg[i], &p->zErrmsg[i+nDel], nErrmsg + 1 - i - nDel);
- nErrmsg -= nDel;
- }
- }
- }
-}
-
-/*
-** Close the RBU handle.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
- int rc;
- if( p ){
-
- /* Commit the transaction to the *-oal file. */
- if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_OAL ){
- p->rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, &p->zErrmsg);
- }
-
- rbuSaveState(p, p->eStage);
-
- if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_OAL ){
- p->rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, &p->zErrmsg);
- }
-
- /* Close any open statement handles. */
- rbuObjIterFinalize(&p->objiter);
-
- /* If this is an RBU vacuum handle and the vacuum has either finished
- ** successfully or encountered an error, delete the contents of the
- ** state table. This causes the next call to sqlite3rbu_vacuum()
- ** specifying the current target and state databases to start a new
- ** vacuum from scratch. */
- if( rbuIsVacuum(p) && p->rc!=SQLITE_OK && p->dbRbu ){
- int rc2 = sqlite3_exec(p->dbRbu, "DELETE FROM stat.rbu_state", 0, 0, 0);
- if( p->rc==SQLITE_DONE && rc2!=SQLITE_OK ) p->rc = rc2;
- }
-
- /* Close the open database handle and VFS object. */
- sqlite3_close(p->dbRbu);
- sqlite3_close(p->dbMain);
- rbuDeleteVfs(p);
- sqlite3_free(p->aBuf);
- sqlite3_free(p->aFrame);
-
- rbuEditErrmsg(p);
- rc = p->rc;
- *pzErrmsg = p->zErrmsg;
- sqlite3_free(p);
- }else{
- rc = SQLITE_NOMEM;
- *pzErrmsg = 0;
- }
- return rc;
-}
-
-/*
-** Return the total number of key-value operations (inserts, deletes or
-** updates) that have been performed on the target database since the
-** current RBU update was started.
-*/
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3rbu_progress(sqlite3rbu *pRbu){
- return pRbu->nProgress;
-}
-
-/*
-** Return permyriadage progress indications for the two main stages of
-** an RBU update.
-*/
-SQLITE_API void SQLITE_STDCALL sqlite3rbu_bp_progress(sqlite3rbu *p, int *pnOne, int *pnTwo){
- const int MAX_PROGRESS = 10000;
- switch( p->eStage ){
- case RBU_STAGE_OAL:
- if( p->nPhaseOneStep>0 ){
- *pnOne = (int)(MAX_PROGRESS * (i64)p->nProgress/(i64)p->nPhaseOneStep);
- }else{
- *pnOne = -1;
- }
- *pnTwo = 0;
- break;
-
- case RBU_STAGE_MOVE:
- *pnOne = MAX_PROGRESS;
- *pnTwo = 0;
- break;
-
- case RBU_STAGE_CKPT:
- *pnOne = MAX_PROGRESS;
- *pnTwo = (int)(MAX_PROGRESS * (i64)p->nStep / (i64)p->nFrame);
- break;
-
- case RBU_STAGE_DONE:
- *pnOne = MAX_PROGRESS;
- *pnTwo = MAX_PROGRESS;
- break;
-
- default:
- assert( 0 );
- }
-}
-
-SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *p){
- int rc = p->rc;
-
- if( rc==SQLITE_DONE ) return SQLITE_OK;
-
- assert( p->eStage>=RBU_STAGE_OAL && p->eStage<=RBU_STAGE_DONE );
- if( p->eStage==RBU_STAGE_OAL ){
- assert( rc!=SQLITE_DONE );
- if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, 0);
- }
-
- p->rc = rc;
- rbuSaveState(p, p->eStage);
- rc = p->rc;
-
- if( p->eStage==RBU_STAGE_OAL ){
- assert( rc!=SQLITE_DONE );
- if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0);
- if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "BEGIN IMMEDIATE", 0, 0, 0);
- if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "BEGIN IMMEDIATE", 0, 0,0);
- }
-
- p->rc = rc;
- return rc;
-}
-
-/**************************************************************************
-** Beginning of RBU VFS shim methods. The VFS shim modifies the behaviour
-** of a standard VFS in the following ways:
-**
-** 1. Whenever the first page of a main database file is read or
-** written, the value of the change-counter cookie is stored in
-** rbu_file.iCookie. Similarly, the value of the "write-version"
-** database header field is stored in rbu_file.iWriteVer. This ensures
-** that the values are always trustworthy within an open transaction.
-**
-** 2. Whenever an SQLITE_OPEN_WAL file is opened, the (rbu_file.pWalFd)
-** member variable of the associated database file descriptor is set
-** to point to the new file. A mutex protected linked list of all main
-** db fds opened using a particular RBU VFS is maintained at
-** rbu_vfs.pMain to facilitate this.
-**
-** 3. Using a new file-control "SQLITE_FCNTL_RBU", a main db rbu_file
-** object can be marked as the target database of an RBU update. This
-** turns on the following extra special behaviour:
-**
-** 3a. If xAccess() is called to check if there exists a *-wal file
-** associated with an RBU target database currently in RBU_STAGE_OAL
-** stage (preparing the *-oal file), the following special handling
-** applies:
-**
-** * if the *-wal file does exist, return SQLITE_CANTOPEN. An RBU
-** target database may not be in wal mode already.
-**
-** * if the *-wal file does not exist, set the output parameter to
-** non-zero (to tell SQLite that it does exist) anyway.
-**
-** Then, when xOpen() is called to open the *-wal file associated with
-** the RBU target in RBU_STAGE_OAL stage, instead of opening the *-wal
-** file, the rbu vfs opens the corresponding *-oal file instead.
-**
-** 3b. The *-shm pages returned by xShmMap() for a target db file in
-** RBU_STAGE_OAL mode are actually stored in heap memory. This is to
-** avoid creating a *-shm file on disk. Additionally, xShmLock() calls
-** are no-ops on target database files in RBU_STAGE_OAL mode. This is
-** because assert() statements in some VFS implementations fail if
-** xShmLock() is called before xShmMap().
-**
-** 3c. If an EXCLUSIVE lock is attempted on a target database file in any
-** mode except RBU_STAGE_DONE (all work completed and checkpointed), it
-** fails with an SQLITE_BUSY error. This is to stop RBU connections
-** from automatically checkpointing a *-wal (or *-oal) file from within
-** sqlite3_close().
-**
-** 3d. In RBU_STAGE_CAPTURE mode, all xRead() calls on the wal file, and
-** all xWrite() calls on the target database file perform no IO.
-** Instead the frame and page numbers that would be read and written
-** are recorded. Additionally, successful attempts to obtain exclusive
-** xShmLock() WRITER, CHECKPOINTER and READ0 locks on the target
-** database file are recorded. xShmLock() calls to unlock the same
-** locks are no-ops (so that once obtained, these locks are never
-** relinquished). Finally, calls to xSync() on the target database
-** file fail with SQLITE_INTERNAL errors.
-*/
-
-static void rbuUnlockShm(rbu_file *p){
- if( p->pRbu ){
- int (*xShmLock)(sqlite3_file*,int,int,int) = p->pReal->pMethods->xShmLock;
- int i;
- for(i=0; i<SQLITE_SHM_NLOCK;i++){
- if( (1<<i) & p->pRbu->mLock ){
- xShmLock(p->pReal, i, 1, SQLITE_SHM_UNLOCK|SQLITE_SHM_EXCLUSIVE);
- }
- }
- p->pRbu->mLock = 0;
- }
-}
-
-/*
-** Close an rbu file.
-*/
-static int rbuVfsClose(sqlite3_file *pFile){
- rbu_file *p = (rbu_file*)pFile;
- int rc;
- int i;
-
- /* Free the contents of the apShm[] array. And the array itself. */
- for(i=0; i<p->nShm; i++){
- sqlite3_free(p->apShm[i]);
- }
- sqlite3_free(p->apShm);
- p->apShm = 0;
- sqlite3_free(p->zDel);
-
- if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
- rbu_file **pp;
- sqlite3_mutex_enter(p->pRbuVfs->mutex);
- for(pp=&p->pRbuVfs->pMain; *pp!=p; pp=&((*pp)->pMainNext));
- *pp = p->pMainNext;
- sqlite3_mutex_leave(p->pRbuVfs->mutex);
- rbuUnlockShm(p);
- p->pReal->pMethods->xShmUnmap(p->pReal, 0);
- }
-
- /* Close the underlying file handle */
- rc = p->pReal->pMethods->xClose(p->pReal);
- return rc;
-}
-
-
-/*
-** Read and return an unsigned 32-bit big-endian integer from the buffer
-** passed as the only argument.
-*/
-static u32 rbuGetU32(u8 *aBuf){
- return ((u32)aBuf[0] << 24)
- + ((u32)aBuf[1] << 16)
- + ((u32)aBuf[2] << 8)
- + ((u32)aBuf[3]);
-}
-
-/*
-** Write an unsigned 32-bit value in big-endian format to the supplied
-** buffer.
-*/
-static void rbuPutU32(u8 *aBuf, u32 iVal){
- aBuf[0] = (iVal >> 24) & 0xFF;
- aBuf[1] = (iVal >> 16) & 0xFF;
- aBuf[2] = (iVal >> 8) & 0xFF;
- aBuf[3] = (iVal >> 0) & 0xFF;
-}
-
-static void rbuPutU16(u8 *aBuf, u16 iVal){
- aBuf[0] = (iVal >> 8) & 0xFF;
- aBuf[1] = (iVal >> 0) & 0xFF;
-}
-
-/*
-** Read data from an rbuVfs-file.
-*/
-static int rbuVfsRead(
- sqlite3_file *pFile,
- void *zBuf,
- int iAmt,
- sqlite_int64 iOfst
-){
- rbu_file *p = (rbu_file*)pFile;
- sqlite3rbu *pRbu = p->pRbu;
- int rc;
-
- if( pRbu && pRbu->eStage==RBU_STAGE_CAPTURE ){
- assert( p->openFlags & SQLITE_OPEN_WAL );
- rc = rbuCaptureWalRead(p->pRbu, iOfst, iAmt);
- }else{
- if( pRbu && pRbu->eStage==RBU_STAGE_OAL
- && (p->openFlags & SQLITE_OPEN_WAL)
- && iOfst>=pRbu->iOalSz
- ){
- rc = SQLITE_OK;
- memset(zBuf, 0, iAmt);
- }else{
- rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
-#if 1
- /* If this is being called to read the first page of the target
- ** database as part of an rbu vacuum operation, synthesize the
- ** contents of the first page if it does not yet exist. Otherwise,
- ** SQLite will not check for a *-wal file. */
- if( pRbu && rbuIsVacuum(pRbu)
- && rc==SQLITE_IOERR_SHORT_READ && iOfst==0
- && (p->openFlags & SQLITE_OPEN_MAIN_DB)
- && pRbu->rc==SQLITE_OK
- ){
- sqlite3_file *pFd = (sqlite3_file*)pRbu->pRbuFd;
- rc = pFd->pMethods->xRead(pFd, zBuf, iAmt, iOfst);
- if( rc==SQLITE_OK ){
- u8 *aBuf = (u8*)zBuf;
- u32 iRoot = rbuGetU32(&aBuf[52]) ? 1 : 0;
- rbuPutU32(&aBuf[52], iRoot); /* largest root page number */
- rbuPutU32(&aBuf[36], 0); /* number of free pages */
- rbuPutU32(&aBuf[32], 0); /* first page on free list trunk */
- rbuPutU32(&aBuf[28], 1); /* size of db file in pages */
- rbuPutU32(&aBuf[24], pRbu->pRbuFd->iCookie+1); /* Change counter */
-
- if( iAmt>100 ){
- memset(&aBuf[100], 0, iAmt-100);
- rbuPutU16(&aBuf[105], iAmt & 0xFFFF);
- aBuf[100] = 0x0D;
- }
- }
- }
-#endif
- }
- if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
- /* These look like magic numbers. But they are stable, as they are part
- ** of the definition of the SQLite file format, which may not change. */
- u8 *pBuf = (u8*)zBuf;
- p->iCookie = rbuGetU32(&pBuf[24]);
- p->iWriteVer = pBuf[19];
- }
- }
- return rc;
-}
-
-/*
-** Write data to an rbuVfs-file.
-*/
-static int rbuVfsWrite(
- sqlite3_file *pFile,
- const void *zBuf,
- int iAmt,
- sqlite_int64 iOfst
-){
- rbu_file *p = (rbu_file*)pFile;
- sqlite3rbu *pRbu = p->pRbu;
- int rc;
-
- if( pRbu && pRbu->eStage==RBU_STAGE_CAPTURE ){
- assert( p->openFlags & SQLITE_OPEN_MAIN_DB );
- rc = rbuCaptureDbWrite(p->pRbu, iOfst);
- }else{
- if( pRbu && pRbu->eStage==RBU_STAGE_OAL
- && (p->openFlags & SQLITE_OPEN_WAL)
- && iOfst>=pRbu->iOalSz
- ){
- pRbu->iOalSz = iAmt + iOfst;
- }
- rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
- if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
- /* These look like magic numbers. But they are stable, as they are part
- ** of the definition of the SQLite file format, which may not change. */
- u8 *pBuf = (u8*)zBuf;
- p->iCookie = rbuGetU32(&pBuf[24]);
- p->iWriteVer = pBuf[19];
- }
- }
- return rc;
-}
-
-/*
-** Truncate an rbuVfs-file.
-*/
-static int rbuVfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
- rbu_file *p = (rbu_file*)pFile;
- return p->pReal->pMethods->xTruncate(p->pReal, size);
-}
-
-/*
-** Sync an rbuVfs-file.
-*/
-static int rbuVfsSync(sqlite3_file *pFile, int flags){
- rbu_file *p = (rbu_file *)pFile;
- if( p->pRbu && p->pRbu->eStage==RBU_STAGE_CAPTURE ){
- if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
- return SQLITE_INTERNAL;
- }
- return SQLITE_OK;
- }
- return p->pReal->pMethods->xSync(p->pReal, flags);
-}
-
-/*
-** Return the current file-size of an rbuVfs-file.
-*/
-static int rbuVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
- rbu_file *p = (rbu_file *)pFile;
- int rc;
- rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
-
- /* If this is an RBU vacuum operation and this is the target database,
- ** pretend that it has at least one page. Otherwise, SQLite will not
- ** check for the existance of a *-wal file. rbuVfsRead() contains
- ** similar logic. */
- if( rc==SQLITE_OK && *pSize==0
- && p->pRbu && rbuIsVacuum(p->pRbu)
- && (p->openFlags & SQLITE_OPEN_MAIN_DB)
- ){
- *pSize = 1024;
- }
- return rc;
-}
-
-/*
-** Lock an rbuVfs-file.
-*/
-static int rbuVfsLock(sqlite3_file *pFile, int eLock){
- rbu_file *p = (rbu_file*)pFile;
- sqlite3rbu *pRbu = p->pRbu;
- int rc = SQLITE_OK;
-
- assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
- if( eLock==SQLITE_LOCK_EXCLUSIVE
- && (p->bNolock || (pRbu && pRbu->eStage!=RBU_STAGE_DONE))
- ){
- /* Do not allow EXCLUSIVE locks. Preventing SQLite from taking this
- ** prevents it from checkpointing the database from sqlite3_close(). */
- rc = SQLITE_BUSY;
- }else{
- rc = p->pReal->pMethods->xLock(p->pReal, eLock);
- }
-
- return rc;
-}
-
-/*
-** Unlock an rbuVfs-file.
-*/
-static int rbuVfsUnlock(sqlite3_file *pFile, int eLock){
- rbu_file *p = (rbu_file *)pFile;
- return p->pReal->pMethods->xUnlock(p->pReal, eLock);
-}
-
-/*
-** Check if another file-handle holds a RESERVED lock on an rbuVfs-file.
-*/
-static int rbuVfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){
- rbu_file *p = (rbu_file *)pFile;
- return p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
-}
-
-/*
-** File control method. For custom operations on an rbuVfs-file.
-*/
-static int rbuVfsFileControl(sqlite3_file *pFile, int op, void *pArg){
- rbu_file *p = (rbu_file *)pFile;
- int (*xControl)(sqlite3_file*,int,void*) = p->pReal->pMethods->xFileControl;
- int rc;
-
- assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB)
- || p->openFlags & (SQLITE_OPEN_TRANSIENT_DB|SQLITE_OPEN_TEMP_JOURNAL)
- );
- if( op==SQLITE_FCNTL_RBU ){
- sqlite3rbu *pRbu = (sqlite3rbu*)pArg;
-
- /* First try to find another RBU vfs lower down in the vfs stack. If
- ** one is found, this vfs will operate in pass-through mode. The lower
- ** level vfs will do the special RBU handling. */
- rc = xControl(p->pReal, op, pArg);
-
- if( rc==SQLITE_NOTFOUND ){
- /* Now search for a zipvfs instance lower down in the VFS stack. If
- ** one is found, this is an error. */
- void *dummy = 0;
- rc = xControl(p->pReal, SQLITE_FCNTL_ZIPVFS, &dummy);
- if( rc==SQLITE_OK ){
- rc = SQLITE_ERROR;
- pRbu->zErrmsg = sqlite3_mprintf("rbu/zipvfs setup error");
- }else if( rc==SQLITE_NOTFOUND ){
- pRbu->pTargetFd = p;
- p->pRbu = pRbu;
- if( p->pWalFd ) p->pWalFd->pRbu = pRbu;
- rc = SQLITE_OK;
- }
- }
- return rc;
- }
- else if( op==SQLITE_FCNTL_RBUCNT ){
- sqlite3rbu *pRbu = (sqlite3rbu*)pArg;
- pRbu->nRbu++;
- pRbu->pRbuFd = p;
- p->bNolock = 1;
- }
-
- rc = xControl(p->pReal, op, pArg);
- if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
- rbu_vfs *pRbuVfs = p->pRbuVfs;
- char *zIn = *(char**)pArg;
- char *zOut = sqlite3_mprintf("rbu(%s)/%z", pRbuVfs->base.zName, zIn);
- *(char**)pArg = zOut;
- if( zOut==0 ) rc = SQLITE_NOMEM;
- }
-
- return rc;
-}
-
-/*
-** Return the sector-size in bytes for an rbuVfs-file.
-*/
-static int rbuVfsSectorSize(sqlite3_file *pFile){
- rbu_file *p = (rbu_file *)pFile;
- return p->pReal->pMethods->xSectorSize(p->pReal);
-}
-
-/*
-** Return the device characteristic flags supported by an rbuVfs-file.
-*/
-static int rbuVfsDeviceCharacteristics(sqlite3_file *pFile){
- rbu_file *p = (rbu_file *)pFile;
- return p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
-}
-
-/*
-** Take or release a shared-memory lock.
-*/
-static int rbuVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
- rbu_file *p = (rbu_file*)pFile;
- sqlite3rbu *pRbu = p->pRbu;
- int rc = SQLITE_OK;
-
-#ifdef SQLITE_AMALGAMATION
- assert( WAL_CKPT_LOCK==1 );
-#endif
-
- assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
- if( pRbu && (pRbu->eStage==RBU_STAGE_OAL || pRbu->eStage==RBU_STAGE_MOVE) ){
- /* Magic number 1 is the WAL_CKPT_LOCK lock. Preventing SQLite from
- ** taking this lock also prevents any checkpoints from occurring.
- ** todo: really, it's not clear why this might occur, as
- ** wal_autocheckpoint ought to be turned off. */
- if( ofst==WAL_LOCK_CKPT && n==1 ) rc = SQLITE_BUSY;
- }else{
- int bCapture = 0;
- if( n==1 && (flags & SQLITE_SHM_EXCLUSIVE)
- && pRbu && pRbu->eStage==RBU_STAGE_CAPTURE
- && (ofst==WAL_LOCK_WRITE || ofst==WAL_LOCK_CKPT || ofst==WAL_LOCK_READ0)
- ){
- bCapture = 1;
- }
-
- if( bCapture==0 || 0==(flags & SQLITE_SHM_UNLOCK) ){
- rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
- if( bCapture && rc==SQLITE_OK ){
- pRbu->mLock |= (1 << ofst);
- }
- }
- }
-
- return rc;
-}
-
-/*
-** Obtain a pointer to a mapping of a single 32KiB page of the *-shm file.
-*/
-static int rbuVfsShmMap(
- sqlite3_file *pFile,
- int iRegion,
- int szRegion,
- int isWrite,
- void volatile **pp
-){
- rbu_file *p = (rbu_file*)pFile;
- int rc = SQLITE_OK;
- int eStage = (p->pRbu ? p->pRbu->eStage : 0);
-
- /* If not in RBU_STAGE_OAL, allow this call to pass through. Or, if this
- ** rbu is in the RBU_STAGE_OAL state, use heap memory for *-shm space
- ** instead of a file on disk. */
- assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
- if( eStage==RBU_STAGE_OAL || eStage==RBU_STAGE_MOVE ){
- if( iRegion<=p->nShm ){
- int nByte = (iRegion+1) * sizeof(char*);
- char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte);
- if( apNew==0 ){
- rc = SQLITE_NOMEM;
- }else{
- memset(&apNew[p->nShm], 0, sizeof(char*) * (1 + iRegion - p->nShm));
- p->apShm = apNew;
- p->nShm = iRegion+1;
- }
- }
-
- if( rc==SQLITE_OK && p->apShm[iRegion]==0 ){
- char *pNew = (char*)sqlite3_malloc64(szRegion);
- if( pNew==0 ){
- rc = SQLITE_NOMEM;
- }else{
- memset(pNew, 0, szRegion);
- p->apShm[iRegion] = pNew;
- }
- }
-
- if( rc==SQLITE_OK ){
- *pp = p->apShm[iRegion];
- }else{
- *pp = 0;
- }
- }else{
- assert( p->apShm==0 );
- rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
- }
-
- return rc;
-}
-
-/*
-** Memory barrier.
-*/
-static void rbuVfsShmBarrier(sqlite3_file *pFile){
- rbu_file *p = (rbu_file *)pFile;
- p->pReal->pMethods->xShmBarrier(p->pReal);
-}
-
-/*
-** The xShmUnmap method.
-*/
-static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){
- rbu_file *p = (rbu_file*)pFile;
- int rc = SQLITE_OK;
- int eStage = (p->pRbu ? p->pRbu->eStage : 0);
-
- assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
- if( eStage==RBU_STAGE_OAL || eStage==RBU_STAGE_MOVE ){
- /* no-op */
- }else{
- /* Release the checkpointer and writer locks */
- rbuUnlockShm(p);
- rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
- }
- return rc;
-}
-
-/*
-** Given that zWal points to a buffer containing a wal file name passed to
-** either the xOpen() or xAccess() VFS method, return a pointer to the
-** file-handle opened by the same database connection on the corresponding
-** database file.
-*/
-static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal){
- rbu_file *pDb;
- sqlite3_mutex_enter(pRbuVfs->mutex);
- for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){}
- sqlite3_mutex_leave(pRbuVfs->mutex);
- return pDb;
-}
-
-/*
-** A main database named zName has just been opened. The following
-** function returns a pointer to a buffer owned by SQLite that contains
-** the name of the *-wal file this db connection will use. SQLite
-** happens to pass a pointer to this buffer when using xAccess()
-** or xOpen() to operate on the *-wal file.
-*/
-static const char *rbuMainToWal(const char *zName, int flags){
- int n = (int)strlen(zName);
- const char *z = &zName[n];
- if( flags & SQLITE_OPEN_URI ){
- int odd = 0;
- while( 1 ){
- if( z[0]==0 ){
- odd = 1 - odd;
- if( odd && z[1]==0 ) break;
- }
- z++;
- }
- z += 2;
- }else{
- while( *z==0 ) z++;
- }
- z += (n + 8 + 1);
- return z;
-}
-
-/*
-** Open an rbu file handle.
-*/
-static int rbuVfsOpen(
- sqlite3_vfs *pVfs,
- const char *zName,
- sqlite3_file *pFile,
- int flags,
- int *pOutFlags
-){
- static sqlite3_io_methods rbuvfs_io_methods = {
- 2, /* iVersion */
- rbuVfsClose, /* xClose */
- rbuVfsRead, /* xRead */
- rbuVfsWrite, /* xWrite */
- rbuVfsTruncate, /* xTruncate */
- rbuVfsSync, /* xSync */
- rbuVfsFileSize, /* xFileSize */
- rbuVfsLock, /* xLock */
- rbuVfsUnlock, /* xUnlock */
- rbuVfsCheckReservedLock, /* xCheckReservedLock */
- rbuVfsFileControl, /* xFileControl */
- rbuVfsSectorSize, /* xSectorSize */
- rbuVfsDeviceCharacteristics, /* xDeviceCharacteristics */
- rbuVfsShmMap, /* xShmMap */
- rbuVfsShmLock, /* xShmLock */
- rbuVfsShmBarrier, /* xShmBarrier */
- rbuVfsShmUnmap, /* xShmUnmap */
- 0, 0 /* xFetch, xUnfetch */
- };
- rbu_vfs *pRbuVfs = (rbu_vfs*)pVfs;
- sqlite3_vfs *pRealVfs = pRbuVfs->pRealVfs;
- rbu_file *pFd = (rbu_file *)pFile;
- int rc = SQLITE_OK;
- const char *zOpen = zName;
- int oflags = flags;
-
- memset(pFd, 0, sizeof(rbu_file));
- pFd->pReal = (sqlite3_file*)&pFd[1];
- pFd->pRbuVfs = pRbuVfs;
- pFd->openFlags = flags;
- if( zName ){
- if( flags & SQLITE_OPEN_MAIN_DB ){
- /* A main database has just been opened. The following block sets
- ** (pFd->zWal) to point to a buffer owned by SQLite that contains
- ** the name of the *-wal file this db connection will use. SQLite
- ** happens to pass a pointer to this buffer when using xAccess()
- ** or xOpen() to operate on the *-wal file. */
- pFd->zWal = rbuMainToWal(zName, flags);
- }
- else if( flags & SQLITE_OPEN_WAL ){
- rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName);
- if( pDb ){
- if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
- /* This call is to open a *-wal file. Intead, open the *-oal. This
- ** code ensures that the string passed to xOpen() is terminated by a
- ** pair of '\0' bytes in case the VFS attempts to extract a URI
- ** parameter from it. */
- const char *zBase = zName;
- size_t nCopy;
- char *zCopy;
- if( rbuIsVacuum(pDb->pRbu) ){
- zBase = sqlite3_db_filename(pDb->pRbu->dbRbu, "main");
- zBase = rbuMainToWal(zBase, SQLITE_OPEN_URI);
- }
- nCopy = strlen(zBase);
- zCopy = sqlite3_malloc64(nCopy+2);
- if( zCopy ){
- memcpy(zCopy, zBase, nCopy);
- zCopy[nCopy-3] = 'o';
- zCopy[nCopy] = '\0';
- zCopy[nCopy+1] = '\0';
- zOpen = (const char*)(pFd->zDel = zCopy);
- }else{
- rc = SQLITE_NOMEM;
- }
- pFd->pRbu = pDb->pRbu;
- }
- pDb->pWalFd = pFd;
- }
- }
- }
-
- if( oflags & SQLITE_OPEN_MAIN_DB
- && sqlite3_uri_boolean(zName, "rbu_memory", 0)
- ){
- assert( oflags & SQLITE_OPEN_MAIN_DB );
- oflags = SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
- SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE;
- zOpen = 0;
- }
-
- if( rc==SQLITE_OK ){
- rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, oflags, pOutFlags);
- }
- if( pFd->pReal->pMethods ){
- /* The xOpen() operation has succeeded. Set the sqlite3_file.pMethods
- ** pointer and, if the file is a main database file, link it into the
- ** mutex protected linked list of all such files. */
- pFile->pMethods = &rbuvfs_io_methods;
- if( flags & SQLITE_OPEN_MAIN_DB ){
- sqlite3_mutex_enter(pRbuVfs->mutex);
- pFd->pMainNext = pRbuVfs->pMain;
- pRbuVfs->pMain = pFd;
- sqlite3_mutex_leave(pRbuVfs->mutex);
- }
- }else{
- sqlite3_free(pFd->zDel);
- }
-
- return rc;
-}
-
-/*
-** Delete the file located at zPath.
-*/
-static int rbuVfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
- sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
- return pRealVfs->xDelete(pRealVfs, zPath, dirSync);
-}
-
-/*
-** Test for access permissions. Return true if the requested permission
-** is available, or false otherwise.
-*/
-static int rbuVfsAccess(
- sqlite3_vfs *pVfs,
- const char *zPath,
- int flags,
- int *pResOut
-){
- rbu_vfs *pRbuVfs = (rbu_vfs*)pVfs;
- sqlite3_vfs *pRealVfs = pRbuVfs->pRealVfs;
- int rc;
-
- rc = pRealVfs->xAccess(pRealVfs, zPath, flags, pResOut);
-
- /* If this call is to check if a *-wal file associated with an RBU target
- ** database connection exists, and the RBU update is in RBU_STAGE_OAL,
- ** the following special handling is activated:
- **
- ** a) if the *-wal file does exist, return SQLITE_CANTOPEN. This
- ** ensures that the RBU extension never tries to update a database
- ** in wal mode, even if the first page of the database file has
- ** been damaged.
- **
- ** b) if the *-wal file does not exist, claim that it does anyway,
- ** causing SQLite to call xOpen() to open it. This call will also
- ** be intercepted (see the rbuVfsOpen() function) and the *-oal
- ** file opened instead.
- */
- if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){
- rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath);
- if( pDb && pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
- if( *pResOut ){
- rc = SQLITE_CANTOPEN;
- }else{
- *pResOut = 1;
- }
- }
- }
-
- return rc;
-}
-
-/*
-** Populate buffer zOut with the full canonical pathname corresponding
-** to the pathname in zPath. zOut is guaranteed to point to a buffer
-** of at least (DEVSYM_MAX_PATHNAME+1) bytes.
-*/
-static int rbuVfsFullPathname(
- sqlite3_vfs *pVfs,
- const char *zPath,
- int nOut,
- char *zOut
-){
- sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
- return pRealVfs->xFullPathname(pRealVfs, zPath, nOut, zOut);
-}
-
-#ifndef SQLITE_OMIT_LOAD_EXTENSION
-/*
-** Open the dynamic library located at zPath and return a handle.
-*/
-static void *rbuVfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
- sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
- return pRealVfs->xDlOpen(pRealVfs, zPath);
-}
-
-/*
-** Populate the buffer zErrMsg (size nByte bytes) with a human readable
-** utf-8 string describing the most recent error encountered associated
-** with dynamic libraries.
-*/
-static void rbuVfsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
- sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
- pRealVfs->xDlError(pRealVfs, nByte, zErrMsg);
-}
-
-/*
-** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
-*/
-static void (*rbuVfsDlSym(
- sqlite3_vfs *pVfs,
- void *pArg,
- const char *zSym
-))(void){
- sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
- return pRealVfs->xDlSym(pRealVfs, pArg, zSym);
-}
-
-/*
-** Close the dynamic library handle pHandle.
-*/
-static void rbuVfsDlClose(sqlite3_vfs *pVfs, void *pHandle){
- sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
- pRealVfs->xDlClose(pRealVfs, pHandle);
-}
-#endif /* SQLITE_OMIT_LOAD_EXTENSION */
-
-/*
-** Populate the buffer pointed to by zBufOut with nByte bytes of
-** random data.
-*/
-static int rbuVfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
- sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
- return pRealVfs->xRandomness(pRealVfs, nByte, zBufOut);
-}
-
-/*
-** Sleep for nMicro microseconds. Return the number of microseconds
-** actually slept.
-*/
-static int rbuVfsSleep(sqlite3_vfs *pVfs, int nMicro){
- sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
- return pRealVfs->xSleep(pRealVfs, nMicro);
-}
-
-/*
-** Return the current time as a Julian Day number in *pTimeOut.
-*/
-static int rbuVfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
- sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
- return pRealVfs->xCurrentTime(pRealVfs, pTimeOut);
-}
-
-/*
-** No-op.
-*/
-static int rbuVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){
- return 0;
-}
-
-/*
-** Deregister and destroy an RBU vfs created by an earlier call to
-** sqlite3rbu_create_vfs().
-*/
-SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName){
- sqlite3_vfs *pVfs = sqlite3_vfs_find(zName);
- if( pVfs && pVfs->xOpen==rbuVfsOpen ){
- sqlite3_mutex_free(((rbu_vfs*)pVfs)->mutex);
- sqlite3_vfs_unregister(pVfs);
- sqlite3_free(pVfs);
- }
-}
-
-/*
-** Create an RBU VFS named zName that accesses the underlying file-system
-** via existing VFS zParent. The new object is registered as a non-default
-** VFS with SQLite before returning.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const char *zParent){
-
- /* Template for VFS */
- static sqlite3_vfs vfs_template = {
- 1, /* iVersion */
- 0, /* szOsFile */
- 0, /* mxPathname */
- 0, /* pNext */
- 0, /* zName */
- 0, /* pAppData */
- rbuVfsOpen, /* xOpen */
- rbuVfsDelete, /* xDelete */
- rbuVfsAccess, /* xAccess */
- rbuVfsFullPathname, /* xFullPathname */
-
-#ifndef SQLITE_OMIT_LOAD_EXTENSION
- rbuVfsDlOpen, /* xDlOpen */
- rbuVfsDlError, /* xDlError */
- rbuVfsDlSym, /* xDlSym */
- rbuVfsDlClose, /* xDlClose */
-#else
- 0, 0, 0, 0,
-#endif
-
- rbuVfsRandomness, /* xRandomness */
- rbuVfsSleep, /* xSleep */
- rbuVfsCurrentTime, /* xCurrentTime */
- rbuVfsGetLastError, /* xGetLastError */
- 0, /* xCurrentTimeInt64 (version 2) */
- 0, 0, 0 /* Unimplemented version 3 methods */
- };
-
- rbu_vfs *pNew = 0; /* Newly allocated VFS */
- int rc = SQLITE_OK;
- size_t nName;
- size_t nByte;
-
- nName = strlen(zName);
- nByte = sizeof(rbu_vfs) + nName + 1;
- pNew = (rbu_vfs*)sqlite3_malloc64(nByte);
- if( pNew==0 ){
- rc = SQLITE_NOMEM;
- }else{
- sqlite3_vfs *pParent; /* Parent VFS */
- memset(pNew, 0, nByte);
- pParent = sqlite3_vfs_find(zParent);
- if( pParent==0 ){
- rc = SQLITE_NOTFOUND;
- }else{
- char *zSpace;
- memcpy(&pNew->base, &vfs_template, sizeof(sqlite3_vfs));
- pNew->base.mxPathname = pParent->mxPathname;
- pNew->base.szOsFile = sizeof(rbu_file) + pParent->szOsFile;
- pNew->pRealVfs = pParent;
- pNew->base.zName = (const char*)(zSpace = (char*)&pNew[1]);
- memcpy(zSpace, zName, nName);
-
- /* Allocate the mutex and register the new VFS (not as the default) */
- pNew->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE);
- if( pNew->mutex==0 ){
- rc = SQLITE_NOMEM;
- }else{
- rc = sqlite3_vfs_register(&pNew->base, 0);
- }
- }
-
- if( rc!=SQLITE_OK ){
- sqlite3_mutex_free(pNew->mutex);
- sqlite3_free(pNew);
- }
- }
-
- return rc;
-}
-
-
-/**************************************************************************/
-
-#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU) */
-
-/************** End of sqlite3rbu.c ******************************************/
/************** Begin file dbstat.c ******************************************/
/*
** 2010 July 12
@@ -168654,12 +155232,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const cha
** information from an SQLite database in order to implement the
** "sqlite3_analyzer" utility. See the ../tool/spaceanal.tcl script
** for an example implementation.
-**
-** Additional information is available on the "dbstat.html" page of the
-** official SQLite documentation.
*/
-/* #include "sqliteInt.h" ** Requires access to internal data structures ** */
#if (defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)) \
&& !defined(SQLITE_OMIT_VIRTUALTABLE)
@@ -168705,8 +155279,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const cha
" unused INTEGER, /* Bytes of unused space on this page */" \
" mx_payload INTEGER, /* Largest payload size of all cells */" \
" pgoffset INTEGER, /* Offset of page in file */" \
- " pgsize INTEGER, /* Size of the page */" \
- " schema TEXT HIDDEN /* Database schema being analyzed */" \
+ " pgsize INTEGER /* Size of the page */" \
");"
@@ -168744,7 +155317,6 @@ struct StatCursor {
sqlite3_vtab_cursor base;
sqlite3_stmt *pStmt; /* Iterates through set of root pages */
int isEof; /* After pStmt has returned SQLITE_DONE */
- int iDb; /* Schema used for this query */
StatPage aPage[32];
int iPage; /* Current entry in aPage[] */
@@ -168787,9 +155359,7 @@ static int statConnect(
int iDb;
if( argc>=4 ){
- Token nm;
- sqlite3TokenInit(&nm, (char*)argv[3]);
- iDb = sqlite3FindDb(db, &nm);
+ iDb = sqlite3FindDbName(db, argv[3]);
if( iDb<0 ){
*pzErr = sqlite3_mprintf("no such database: %s", argv[3]);
return SQLITE_ERROR;
@@ -168800,7 +155370,7 @@ static int statConnect(
rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
if( rc==SQLITE_OK ){
pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
- if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
+ if( pTab==0 ) rc = SQLITE_NOMEM;
}
assert( rc==SQLITE_OK || pTab==0 );
@@ -168824,32 +155394,9 @@ static int statDisconnect(sqlite3_vtab *pVtab){
/*
** There is no "best-index". This virtual table always does a linear
-** scan. However, a schema=? constraint should cause this table to
-** operate on a different database schema, so check for it.
-**
-** idxNum is normally 0, but will be 1 if a schema=? constraint exists.
+** scan of the binary VFS log file.
*/
static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
- int i;
-
- pIdxInfo->estimatedCost = 1.0e6; /* Initial cost estimate */
-
- /* Look for a valid schema=? constraint. If found, change the idxNum to
- ** 1 and request the value of that constraint be sent to xFilter. And
- ** lower the cost estimate to encourage the constrained version to be
- ** used.
- */
- for(i=0; i<pIdxInfo->nConstraint; i++){
- if( pIdxInfo->aConstraint[i].usable==0 ) continue;
- if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
- if( pIdxInfo->aConstraint[i].iColumn!=10 ) continue;
- pIdxInfo->idxNum = 1;
- pIdxInfo->estimatedCost = 1.0;
- pIdxInfo->aConstraintUsage[i].argvIndex = 1;
- pIdxInfo->aConstraintUsage[i].omit = 1;
- break;
- }
-
/* Records are always returned in ascending order of (name, path).
** If this will satisfy the client, set the orderByConsumed flag so that
@@ -168869,6 +155416,7 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
pIdxInfo->orderByConsumed = 1;
}
+ pIdxInfo->estimatedCost = 10.0;
return SQLITE_OK;
}
@@ -168878,18 +155426,36 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
StatTable *pTab = (StatTable *)pVTab;
StatCursor *pCsr;
+ int rc;
pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor));
if( pCsr==0 ){
- return SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM;
}else{
+ char *zSql;
memset(pCsr, 0, sizeof(StatCursor));
pCsr->base.pVtab = pVTab;
- pCsr->iDb = pTab->iDb;
+
+ zSql = sqlite3_mprintf(
+ "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
+ " UNION ALL "
+ "SELECT name, rootpage, type"
+ " FROM \"%w\".sqlite_master WHERE rootpage!=0"
+ " ORDER BY name", pTab->db->aDb[pTab->iDb].zName);
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
+ sqlite3_free(zSql);
+ }
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(pCsr);
+ pCsr = 0;
+ }
}
*ppCursor = (sqlite3_vtab_cursor *)pCsr;
- return SQLITE_OK;
+ return rc;
}
static void statClearPage(StatPage *p){
@@ -168914,7 +155480,6 @@ static void statResetCsr(StatCursor *pCsr){
pCsr->iPage = 0;
sqlite3_free(pCsr->zPath);
pCsr->zPath = 0;
- pCsr->isEof = 0;
}
/*
@@ -168987,7 +155552,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){
nUsable = szPage - sqlite3BtreeGetReserveNoMutex(pBt);
sqlite3BtreeLeave(pBt);
p->aCell = sqlite3_malloc64((p->nCell+1) * sizeof(StatCell));
- if( p->aCell==0 ) return SQLITE_NOMEM_BKPT;
+ if( p->aCell==0 ) return SQLITE_NOMEM;
memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell));
for(i=0; i<p->nCell; i++){
@@ -169020,13 +155585,13 @@ static int statDecodePage(Btree *pBt, StatPage *p){
pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
pCell->nOvfl = nOvfl;
pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
- if( pCell->aOvfl==0 ) return SQLITE_NOMEM_BKPT;
+ if( pCell->aOvfl==0 ) return SQLITE_NOMEM;
pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]);
for(j=1; j<nOvfl; j++){
int rc;
u32 iPrev = pCell->aOvfl[j-1];
DbPage *pPg = 0;
- rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPrev, &pPg, 0);
+ rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPrev, &pPg);
if( rc!=SQLITE_OK ){
assert( pPg==0 );
return rc;
@@ -169077,7 +155642,7 @@ static int statNext(sqlite3_vtab_cursor *pCursor){
char *z;
StatCursor *pCsr = (StatCursor *)pCursor;
StatTable *pTab = (StatTable *)pCursor->pVtab;
- Btree *pBt = pTab->db->aDb[pCsr->iDb].pBt;
+ Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
Pager *pPager = sqlite3BtreePager(pBt);
sqlite3_free(pCsr->zPath);
@@ -169094,12 +155659,12 @@ statNextRestart:
pCsr->isEof = 1;
return sqlite3_reset(pCsr->pStmt);
}
- rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg, 0);
+ rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg);
pCsr->aPage[0].iPgno = iRoot;
pCsr->aPage[0].iCell = 0;
pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
pCsr->iPage = 0;
- if( z==0 ) rc = SQLITE_NOMEM_BKPT;
+ if( z==0 ) rc = SQLITE_NOMEM;
}else{
pCsr->isEof = 1;
return sqlite3_reset(pCsr->pStmt);
@@ -169134,7 +155699,7 @@ statNextRestart:
}
pCell->iOvfl++;
statSizeAndOffset(pCsr);
- return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
+ return z==0 ? SQLITE_NOMEM : SQLITE_OK;
}
if( p->iRightChildPg ) break;
p->iCell++;
@@ -169154,11 +155719,11 @@ statNextRestart:
}else{
p[1].iPgno = p->aCell[p->iCell].iChildPg;
}
- rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg, 0);
+ rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg);
p[1].iCell = 0;
p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
p->iCell++;
- if( z==0 ) rc = SQLITE_NOMEM_BKPT;
+ if( z==0 ) rc = SQLITE_NOMEM;
}
@@ -169192,7 +155757,7 @@ statNextRestart:
pCsr->nUnused = p->nUnused;
pCsr->nMxPayload = p->nMxPayload;
pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
- if( z==0 ) rc = SQLITE_NOMEM_BKPT;
+ if( z==0 ) rc = SQLITE_NOMEM;
nPayload = 0;
for(i=0; i<p->nCell; i++){
nPayload += p->aCell[i].nLocal;
@@ -169215,43 +155780,9 @@ static int statFilter(
int argc, sqlite3_value **argv
){
StatCursor *pCsr = (StatCursor *)pCursor;
- StatTable *pTab = (StatTable*)(pCursor->pVtab);
- char *zSql;
- int rc = SQLITE_OK;
- char *zMaster;
- if( idxNum==1 ){
- const char *zDbase = (const char*)sqlite3_value_text(argv[0]);
- pCsr->iDb = sqlite3FindDbName(pTab->db, zDbase);
- if( pCsr->iDb<0 ){
- sqlite3_free(pCursor->pVtab->zErrMsg);
- pCursor->pVtab->zErrMsg = sqlite3_mprintf("no such schema: %s", zDbase);
- return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM_BKPT;
- }
- }else{
- pCsr->iDb = pTab->iDb;
- }
statResetCsr(pCsr);
- sqlite3_finalize(pCsr->pStmt);
- pCsr->pStmt = 0;
- zMaster = pCsr->iDb==1 ? "sqlite_temp_master" : "sqlite_master";
- zSql = sqlite3_mprintf(
- "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
- " UNION ALL "
- "SELECT name, rootpage, type"
- " FROM \"%w\".%s WHERE rootpage!=0"
- " ORDER BY name", pTab->db->aDb[pCsr->iDb].zName, zMaster);
- if( zSql==0 ){
- return SQLITE_NOMEM_BKPT;
- }else{
- rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
- sqlite3_free(zSql);
- }
-
- if( rc==SQLITE_OK ){
- rc = statNext(pCursor);
- }
- return rc;
+ return statNext(pCursor);
}
static int statColumn(
@@ -169288,15 +155819,10 @@ static int statColumn(
case 8: /* pgoffset */
sqlite3_result_int64(ctx, pCsr->iOffset);
break;
- case 9: /* pgsize */
+ default: /* pgsize */
+ assert( i==9 );
sqlite3_result_int(ctx, pCsr->szPage);
break;
- default: { /* schema */
- sqlite3 *db = sqlite3_context_db_handle(ctx);
- int iDb = pCsr->iDb;
- sqlite3_result_text(ctx, db->aDb[iDb].zName, -1, SQLITE_STATIC);
- break;
- }
}
return SQLITE_OK;
}
@@ -169310,7 +155836,7 @@ static int statRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
/*
** Invoke this routine to register the "dbstat" virtual table module
*/
-SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){
+SQLITE_API int SQLITE_STDCALL sqlite3_dbstat_register(sqlite3 *db){
static sqlite3_module dbstat_module = {
0, /* iVersion */
statConnect, /* xCreate */
@@ -169335,27508 +155861,6 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){
};
return sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
}
-#elif defined(SQLITE_ENABLE_DBSTAT_VTAB)
-SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; }
#endif /* SQLITE_ENABLE_DBSTAT_VTAB */
/************** End of dbstat.c **********************************************/
-/************** Begin file sqlite3session.c **********************************/
-
-#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
-/* #include "sqlite3session.h" */
-/* #include <assert.h> */
-/* #include <string.h> */
-
-#ifndef SQLITE_AMALGAMATION
-/* # include "sqliteInt.h" */
-/* # include "vdbeInt.h" */
-#endif
-
-typedef struct SessionTable SessionTable;
-typedef struct SessionChange SessionChange;
-typedef struct SessionBuffer SessionBuffer;
-typedef struct SessionInput SessionInput;
-
-/*
-** Minimum chunk size used by streaming versions of functions.
-*/
-#ifndef SESSIONS_STRM_CHUNK_SIZE
-# ifdef SQLITE_TEST
-# define SESSIONS_STRM_CHUNK_SIZE 64
-# else
-# define SESSIONS_STRM_CHUNK_SIZE 1024
-# endif
-#endif
-
-typedef struct SessionHook SessionHook;
-struct SessionHook {
- void *pCtx;
- int (*xOld)(void*,int,sqlite3_value**);
- int (*xNew)(void*,int,sqlite3_value**);
- int (*xCount)(void*);
- int (*xDepth)(void*);
-};
-
-/*
-** Session handle structure.
-*/
-struct sqlite3_session {
- sqlite3 *db; /* Database handle session is attached to */
- char *zDb; /* Name of database session is attached to */
- int bEnable; /* True if currently recording */
- int bIndirect; /* True if all changes are indirect */
- int bAutoAttach; /* True to auto-attach tables */
- int rc; /* Non-zero if an error has occurred */
- void *pFilterCtx; /* First argument to pass to xTableFilter */
- int (*xTableFilter)(void *pCtx, const char *zTab);
- sqlite3_session *pNext; /* Next session object on same db. */
- SessionTable *pTable; /* List of attached tables */
- SessionHook hook; /* APIs to grab new and old data with */
-};
-
-/*
-** Instances of this structure are used to build strings or binary records.
-*/
-struct SessionBuffer {
- u8 *aBuf; /* Pointer to changeset buffer */
- int nBuf; /* Size of buffer aBuf */
- int nAlloc; /* Size of allocation containing aBuf */
-};
-
-/*
-** An object of this type is used internally as an abstraction for
-** input data. Input data may be supplied either as a single large buffer
-** (e.g. sqlite3changeset_start()) or using a stream function (e.g.
-** sqlite3changeset_start_strm()).
-*/
-struct SessionInput {
- int bNoDiscard; /* If true, discard no data */
- int iCurrent; /* Offset in aData[] of current change */
- int iNext; /* Offset in aData[] of next change */
- u8 *aData; /* Pointer to buffer containing changeset */
- int nData; /* Number of bytes in aData */
-
- SessionBuffer buf; /* Current read buffer */
- int (*xInput)(void*, void*, int*); /* Input stream call (or NULL) */
- void *pIn; /* First argument to xInput */
- int bEof; /* Set to true after xInput finished */
-};
-
-/*
-** Structure for changeset iterators.
-*/
-struct sqlite3_changeset_iter {
- SessionInput in; /* Input buffer or stream */
- SessionBuffer tblhdr; /* Buffer to hold apValue/zTab/abPK/ */
- int bPatchset; /* True if this is a patchset */
- int rc; /* Iterator error code */
- sqlite3_stmt *pConflict; /* Points to conflicting row, if any */
- char *zTab; /* Current table */
- int nCol; /* Number of columns in zTab */
- int op; /* Current operation */
- int bIndirect; /* True if current change was indirect */
- u8 *abPK; /* Primary key array */
- sqlite3_value **apValue; /* old.* and new.* values */
-};
-
-/*
-** Each session object maintains a set of the following structures, one
-** for each table the session object is monitoring. The structures are
-** stored in a linked list starting at sqlite3_session.pTable.
-**
-** The keys of the SessionTable.aChange[] hash table are all rows that have
-** been modified in any way since the session object was attached to the
-** table.
-**
-** The data associated with each hash-table entry is a structure containing
-** a subset of the initial values that the modified row contained at the
-** start of the session. Or no initial values if the row was inserted.
-*/
-struct SessionTable {
- SessionTable *pNext;
- char *zName; /* Local name of table */
- int nCol; /* Number of columns in table zName */
- const char **azCol; /* Column names */
- u8 *abPK; /* Array of primary key flags */
- int nEntry; /* Total number of entries in hash table */
- int nChange; /* Size of apChange[] array */
- SessionChange **apChange; /* Hash table buckets */
-};
-
-/*
-** RECORD FORMAT:
-**
-** The following record format is similar to (but not compatible with) that
-** used in SQLite database files. This format is used as part of the
-** change-set binary format, and so must be architecture independent.
-**
-** Unlike the SQLite database record format, each field is self-contained -
-** there is no separation of header and data. Each field begins with a
-** single byte describing its type, as follows:
-**
-** 0x00: Undefined value.
-** 0x01: Integer value.
-** 0x02: Real value.
-** 0x03: Text value.
-** 0x04: Blob value.
-** 0x05: SQL NULL value.
-**
-** Note that the above match the definitions of SQLITE_INTEGER, SQLITE_TEXT
-** and so on in sqlite3.h. For undefined and NULL values, the field consists
-** only of the single type byte. For other types of values, the type byte
-** is followed by:
-**
-** Text values:
-** A varint containing the number of bytes in the value (encoded using
-** UTF-8). Followed by a buffer containing the UTF-8 representation
-** of the text value. There is no nul terminator.
-**
-** Blob values:
-** A varint containing the number of bytes in the value, followed by
-** a buffer containing the value itself.
-**
-** Integer values:
-** An 8-byte big-endian integer value.
-**
-** Real values:
-** An 8-byte big-endian IEEE 754-2008 real value.
-**
-** Varint values are encoded in the same way as varints in the SQLite
-** record format.
-**
-** CHANGESET FORMAT:
-**
-** A changeset is a collection of DELETE, UPDATE and INSERT operations on
-** one or more tables. Operations on a single table are grouped together,
-** but may occur in any order (i.e. deletes, updates and inserts are all
-** mixed together).
-**
-** Each group of changes begins with a table header:
-**
-** 1 byte: Constant 0x54 (capital 'T')
-** Varint: Number of columns in the table.
-** nCol bytes: 0x01 for PK columns, 0x00 otherwise.
-** N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated.
-**
-** Followed by one or more changes to the table.
-**
-** 1 byte: Either SQLITE_INSERT (0x12), UPDATE (0x17) or DELETE (0x09).
-** 1 byte: The "indirect-change" flag.
-** old.* record: (delete and update only)
-** new.* record: (insert and update only)
-**
-** The "old.*" and "new.*" records, if present, are N field records in the
-** format described above under "RECORD FORMAT", where N is the number of
-** columns in the table. The i'th field of each record is associated with
-** the i'th column of the table, counting from left to right in the order
-** in which columns were declared in the CREATE TABLE statement.
-**
-** The new.* record that is part of each INSERT change contains the values
-** that make up the new row. Similarly, the old.* record that is part of each
-** DELETE change contains the values that made up the row that was deleted
-** from the database. In the changeset format, the records that are part
-** of INSERT or DELETE changes never contain any undefined (type byte 0x00)
-** fields.
-**
-** Within the old.* record associated with an UPDATE change, all fields
-** associated with table columns that are not PRIMARY KEY columns and are
-** not modified by the UPDATE change are set to "undefined". Other fields
-** are set to the values that made up the row before the UPDATE that the
-** change records took place. Within the new.* record, fields associated
-** with table columns modified by the UPDATE change contain the new
-** values. Fields associated with table columns that are not modified
-** are set to "undefined".
-**
-** PATCHSET FORMAT:
-**
-** A patchset is also a collection of changes. It is similar to a changeset,
-** but leaves undefined those fields that are not useful if no conflict
-** resolution is required when applying the changeset.
-**
-** Each group of changes begins with a table header:
-**
-** 1 byte: Constant 0x50 (capital 'P')
-** Varint: Number of columns in the table.
-** nCol bytes: 0x01 for PK columns, 0x00 otherwise.
-** N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated.
-**
-** Followed by one or more changes to the table.
-**
-** 1 byte: Either SQLITE_INSERT (0x12), UPDATE (0x17) or DELETE (0x09).
-** 1 byte: The "indirect-change" flag.
-** single record: (PK fields for DELETE, PK and modified fields for UPDATE,
-** full record for INSERT).
-**
-** As in the changeset format, each field of the single record that is part
-** of a patchset change is associated with the correspondingly positioned
-** table column, counting from left to right within the CREATE TABLE
-** statement.
-**
-** For a DELETE change, all fields within the record except those associated
-** with PRIMARY KEY columns are set to "undefined". The PRIMARY KEY fields
-** contain the values identifying the row to delete.
-**
-** For an UPDATE change, all fields except those associated with PRIMARY KEY
-** columns and columns that are modified by the UPDATE are set to "undefined".
-** PRIMARY KEY fields contain the values identifying the table row to update,
-** and fields associated with modified columns contain the new column values.
-**
-** The records associated with INSERT changes are in the same format as for
-** changesets. It is not possible for a record associated with an INSERT
-** change to contain a field set to "undefined".
-*/
-
-/*
-** For each row modified during a session, there exists a single instance of
-** this structure stored in a SessionTable.aChange[] hash table.
-*/
-struct SessionChange {
- int op; /* One of UPDATE, DELETE, INSERT */
- int bIndirect; /* True if this change is "indirect" */
- int nRecord; /* Number of bytes in buffer aRecord[] */
- u8 *aRecord; /* Buffer containing old.* record */
- SessionChange *pNext; /* For hash-table collisions */
-};
-
-/*
-** Write a varint with value iVal into the buffer at aBuf. Return the
-** number of bytes written.
-*/
-static int sessionVarintPut(u8 *aBuf, int iVal){
- return putVarint32(aBuf, iVal);
-}
-
-/*
-** Return the number of bytes required to store value iVal as a varint.
-*/
-static int sessionVarintLen(int iVal){
- return sqlite3VarintLen(iVal);
-}
-
-/*
-** Read a varint value from aBuf[] into *piVal. Return the number of
-** bytes read.
-*/
-static int sessionVarintGet(u8 *aBuf, int *piVal){
- return getVarint32(aBuf, *piVal);
-}
-
-/* Load an unaligned and unsigned 32-bit integer */
-#define SESSION_UINT32(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3])
-
-/*
-** Read a 64-bit big-endian integer value from buffer aRec[]. Return
-** the value read.
-*/
-static sqlite3_int64 sessionGetI64(u8 *aRec){
- u64 x = SESSION_UINT32(aRec);
- u32 y = SESSION_UINT32(aRec+4);
- x = (x<<32) + y;
- return (sqlite3_int64)x;
-}
-
-/*
-** Write a 64-bit big-endian integer value to the buffer aBuf[].
-*/
-static void sessionPutI64(u8 *aBuf, sqlite3_int64 i){
- aBuf[0] = (i>>56) & 0xFF;
- aBuf[1] = (i>>48) & 0xFF;
- aBuf[2] = (i>>40) & 0xFF;
- aBuf[3] = (i>>32) & 0xFF;
- aBuf[4] = (i>>24) & 0xFF;
- aBuf[5] = (i>>16) & 0xFF;
- aBuf[6] = (i>> 8) & 0xFF;
- aBuf[7] = (i>> 0) & 0xFF;
-}
-
-/*
-** This function is used to serialize the contents of value pValue (see
-** comment titled "RECORD FORMAT" above).
-**
-** If it is non-NULL, the serialized form of the value is written to
-** buffer aBuf. *pnWrite is set to the number of bytes written before
-** returning. Or, if aBuf is NULL, the only thing this function does is
-** set *pnWrite.
-**
-** If no error occurs, SQLITE_OK is returned. Or, if an OOM error occurs
-** within a call to sqlite3_value_text() (may fail if the db is utf-16))
-** SQLITE_NOMEM is returned.
-*/
-static int sessionSerializeValue(
- u8 *aBuf, /* If non-NULL, write serialized value here */
- sqlite3_value *pValue, /* Value to serialize */
- int *pnWrite /* IN/OUT: Increment by bytes written */
-){
- int nByte; /* Size of serialized value in bytes */
-
- if( pValue ){
- int eType; /* Value type (SQLITE_NULL, TEXT etc.) */
-
- eType = sqlite3_value_type(pValue);
- if( aBuf ) aBuf[0] = eType;
-
- switch( eType ){
- case SQLITE_NULL:
- nByte = 1;
- break;
-
- case SQLITE_INTEGER:
- case SQLITE_FLOAT:
- if( aBuf ){
- /* TODO: SQLite does something special to deal with mixed-endian
- ** floating point values (e.g. ARM7). This code probably should
- ** too. */
- u64 i;
- if( eType==SQLITE_INTEGER ){
- i = (u64)sqlite3_value_int64(pValue);
- }else{
- double r;
- assert( sizeof(double)==8 && sizeof(u64)==8 );
- r = sqlite3_value_double(pValue);
- memcpy(&i, &r, 8);
- }
- sessionPutI64(&aBuf[1], i);
- }
- nByte = 9;
- break;
-
- default: {
- u8 *z;
- int n;
- int nVarint;
-
- assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
- if( eType==SQLITE_TEXT ){
- z = (u8 *)sqlite3_value_text(pValue);
- }else{
- z = (u8 *)sqlite3_value_blob(pValue);
- }
- n = sqlite3_value_bytes(pValue);
- if( z==0 && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
- nVarint = sessionVarintLen(n);
-
- if( aBuf ){
- sessionVarintPut(&aBuf[1], n);
- memcpy(&aBuf[nVarint + 1], eType==SQLITE_TEXT ?
- sqlite3_value_text(pValue) : sqlite3_value_blob(pValue), n
- );
- }
-
- nByte = 1 + nVarint + n;
- break;
- }
- }
- }else{
- nByte = 1;
- if( aBuf ) aBuf[0] = '\0';
- }
-
- if( pnWrite ) *pnWrite += nByte;
- return SQLITE_OK;
-}
-
-
-/*
-** This macro is used to calculate hash key values for data structures. In
-** order to use this macro, the entire data structure must be represented
-** as a series of unsigned integers. In order to calculate a hash-key value
-** for a data structure represented as three such integers, the macro may
-** then be used as follows:
-**
-** int hash_key_value;
-** hash_key_value = HASH_APPEND(0, <value 1>);
-** hash_key_value = HASH_APPEND(hash_key_value, <value 2>);
-** hash_key_value = HASH_APPEND(hash_key_value, <value 3>);
-**
-** In practice, the data structures this macro is used for are the primary
-** key values of modified rows.
-*/
-#define HASH_APPEND(hash, add) ((hash) << 3) ^ (hash) ^ (unsigned int)(add)
-
-/*
-** Append the hash of the 64-bit integer passed as the second argument to the
-** hash-key value passed as the first. Return the new hash-key value.
-*/
-static unsigned int sessionHashAppendI64(unsigned int h, i64 i){
- h = HASH_APPEND(h, i & 0xFFFFFFFF);
- return HASH_APPEND(h, (i>>32)&0xFFFFFFFF);
-}
-
-/*
-** Append the hash of the blob passed via the second and third arguments to
-** the hash-key value passed as the first. Return the new hash-key value.
-*/
-static unsigned int sessionHashAppendBlob(unsigned int h, int n, const u8 *z){
- int i;
- for(i=0; i<n; i++) h = HASH_APPEND(h, z[i]);
- return h;
-}
-
-/*
-** Append the hash of the data type passed as the second argument to the
-** hash-key value passed as the first. Return the new hash-key value.
-*/
-static unsigned int sessionHashAppendType(unsigned int h, int eType){
- return HASH_APPEND(h, eType);
-}
-
-/*
-** This function may only be called from within a pre-update callback.
-** It calculates a hash based on the primary key values of the old.* or
-** new.* row currently available and, assuming no error occurs, writes it to
-** *piHash before returning. If the primary key contains one or more NULL
-** values, *pbNullPK is set to true before returning.
-**
-** If an error occurs, an SQLite error code is returned and the final values
-** of *piHash asn *pbNullPK are undefined. Otherwise, SQLITE_OK is returned
-** and the output variables are set as described above.
-*/
-static int sessionPreupdateHash(
- sqlite3_session *pSession, /* Session object that owns pTab */
- SessionTable *pTab, /* Session table handle */
- int bNew, /* True to hash the new.* PK */
- int *piHash, /* OUT: Hash value */
- int *pbNullPK /* OUT: True if there are NULL values in PK */
-){
- unsigned int h = 0; /* Hash value to return */
- int i; /* Used to iterate through columns */
-
- assert( *pbNullPK==0 );
- assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) );
- for(i=0; i<pTab->nCol; i++){
- if( pTab->abPK[i] ){
- int rc;
- int eType;
- sqlite3_value *pVal;
-
- if( bNew ){
- rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal);
- }else{
- rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal);
- }
- if( rc!=SQLITE_OK ) return rc;
-
- eType = sqlite3_value_type(pVal);
- h = sessionHashAppendType(h, eType);
- if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
- i64 iVal;
- if( eType==SQLITE_INTEGER ){
- iVal = sqlite3_value_int64(pVal);
- }else{
- double rVal = sqlite3_value_double(pVal);
- assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
- memcpy(&iVal, &rVal, 8);
- }
- h = sessionHashAppendI64(h, iVal);
- }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
- const u8 *z;
- int n;
- if( eType==SQLITE_TEXT ){
- z = (const u8 *)sqlite3_value_text(pVal);
- }else{
- z = (const u8 *)sqlite3_value_blob(pVal);
- }
- n = sqlite3_value_bytes(pVal);
- if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
- h = sessionHashAppendBlob(h, n, z);
- }else{
- assert( eType==SQLITE_NULL );
- *pbNullPK = 1;
- }
- }
- }
-
- *piHash = (h % pTab->nChange);
- return SQLITE_OK;
-}
-
-/*
-** The buffer that the argument points to contains a serialized SQL value.
-** Return the number of bytes of space occupied by the value (including
-** the type byte).
-*/
-static int sessionSerialLen(u8 *a){
- int e = *a;
- int n;
- if( e==0 ) return 1;
- if( e==SQLITE_NULL ) return 1;
- if( e==SQLITE_INTEGER || e==SQLITE_FLOAT ) return 9;
- return sessionVarintGet(&a[1], &n) + 1 + n;
-}
-
-/*
-** Based on the primary key values stored in change aRecord, calculate a
-** hash key. Assume the has table has nBucket buckets. The hash keys
-** calculated by this function are compatible with those calculated by
-** sessionPreupdateHash().
-**
-** The bPkOnly argument is non-zero if the record at aRecord[] is from
-** a patchset DELETE. In this case the non-PK fields are omitted entirely.
-*/
-static unsigned int sessionChangeHash(
- SessionTable *pTab, /* Table handle */
- int bPkOnly, /* Record consists of PK fields only */
- u8 *aRecord, /* Change record */
- int nBucket /* Assume this many buckets in hash table */
-){
- unsigned int h = 0; /* Value to return */
- int i; /* Used to iterate through columns */
- u8 *a = aRecord; /* Used to iterate through change record */
-
- for(i=0; i<pTab->nCol; i++){
- int eType = *a;
- int isPK = pTab->abPK[i];
- if( bPkOnly && isPK==0 ) continue;
-
- /* It is not possible for eType to be SQLITE_NULL here. The session
- ** module does not record changes for rows with NULL values stored in
- ** primary key columns. */
- assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
- || eType==SQLITE_TEXT || eType==SQLITE_BLOB
- || eType==SQLITE_NULL || eType==0
- );
- assert( !isPK || (eType!=0 && eType!=SQLITE_NULL) );
-
- if( isPK ){
- a++;
- h = sessionHashAppendType(h, eType);
- if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
- h = sessionHashAppendI64(h, sessionGetI64(a));
- a += 8;
- }else{
- int n;
- a += sessionVarintGet(a, &n);
- h = sessionHashAppendBlob(h, n, a);
- a += n;
- }
- }else{
- a += sessionSerialLen(a);
- }
- }
- return (h % nBucket);
-}
-
-/*
-** Arguments aLeft and aRight are pointers to change records for table pTab.
-** This function returns true if the two records apply to the same row (i.e.
-** have the same values stored in the primary key columns), or false
-** otherwise.
-*/
-static int sessionChangeEqual(
- SessionTable *pTab, /* Table used for PK definition */
- int bLeftPkOnly, /* True if aLeft[] contains PK fields only */
- u8 *aLeft, /* Change record */
- int bRightPkOnly, /* True if aRight[] contains PK fields only */
- u8 *aRight /* Change record */
-){
- u8 *a1 = aLeft; /* Cursor to iterate through aLeft */
- u8 *a2 = aRight; /* Cursor to iterate through aRight */
- int iCol; /* Used to iterate through table columns */
-
- for(iCol=0; iCol<pTab->nCol; iCol++){
- if( pTab->abPK[iCol] ){
- int n1 = sessionSerialLen(a1);
- int n2 = sessionSerialLen(a2);
-
- if( pTab->abPK[iCol] && (n1!=n2 || memcmp(a1, a2, n1)) ){
- return 0;
- }
- a1 += n1;
- a2 += n2;
- }else{
- if( bLeftPkOnly==0 ) a1 += sessionSerialLen(a1);
- if( bRightPkOnly==0 ) a2 += sessionSerialLen(a2);
- }
- }
-
- return 1;
-}
-
-/*
-** Arguments aLeft and aRight both point to buffers containing change
-** records with nCol columns. This function "merges" the two records into
-** a single records which is written to the buffer at *paOut. *paOut is
-** then set to point to one byte after the last byte written before
-** returning.
-**
-** The merging of records is done as follows: For each column, if the
-** aRight record contains a value for the column, copy the value from
-** their. Otherwise, if aLeft contains a value, copy it. If neither
-** record contains a value for a given column, then neither does the
-** output record.
-*/
-static void sessionMergeRecord(
- u8 **paOut,
- int nCol,
- u8 *aLeft,
- u8 *aRight
-){
- u8 *a1 = aLeft; /* Cursor used to iterate through aLeft */
- u8 *a2 = aRight; /* Cursor used to iterate through aRight */
- u8 *aOut = *paOut; /* Output cursor */
- int iCol; /* Used to iterate from 0 to nCol */
-
- for(iCol=0; iCol<nCol; iCol++){
- int n1 = sessionSerialLen(a1);
- int n2 = sessionSerialLen(a2);
- if( *a2 ){
- memcpy(aOut, a2, n2);
- aOut += n2;
- }else{
- memcpy(aOut, a1, n1);
- aOut += n1;
- }
- a1 += n1;
- a2 += n2;
- }
-
- *paOut = aOut;
-}
-
-/*
-** This is a helper function used by sessionMergeUpdate().
-**
-** When this function is called, both *paOne and *paTwo point to a value
-** within a change record. Before it returns, both have been advanced so
-** as to point to the next value in the record.
-**
-** If, when this function is called, *paTwo points to a valid value (i.e.
-** *paTwo[0] is not 0x00 - the "no value" placeholder), a copy of the *paTwo
-** pointer is returned and *pnVal is set to the number of bytes in the
-** serialized value. Otherwise, a copy of *paOne is returned and *pnVal
-** set to the number of bytes in the value at *paOne. If *paOne points
-** to the "no value" placeholder, *pnVal is set to 1. In other words:
-**
-** if( *paTwo is valid ) return *paTwo;
-** return *paOne;
-**
-*/
-static u8 *sessionMergeValue(
- u8 **paOne, /* IN/OUT: Left-hand buffer pointer */
- u8 **paTwo, /* IN/OUT: Right-hand buffer pointer */
- int *pnVal /* OUT: Bytes in returned value */
-){
- u8 *a1 = *paOne;
- u8 *a2 = *paTwo;
- u8 *pRet = 0;
- int n1;
-
- assert( a1 );
- if( a2 ){
- int n2 = sessionSerialLen(a2);
- if( *a2 ){
- *pnVal = n2;
- pRet = a2;
- }
- *paTwo = &a2[n2];
- }
-
- n1 = sessionSerialLen(a1);
- if( pRet==0 ){
- *pnVal = n1;
- pRet = a1;
- }
- *paOne = &a1[n1];
-
- return pRet;
-}
-
-/*
-** This function is used by changeset_concat() to merge two UPDATE changes
-** on the same row.
-*/
-static int sessionMergeUpdate(
- u8 **paOut, /* IN/OUT: Pointer to output buffer */
- SessionTable *pTab, /* Table change pertains to */
- int bPatchset, /* True if records are patchset records */
- u8 *aOldRecord1, /* old.* record for first change */
- u8 *aOldRecord2, /* old.* record for second change */
- u8 *aNewRecord1, /* new.* record for first change */
- u8 *aNewRecord2 /* new.* record for second change */
-){
- u8 *aOld1 = aOldRecord1;
- u8 *aOld2 = aOldRecord2;
- u8 *aNew1 = aNewRecord1;
- u8 *aNew2 = aNewRecord2;
-
- u8 *aOut = *paOut;
- int i;
-
- if( bPatchset==0 ){
- int bRequired = 0;
-
- assert( aOldRecord1 && aNewRecord1 );
-
- /* Write the old.* vector first. */
- for(i=0; i<pTab->nCol; i++){
- int nOld;
- u8 *aOld;
- int nNew;
- u8 *aNew;
-
- aOld = sessionMergeValue(&aOld1, &aOld2, &nOld);
- aNew = sessionMergeValue(&aNew1, &aNew2, &nNew);
- if( pTab->abPK[i] || nOld!=nNew || memcmp(aOld, aNew, nNew) ){
- if( pTab->abPK[i]==0 ) bRequired = 1;
- memcpy(aOut, aOld, nOld);
- aOut += nOld;
- }else{
- *(aOut++) = '\0';
- }
- }
-
- if( !bRequired ) return 0;
- }
-
- /* Write the new.* vector */
- aOld1 = aOldRecord1;
- aOld2 = aOldRecord2;
- aNew1 = aNewRecord1;
- aNew2 = aNewRecord2;
- for(i=0; i<pTab->nCol; i++){
- int nOld;
- u8 *aOld;
- int nNew;
- u8 *aNew;
-
- aOld = sessionMergeValue(&aOld1, &aOld2, &nOld);
- aNew = sessionMergeValue(&aNew1, &aNew2, &nNew);
- if( bPatchset==0
- && (pTab->abPK[i] || (nOld==nNew && 0==memcmp(aOld, aNew, nNew)))
- ){
- *(aOut++) = '\0';
- }else{
- memcpy(aOut, aNew, nNew);
- aOut += nNew;
- }
- }
-
- *paOut = aOut;
- return 1;
-}
-
-/*
-** This function is only called from within a pre-update-hook callback.
-** It determines if the current pre-update-hook change affects the same row
-** as the change stored in argument pChange. If so, it returns true. Otherwise
-** if the pre-update-hook does not affect the same row as pChange, it returns
-** false.
-*/
-static int sessionPreupdateEqual(
- sqlite3_session *pSession, /* Session object that owns SessionTable */
- SessionTable *pTab, /* Table associated with change */
- SessionChange *pChange, /* Change to compare to */
- int op /* Current pre-update operation */
-){
- int iCol; /* Used to iterate through columns */
- u8 *a = pChange->aRecord; /* Cursor used to scan change record */
-
- assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE );
- for(iCol=0; iCol<pTab->nCol; iCol++){
- if( !pTab->abPK[iCol] ){
- a += sessionSerialLen(a);
- }else{
- sqlite3_value *pVal; /* Value returned by preupdate_new/old */
- int rc; /* Error code from preupdate_new/old */
- int eType = *a++; /* Type of value from change record */
-
- /* The following calls to preupdate_new() and preupdate_old() can not
- ** fail. This is because they cache their return values, and by the
- ** time control flows to here they have already been called once from
- ** within sessionPreupdateHash(). The first two asserts below verify
- ** this (that the method has already been called). */
- if( op==SQLITE_INSERT ){
- /* assert( db->pPreUpdate->pNewUnpacked || db->pPreUpdate->aNew ); */
- rc = pSession->hook.xNew(pSession->hook.pCtx, iCol, &pVal);
- }else{
- /* assert( db->pPreUpdate->pUnpacked ); */
- rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal);
- }
- assert( rc==SQLITE_OK );
- if( sqlite3_value_type(pVal)!=eType ) return 0;
-
- /* A SessionChange object never has a NULL value in a PK column */
- assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
- || eType==SQLITE_BLOB || eType==SQLITE_TEXT
- );
-
- if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
- i64 iVal = sessionGetI64(a);
- a += 8;
- if( eType==SQLITE_INTEGER ){
- if( sqlite3_value_int64(pVal)!=iVal ) return 0;
- }else{
- double rVal;
- assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
- memcpy(&rVal, &iVal, 8);
- if( sqlite3_value_double(pVal)!=rVal ) return 0;
- }
- }else{
- int n;
- const u8 *z;
- a += sessionVarintGet(a, &n);
- if( sqlite3_value_bytes(pVal)!=n ) return 0;
- if( eType==SQLITE_TEXT ){
- z = sqlite3_value_text(pVal);
- }else{
- z = sqlite3_value_blob(pVal);
- }
- if( memcmp(a, z, n) ) return 0;
- a += n;
- break;
- }
- }
- }
-
- return 1;
-}
-
-/*
-** If required, grow the hash table used to store changes on table pTab
-** (part of the session pSession). If a fatal OOM error occurs, set the
-** session object to failed and return SQLITE_ERROR. Otherwise, return
-** SQLITE_OK.
-**
-** It is possible that a non-fatal OOM error occurs in this function. In
-** that case the hash-table does not grow, but SQLITE_OK is returned anyway.
-** Growing the hash table in this case is a performance optimization only,
-** it is not required for correct operation.
-*/
-static int sessionGrowHash(int bPatchset, SessionTable *pTab){
- if( pTab->nChange==0 || pTab->nEntry>=(pTab->nChange/2) ){
- int i;
- SessionChange **apNew;
- int nNew = (pTab->nChange ? pTab->nChange : 128) * 2;
-
- apNew = (SessionChange **)sqlite3_malloc(sizeof(SessionChange *) * nNew);
- if( apNew==0 ){
- if( pTab->nChange==0 ){
- return SQLITE_ERROR;
- }
- return SQLITE_OK;
- }
- memset(apNew, 0, sizeof(SessionChange *) * nNew);
-
- for(i=0; i<pTab->nChange; i++){
- SessionChange *p;
- SessionChange *pNext;
- for(p=pTab->apChange[i]; p; p=pNext){
- int bPkOnly = (p->op==SQLITE_DELETE && bPatchset);
- int iHash = sessionChangeHash(pTab, bPkOnly, p->aRecord, nNew);
- pNext = p->pNext;
- p->pNext = apNew[iHash];
- apNew[iHash] = p;
- }
- }
-
- sqlite3_free(pTab->apChange);
- pTab->nChange = nNew;
- pTab->apChange = apNew;
- }
-
- return SQLITE_OK;
-}
-
-/*
-** This function queries the database for the names of the columns of table
-** zThis, in schema zDb. It is expected that the table has nCol columns. If
-** not, SQLITE_SCHEMA is returned and none of the output variables are
-** populated.
-**
-** Otherwise, if they are not NULL, variable *pnCol is set to the number
-** of columns in the database table and variable *pzTab is set to point to a
-** nul-terminated copy of the table name. *pazCol (if not NULL) is set to
-** point to an array of pointers to column names. And *pabPK (again, if not
-** NULL) is set to point to an array of booleans - true if the corresponding
-** column is part of the primary key.
-**
-** For example, if the table is declared as:
-**
-** CREATE TABLE tbl1(w, x, y, z, PRIMARY KEY(w, z));
-**
-** Then the four output variables are populated as follows:
-**
-** *pnCol = 4
-** *pzTab = "tbl1"
-** *pazCol = {"w", "x", "y", "z"}
-** *pabPK = {1, 0, 0, 1}
-**
-** All returned buffers are part of the same single allocation, which must
-** be freed using sqlite3_free() by the caller. If pazCol was not NULL, then
-** pointer *pazCol should be freed to release all memory. Otherwise, pointer
-** *pabPK. It is illegal for both pazCol and pabPK to be NULL.
-*/
-static int sessionTableInfo(
- sqlite3 *db, /* Database connection */
- const char *zDb, /* Name of attached database (e.g. "main") */
- const char *zThis, /* Table name */
- int *pnCol, /* OUT: number of columns */
- const char **pzTab, /* OUT: Copy of zThis */
- const char ***pazCol, /* OUT: Array of column names for table */
- u8 **pabPK /* OUT: Array of booleans - true for PK col */
-){
- char *zPragma;
- sqlite3_stmt *pStmt;
- int rc;
- int nByte;
- int nDbCol = 0;
- int nThis;
- int i;
- u8 *pAlloc = 0;
- char **azCol = 0;
- u8 *abPK = 0;
-
- assert( pazCol && pabPK );
-
- nThis = sqlite3Strlen30(zThis);
- zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
- if( !zPragma ) return SQLITE_NOMEM;
-
- rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
- sqlite3_free(zPragma);
- if( rc!=SQLITE_OK ) return rc;
-
- nByte = nThis + 1;
- while( SQLITE_ROW==sqlite3_step(pStmt) ){
- nByte += sqlite3_column_bytes(pStmt, 1);
- nDbCol++;
- }
- rc = sqlite3_reset(pStmt);
-
- if( rc==SQLITE_OK ){
- nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
- pAlloc = sqlite3_malloc(nByte);
- if( pAlloc==0 ){
- rc = SQLITE_NOMEM;
- }
- }
- if( rc==SQLITE_OK ){
- azCol = (char **)pAlloc;
- pAlloc = (u8 *)&azCol[nDbCol];
- abPK = (u8 *)pAlloc;
- pAlloc = &abPK[nDbCol];
- if( pzTab ){
- memcpy(pAlloc, zThis, nThis+1);
- *pzTab = (char *)pAlloc;
- pAlloc += nThis+1;
- }
-
- i = 0;
- while( SQLITE_ROW==sqlite3_step(pStmt) ){
- int nName = sqlite3_column_bytes(pStmt, 1);
- const unsigned char *zName = sqlite3_column_text(pStmt, 1);
- if( zName==0 ) break;
- memcpy(pAlloc, zName, nName+1);
- azCol[i] = (char *)pAlloc;
- pAlloc += nName+1;
- abPK[i] = sqlite3_column_int(pStmt, 5);
- i++;
- }
- rc = sqlite3_reset(pStmt);
-
- }
-
- /* If successful, populate the output variables. Otherwise, zero them and
- ** free any allocation made. An error code will be returned in this case.
- */
- if( rc==SQLITE_OK ){
- *pazCol = (const char **)azCol;
- *pabPK = abPK;
- *pnCol = nDbCol;
- }else{
- *pazCol = 0;
- *pabPK = 0;
- *pnCol = 0;
- if( pzTab ) *pzTab = 0;
- sqlite3_free(azCol);
- }
- sqlite3_finalize(pStmt);
- return rc;
-}
-
-/*
-** This function is only called from within a pre-update handler for a
-** write to table pTab, part of session pSession. If this is the first
-** write to this table, initalize the SessionTable.nCol, azCol[] and
-** abPK[] arrays accordingly.
-**
-** If an error occurs, an error code is stored in sqlite3_session.rc and
-** non-zero returned. Or, if no error occurs but the table has no primary
-** key, sqlite3_session.rc is left set to SQLITE_OK and non-zero returned to
-** indicate that updates on this table should be ignored. SessionTable.abPK
-** is set to NULL in this case.
-*/
-static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
- if( pTab->nCol==0 ){
- u8 *abPK;
- assert( pTab->azCol==0 || pTab->abPK==0 );
- pSession->rc = sessionTableInfo(pSession->db, pSession->zDb,
- pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK
- );
- if( pSession->rc==SQLITE_OK ){
- int i;
- for(i=0; i<pTab->nCol; i++){
- if( abPK[i] ){
- pTab->abPK = abPK;
- break;
- }
- }
- }
- }
- return (pSession->rc || pTab->abPK==0);
-}
-
-/*
-** This function is only called from with a pre-update-hook reporting a
-** change on table pTab (attached to session pSession). The type of change
-** (UPDATE, INSERT, DELETE) is specified by the first argument.
-**
-** Unless one is already present or an error occurs, an entry is added
-** to the changed-rows hash table associated with table pTab.
-*/
-static void sessionPreupdateOneChange(
- int op, /* One of SQLITE_UPDATE, INSERT, DELETE */
- sqlite3_session *pSession, /* Session object pTab is attached to */
- SessionTable *pTab /* Table that change applies to */
-){
- int iHash;
- int bNull = 0;
- int rc = SQLITE_OK;
-
- if( pSession->rc ) return;
-
- /* Load table details if required */
- if( sessionInitTable(pSession, pTab) ) return;
-
- /* Check the number of columns in this xPreUpdate call matches the
- ** number of columns in the table. */
- if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){
- pSession->rc = SQLITE_SCHEMA;
- return;
- }
-
- /* Grow the hash table if required */
- if( sessionGrowHash(0, pTab) ){
- pSession->rc = SQLITE_NOMEM;
- return;
- }
-
- /* Calculate the hash-key for this change. If the primary key of the row
- ** includes a NULL value, exit early. Such changes are ignored by the
- ** session module. */
- rc = sessionPreupdateHash(pSession, pTab, op==SQLITE_INSERT, &iHash, &bNull);
- if( rc!=SQLITE_OK ) goto error_out;
-
- if( bNull==0 ){
- /* Search the hash table for an existing record for this row. */
- SessionChange *pC;
- for(pC=pTab->apChange[iHash]; pC; pC=pC->pNext){
- if( sessionPreupdateEqual(pSession, pTab, pC, op) ) break;
- }
-
- if( pC==0 ){
- /* Create a new change object containing all the old values (if
- ** this is an SQLITE_UPDATE or SQLITE_DELETE), or just the PK
- ** values (if this is an INSERT). */
- SessionChange *pChange; /* New change object */
- int nByte; /* Number of bytes to allocate */
- int i; /* Used to iterate through columns */
-
- assert( rc==SQLITE_OK );
- pTab->nEntry++;
-
- /* Figure out how large an allocation is required */
- nByte = sizeof(SessionChange);
- for(i=0; i<pTab->nCol; i++){
- sqlite3_value *p = 0;
- if( op!=SQLITE_INSERT ){
- TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p);
- assert( trc==SQLITE_OK );
- }else if( pTab->abPK[i] ){
- TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p);
- assert( trc==SQLITE_OK );
- }
-
- /* This may fail if SQLite value p contains a utf-16 string that must
- ** be converted to utf-8 and an OOM error occurs while doing so. */
- rc = sessionSerializeValue(0, p, &nByte);
- if( rc!=SQLITE_OK ) goto error_out;
- }
-
- /* Allocate the change object */
- pChange = (SessionChange *)sqlite3_malloc(nByte);
- if( !pChange ){
- rc = SQLITE_NOMEM;
- goto error_out;
- }else{
- memset(pChange, 0, sizeof(SessionChange));
- pChange->aRecord = (u8 *)&pChange[1];
- }
-
- /* Populate the change object. None of the preupdate_old(),
- ** preupdate_new() or SerializeValue() calls below may fail as all
- ** required values and encodings have already been cached in memory.
- ** It is not possible for an OOM to occur in this block. */
- nByte = 0;
- for(i=0; i<pTab->nCol; i++){
- sqlite3_value *p = 0;
- if( op!=SQLITE_INSERT ){
- pSession->hook.xOld(pSession->hook.pCtx, i, &p);
- }else if( pTab->abPK[i] ){
- pSession->hook.xNew(pSession->hook.pCtx, i, &p);
- }
- sessionSerializeValue(&pChange->aRecord[nByte], p, &nByte);
- }
-
- /* Add the change to the hash-table */
- if( pSession->bIndirect || pSession->hook.xDepth(pSession->hook.pCtx) ){
- pChange->bIndirect = 1;
- }
- pChange->nRecord = nByte;
- pChange->op = op;
- pChange->pNext = pTab->apChange[iHash];
- pTab->apChange[iHash] = pChange;
-
- }else if( pC->bIndirect ){
- /* If the existing change is considered "indirect", but this current
- ** change is "direct", mark the change object as direct. */
- if( pSession->hook.xDepth(pSession->hook.pCtx)==0
- && pSession->bIndirect==0
- ){
- pC->bIndirect = 0;
- }
- }
- }
-
- /* If an error has occurred, mark the session object as failed. */
- error_out:
- if( rc!=SQLITE_OK ){
- pSession->rc = rc;
- }
-}
-
-static int sessionFindTable(
- sqlite3_session *pSession,
- const char *zName,
- SessionTable **ppTab
-){
- int rc = SQLITE_OK;
- int nName = sqlite3Strlen30(zName);
- SessionTable *pRet;
-
- /* Search for an existing table */
- for(pRet=pSession->pTable; pRet; pRet=pRet->pNext){
- if( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) ) break;
- }
-
- if( pRet==0 && pSession->bAutoAttach ){
- /* If there is a table-filter configured, invoke it. If it returns 0,
- ** do not automatically add the new table. */
- if( pSession->xTableFilter==0
- || pSession->xTableFilter(pSession->pFilterCtx, zName)
- ){
- rc = sqlite3session_attach(pSession, zName);
- if( rc==SQLITE_OK ){
- for(pRet=pSession->pTable; pRet->pNext; pRet=pRet->pNext);
- assert( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) );
- }
- }
- }
-
- assert( rc==SQLITE_OK || pRet==0 );
- *ppTab = pRet;
- return rc;
-}
-
-/*
-** The 'pre-update' hook registered by this module with SQLite databases.
-*/
-static void xPreUpdate(
- void *pCtx, /* Copy of third arg to preupdate_hook() */
- sqlite3 *db, /* Database handle */
- int op, /* SQLITE_UPDATE, DELETE or INSERT */
- char const *zDb, /* Database name */
- char const *zName, /* Table name */
- sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */
- sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */
-){
- sqlite3_session *pSession;
- int nDb = sqlite3Strlen30(zDb);
-
- assert( sqlite3_mutex_held(db->mutex) );
-
- for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){
- SessionTable *pTab;
-
- /* If this session is attached to a different database ("main", "temp"
- ** etc.), or if it is not currently enabled, there is nothing to do. Skip
- ** to the next session object attached to this database. */
- if( pSession->bEnable==0 ) continue;
- if( pSession->rc ) continue;
- if( sqlite3_strnicmp(zDb, pSession->zDb, nDb+1) ) continue;
-
- pSession->rc = sessionFindTable(pSession, zName, &pTab);
- if( pTab ){
- assert( pSession->rc==SQLITE_OK );
- sessionPreupdateOneChange(op, pSession, pTab);
- if( op==SQLITE_UPDATE ){
- sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab);
- }
- }
- }
-}
-
-/*
-** The pre-update hook implementations.
-*/
-static int sessionPreupdateOld(void *pCtx, int iVal, sqlite3_value **ppVal){
- return sqlite3_preupdate_old((sqlite3*)pCtx, iVal, ppVal);
-}
-static int sessionPreupdateNew(void *pCtx, int iVal, sqlite3_value **ppVal){
- return sqlite3_preupdate_new((sqlite3*)pCtx, iVal, ppVal);
-}
-static int sessionPreupdateCount(void *pCtx){
- return sqlite3_preupdate_count((sqlite3*)pCtx);
-}
-static int sessionPreupdateDepth(void *pCtx){
- return sqlite3_preupdate_depth((sqlite3*)pCtx);
-}
-
-/*
-** Install the pre-update hooks on the session object passed as the only
-** argument.
-*/
-static void sessionPreupdateHooks(
- sqlite3_session *pSession
-){
- pSession->hook.pCtx = (void*)pSession->db;
- pSession->hook.xOld = sessionPreupdateOld;
- pSession->hook.xNew = sessionPreupdateNew;
- pSession->hook.xCount = sessionPreupdateCount;
- pSession->hook.xDepth = sessionPreupdateDepth;
-}
-
-typedef struct SessionDiffCtx SessionDiffCtx;
-struct SessionDiffCtx {
- sqlite3_stmt *pStmt;
- int nOldOff;
-};
-
-/*
-** The diff hook implementations.
-*/
-static int sessionDiffOld(void *pCtx, int iVal, sqlite3_value **ppVal){
- SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
- *ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff);
- return SQLITE_OK;
-}
-static int sessionDiffNew(void *pCtx, int iVal, sqlite3_value **ppVal){
- SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
- *ppVal = sqlite3_column_value(p->pStmt, iVal);
- return SQLITE_OK;
-}
-static int sessionDiffCount(void *pCtx){
- SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
- return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt);
-}
-static int sessionDiffDepth(void *pCtx){
- return 0;
-}
-
-/*
-** Install the diff hooks on the session object passed as the only
-** argument.
-*/
-static void sessionDiffHooks(
- sqlite3_session *pSession,
- SessionDiffCtx *pDiffCtx
-){
- pSession->hook.pCtx = (void*)pDiffCtx;
- pSession->hook.xOld = sessionDiffOld;
- pSession->hook.xNew = sessionDiffNew;
- pSession->hook.xCount = sessionDiffCount;
- pSession->hook.xDepth = sessionDiffDepth;
-}
-
-static char *sessionExprComparePK(
- int nCol,
- const char *zDb1, const char *zDb2,
- const char *zTab,
- const char **azCol, u8 *abPK
-){
- int i;
- const char *zSep = "";
- char *zRet = 0;
-
- for(i=0; i<nCol; i++){
- if( abPK[i] ){
- zRet = sqlite3_mprintf("%z%s\"%w\".\"%w\".\"%w\"=\"%w\".\"%w\".\"%w\"",
- zRet, zSep, zDb1, zTab, azCol[i], zDb2, zTab, azCol[i]
- );
- zSep = " AND ";
- if( zRet==0 ) break;
- }
- }
-
- return zRet;
-}
-
-static char *sessionExprCompareOther(
- int nCol,
- const char *zDb1, const char *zDb2,
- const char *zTab,
- const char **azCol, u8 *abPK
-){
- int i;
- const char *zSep = "";
- char *zRet = 0;
- int bHave = 0;
-
- for(i=0; i<nCol; i++){
- if( abPK[i]==0 ){
- bHave = 1;
- zRet = sqlite3_mprintf(
- "%z%s\"%w\".\"%w\".\"%w\" IS NOT \"%w\".\"%w\".\"%w\"",
- zRet, zSep, zDb1, zTab, azCol[i], zDb2, zTab, azCol[i]
- );
- zSep = " OR ";
- if( zRet==0 ) break;
- }
- }
-
- if( bHave==0 ){
- assert( zRet==0 );
- zRet = sqlite3_mprintf("0");
- }
-
- return zRet;
-}
-
-static char *sessionSelectFindNew(
- int nCol,
- const char *zDb1, /* Pick rows in this db only */
- const char *zDb2, /* But not in this one */
- const char *zTbl, /* Table name */
- const char *zExpr
-){
- char *zRet = sqlite3_mprintf(
- "SELECT * FROM \"%w\".\"%w\" WHERE NOT EXISTS ("
- " SELECT 1 FROM \"%w\".\"%w\" WHERE %s"
- ")",
- zDb1, zTbl, zDb2, zTbl, zExpr
- );
- return zRet;
-}
-
-static int sessionDiffFindNew(
- int op,
- sqlite3_session *pSession,
- SessionTable *pTab,
- const char *zDb1,
- const char *zDb2,
- char *zExpr
-){
- int rc = SQLITE_OK;
- char *zStmt = sessionSelectFindNew(pTab->nCol, zDb1, zDb2, pTab->zName,zExpr);
-
- if( zStmt==0 ){
- rc = SQLITE_NOMEM;
- }else{
- sqlite3_stmt *pStmt;
- rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0);
- if( rc==SQLITE_OK ){
- SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
- pDiffCtx->pStmt = pStmt;
- pDiffCtx->nOldOff = 0;
- while( SQLITE_ROW==sqlite3_step(pStmt) ){
- sessionPreupdateOneChange(op, pSession, pTab);
- }
- rc = sqlite3_finalize(pStmt);
- }
- sqlite3_free(zStmt);
- }
-
- return rc;
-}
-
-static int sessionDiffFindModified(
- sqlite3_session *pSession,
- SessionTable *pTab,
- const char *zFrom,
- const char *zExpr
-){
- int rc = SQLITE_OK;
-
- char *zExpr2 = sessionExprCompareOther(pTab->nCol,
- pSession->zDb, zFrom, pTab->zName, pTab->azCol, pTab->abPK
- );
- if( zExpr2==0 ){
- rc = SQLITE_NOMEM;
- }else{
- char *zStmt = sqlite3_mprintf(
- "SELECT * FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)",
- pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2
- );
- if( zStmt==0 ){
- rc = SQLITE_NOMEM;
- }else{
- sqlite3_stmt *pStmt;
- rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0);
-
- if( rc==SQLITE_OK ){
- SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
- pDiffCtx->pStmt = pStmt;
- pDiffCtx->nOldOff = pTab->nCol;
- while( SQLITE_ROW==sqlite3_step(pStmt) ){
- sessionPreupdateOneChange(SQLITE_UPDATE, pSession, pTab);
- }
- rc = sqlite3_finalize(pStmt);
- }
- sqlite3_free(zStmt);
- }
- }
-
- return rc;
-}
-
-SQLITE_API int SQLITE_STDCALL sqlite3session_diff(
- sqlite3_session *pSession,
- const char *zFrom,
- const char *zTbl,
- char **pzErrMsg
-){
- const char *zDb = pSession->zDb;
- int rc = pSession->rc;
- SessionDiffCtx d;
-
- memset(&d, 0, sizeof(d));
- sessionDiffHooks(pSession, &d);
-
- sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
- if( pzErrMsg ) *pzErrMsg = 0;
- if( rc==SQLITE_OK ){
- char *zExpr = 0;
- sqlite3 *db = pSession->db;
- SessionTable *pTo; /* Table zTbl */
-
- /* Locate and if necessary initialize the target table object */
- rc = sessionFindTable(pSession, zTbl, &pTo);
- if( pTo==0 ) goto diff_out;
- if( sessionInitTable(pSession, pTo) ){
- rc = pSession->rc;
- goto diff_out;
- }
-
- /* Check the table schemas match */
- if( rc==SQLITE_OK ){
- int bHasPk = 0;
- int bMismatch = 0;
- int nCol; /* Columns in zFrom.zTbl */
- u8 *abPK;
- const char **azCol = 0;
- rc = sessionTableInfo(db, zFrom, zTbl, &nCol, 0, &azCol, &abPK);
- if( rc==SQLITE_OK ){
- if( pTo->nCol!=nCol ){
- bMismatch = 1;
- }else{
- int i;
- for(i=0; i<nCol; i++){
- if( pTo->abPK[i]!=abPK[i] ) bMismatch = 1;
- if( sqlite3_stricmp(azCol[i], pTo->azCol[i]) ) bMismatch = 1;
- if( abPK[i] ) bHasPk = 1;
- }
- }
-
- }
- sqlite3_free((char*)azCol);
- if( bMismatch ){
- *pzErrMsg = sqlite3_mprintf("table schemas do not match");
- rc = SQLITE_SCHEMA;
- }
- if( bHasPk==0 ){
- /* Ignore tables with no primary keys */
- goto diff_out;
- }
- }
-
- if( rc==SQLITE_OK ){
- zExpr = sessionExprComparePK(pTo->nCol,
- zDb, zFrom, pTo->zName, pTo->azCol, pTo->abPK
- );
- }
-
- /* Find new rows */
- if( rc==SQLITE_OK ){
- rc = sessionDiffFindNew(SQLITE_INSERT, pSession, pTo, zDb, zFrom, zExpr);
- }
-
- /* Find old rows */
- if( rc==SQLITE_OK ){
- rc = sessionDiffFindNew(SQLITE_DELETE, pSession, pTo, zFrom, zDb, zExpr);
- }
-
- /* Find modified rows */
- if( rc==SQLITE_OK ){
- rc = sessionDiffFindModified(pSession, pTo, zFrom, zExpr);
- }
-
- sqlite3_free(zExpr);
- }
-
- diff_out:
- sessionPreupdateHooks(pSession);
- sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
- return rc;
-}
-
-/*
-** Create a session object. This session object will record changes to
-** database zDb attached to connection db.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3session_create(
- sqlite3 *db, /* Database handle */
- const char *zDb, /* Name of db (e.g. "main") */
- sqlite3_session **ppSession /* OUT: New session object */
-){
- sqlite3_session *pNew; /* Newly allocated session object */
- sqlite3_session *pOld; /* Session object already attached to db */
- int nDb = sqlite3Strlen30(zDb); /* Length of zDb in bytes */
-
- /* Zero the output value in case an error occurs. */
- *ppSession = 0;
-
- /* Allocate and populate the new session object. */
- pNew = (sqlite3_session *)sqlite3_malloc(sizeof(sqlite3_session) + nDb + 1);
- if( !pNew ) return SQLITE_NOMEM;
- memset(pNew, 0, sizeof(sqlite3_session));
- pNew->db = db;
- pNew->zDb = (char *)&pNew[1];
- pNew->bEnable = 1;
- memcpy(pNew->zDb, zDb, nDb+1);
- sessionPreupdateHooks(pNew);
-
- /* Add the new session object to the linked list of session objects
- ** attached to database handle $db. Do this under the cover of the db
- ** handle mutex. */
- sqlite3_mutex_enter(sqlite3_db_mutex(db));
- pOld = (sqlite3_session*)sqlite3_preupdate_hook(db, xPreUpdate, (void*)pNew);
- pNew->pNext = pOld;
- sqlite3_mutex_leave(sqlite3_db_mutex(db));
-
- *ppSession = pNew;
- return SQLITE_OK;
-}
-
-/*
-** Free the list of table objects passed as the first argument. The contents
-** of the changed-rows hash tables are also deleted.
-*/
-static void sessionDeleteTable(SessionTable *pList){
- SessionTable *pNext;
- SessionTable *pTab;
-
- for(pTab=pList; pTab; pTab=pNext){
- int i;
- pNext = pTab->pNext;
- for(i=0; i<pTab->nChange; i++){
- SessionChange *p;
- SessionChange *pNextChange;
- for(p=pTab->apChange[i]; p; p=pNextChange){
- pNextChange = p->pNext;
- sqlite3_free(p);
- }
- }
- sqlite3_free((char*)pTab->azCol); /* cast works around VC++ bug */
- sqlite3_free(pTab->apChange);
- sqlite3_free(pTab);
- }
-}
-
-/*
-** Delete a session object previously allocated using sqlite3session_create().
-*/
-SQLITE_API void SQLITE_STDCALL sqlite3session_delete(sqlite3_session *pSession){
- sqlite3 *db = pSession->db;
- sqlite3_session *pHead;
- sqlite3_session **pp;
-
- /* Unlink the session from the linked list of sessions attached to the
- ** database handle. Hold the db mutex while doing so. */
- sqlite3_mutex_enter(sqlite3_db_mutex(db));
- pHead = (sqlite3_session*)sqlite3_preupdate_hook(db, 0, 0);
- for(pp=&pHead; ALWAYS((*pp)!=0); pp=&((*pp)->pNext)){
- if( (*pp)==pSession ){
- *pp = (*pp)->pNext;
- if( pHead ) sqlite3_preupdate_hook(db, xPreUpdate, (void*)pHead);
- break;
- }
- }
- sqlite3_mutex_leave(sqlite3_db_mutex(db));
-
- /* Delete all attached table objects. And the contents of their
- ** associated hash-tables. */
- sessionDeleteTable(pSession->pTable);
-
- /* Free the session object itself. */
- sqlite3_free(pSession);
-}
-
-/*
-** Set a table filter on a Session Object.
-*/
-SQLITE_API void SQLITE_STDCALL sqlite3session_table_filter(
- sqlite3_session *pSession,
- int(*xFilter)(void*, const char*),
- void *pCtx /* First argument passed to xFilter */
-){
- pSession->bAutoAttach = 1;
- pSession->pFilterCtx = pCtx;
- pSession->xTableFilter = xFilter;
-}
-
-/*
-** Attach a table to a session. All subsequent changes made to the table
-** while the session object is enabled will be recorded.
-**
-** Only tables that have a PRIMARY KEY defined may be attached. It does
-** not matter if the PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias)
-** or not.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3session_attach(
- sqlite3_session *pSession, /* Session object */
- const char *zName /* Table name */
-){
- int rc = SQLITE_OK;
- sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
-
- if( !zName ){
- pSession->bAutoAttach = 1;
- }else{
- SessionTable *pTab; /* New table object (if required) */
- int nName; /* Number of bytes in string zName */
-
- /* First search for an existing entry. If one is found, this call is
- ** a no-op. Return early. */
- nName = sqlite3Strlen30(zName);
- for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){
- if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ) break;
- }
-
- if( !pTab ){
- /* Allocate new SessionTable object. */
- pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1);
- if( !pTab ){
- rc = SQLITE_NOMEM;
- }else{
- /* Populate the new SessionTable object and link it into the list.
- ** The new object must be linked onto the end of the list, not
- ** simply added to the start of it in order to ensure that tables
- ** appear in the correct order when a changeset or patchset is
- ** eventually generated. */
- SessionTable **ppTab;
- memset(pTab, 0, sizeof(SessionTable));
- pTab->zName = (char *)&pTab[1];
- memcpy(pTab->zName, zName, nName+1);
- for(ppTab=&pSession->pTable; *ppTab; ppTab=&(*ppTab)->pNext);
- *ppTab = pTab;
- }
- }
- }
-
- sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
- return rc;
-}
-
-/*
-** Ensure that there is room in the buffer to append nByte bytes of data.
-** If not, use sqlite3_realloc() to grow the buffer so that there is.
-**
-** If successful, return zero. Otherwise, if an OOM condition is encountered,
-** set *pRc to SQLITE_NOMEM and return non-zero.
-*/
-static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){
- if( *pRc==SQLITE_OK && p->nAlloc-p->nBuf<nByte ){
- u8 *aNew;
- int nNew = p->nAlloc ? p->nAlloc : 128;
- do {
- nNew = nNew*2;
- }while( nNew<(p->nBuf+nByte) );
-
- aNew = (u8 *)sqlite3_realloc(p->aBuf, nNew);
- if( 0==aNew ){
- *pRc = SQLITE_NOMEM;
- }else{
- p->aBuf = aNew;
- p->nAlloc = nNew;
- }
- }
- return (*pRc!=SQLITE_OK);
-}
-
-/*
-** Append the value passed as the second argument to the buffer passed
-** as the first.
-**
-** This function is a no-op if *pRc is non-zero when it is called.
-** Otherwise, if an error occurs, *pRc is set to an SQLite error code
-** before returning.
-*/
-static void sessionAppendValue(SessionBuffer *p, sqlite3_value *pVal, int *pRc){
- int rc = *pRc;
- if( rc==SQLITE_OK ){
- int nByte = 0;
- rc = sessionSerializeValue(0, pVal, &nByte);
- sessionBufferGrow(p, nByte, &rc);
- if( rc==SQLITE_OK ){
- rc = sessionSerializeValue(&p->aBuf[p->nBuf], pVal, 0);
- p->nBuf += nByte;
- }else{
- *pRc = rc;
- }
- }
-}
-
-/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
-** called. Otherwise, append a single byte to the buffer.
-**
-** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
-** returning.
-*/
-static void sessionAppendByte(SessionBuffer *p, u8 v, int *pRc){
- if( 0==sessionBufferGrow(p, 1, pRc) ){
- p->aBuf[p->nBuf++] = v;
- }
-}
-
-/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
-** called. Otherwise, append a single varint to the buffer.
-**
-** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
-** returning.
-*/
-static void sessionAppendVarint(SessionBuffer *p, int v, int *pRc){
- if( 0==sessionBufferGrow(p, 9, pRc) ){
- p->nBuf += sessionVarintPut(&p->aBuf[p->nBuf], v);
- }
-}
-
-/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
-** called. Otherwise, append a blob of data to the buffer.
-**
-** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
-** returning.
-*/
-static void sessionAppendBlob(
- SessionBuffer *p,
- const u8 *aBlob,
- int nBlob,
- int *pRc
-){
- if( 0==sessionBufferGrow(p, nBlob, pRc) ){
- memcpy(&p->aBuf[p->nBuf], aBlob, nBlob);
- p->nBuf += nBlob;
- }
-}
-
-/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
-** called. Otherwise, append a string to the buffer. All bytes in the string
-** up to (but not including) the nul-terminator are written to the buffer.
-**
-** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
-** returning.
-*/
-static void sessionAppendStr(
- SessionBuffer *p,
- const char *zStr,
- int *pRc
-){
- int nStr = sqlite3Strlen30(zStr);
- if( 0==sessionBufferGrow(p, nStr, pRc) ){
- memcpy(&p->aBuf[p->nBuf], zStr, nStr);
- p->nBuf += nStr;
- }
-}
-
-/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
-** called. Otherwise, append the string representation of integer iVal
-** to the buffer. No nul-terminator is written.
-**
-** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
-** returning.
-*/
-static void sessionAppendInteger(
- SessionBuffer *p, /* Buffer to append to */
- int iVal, /* Value to write the string rep. of */
- int *pRc /* IN/OUT: Error code */
-){
- char aBuf[24];
- sqlite3_snprintf(sizeof(aBuf)-1, aBuf, "%d", iVal);
- sessionAppendStr(p, aBuf, pRc);
-}
-
-/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
-** called. Otherwise, append the string zStr enclosed in quotes (") and
-** with any embedded quote characters escaped to the buffer. No
-** nul-terminator byte is written.
-**
-** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
-** returning.
-*/
-static void sessionAppendIdent(
- SessionBuffer *p, /* Buffer to a append to */
- const char *zStr, /* String to quote, escape and append */
- int *pRc /* IN/OUT: Error code */
-){
- int nStr = sqlite3Strlen30(zStr)*2 + 2 + 1;
- if( 0==sessionBufferGrow(p, nStr, pRc) ){
- char *zOut = (char *)&p->aBuf[p->nBuf];
- const char *zIn = zStr;
- *zOut++ = '"';
- while( *zIn ){
- if( *zIn=='"' ) *zOut++ = '"';
- *zOut++ = *(zIn++);
- }
- *zOut++ = '"';
- p->nBuf = (int)((u8 *)zOut - p->aBuf);
- }
-}
-
-/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
-** called. Otherwse, it appends the serialized version of the value stored
-** in column iCol of the row that SQL statement pStmt currently points
-** to to the buffer.
-*/
-static void sessionAppendCol(
- SessionBuffer *p, /* Buffer to append to */
- sqlite3_stmt *pStmt, /* Handle pointing to row containing value */
- int iCol, /* Column to read value from */
- int *pRc /* IN/OUT: Error code */
-){
- if( *pRc==SQLITE_OK ){
- int eType = sqlite3_column_type(pStmt, iCol);
- sessionAppendByte(p, (u8)eType, pRc);
- if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
- sqlite3_int64 i;
- u8 aBuf[8];
- if( eType==SQLITE_INTEGER ){
- i = sqlite3_column_int64(pStmt, iCol);
- }else{
- double r = sqlite3_column_double(pStmt, iCol);
- memcpy(&i, &r, 8);
- }
- sessionPutI64(aBuf, i);
- sessionAppendBlob(p, aBuf, 8, pRc);
- }
- if( eType==SQLITE_BLOB || eType==SQLITE_TEXT ){
- u8 *z;
- int nByte;
- if( eType==SQLITE_BLOB ){
- z = (u8 *)sqlite3_column_blob(pStmt, iCol);
- }else{
- z = (u8 *)sqlite3_column_text(pStmt, iCol);
- }
- nByte = sqlite3_column_bytes(pStmt, iCol);
- if( z || (eType==SQLITE_BLOB && nByte==0) ){
- sessionAppendVarint(p, nByte, pRc);
- sessionAppendBlob(p, z, nByte, pRc);
- }else{
- *pRc = SQLITE_NOMEM;
- }
- }
- }
-}
-
-/*
-**
-** This function appends an update change to the buffer (see the comments
-** under "CHANGESET FORMAT" at the top of the file). An update change
-** consists of:
-**
-** 1 byte: SQLITE_UPDATE (0x17)
-** n bytes: old.* record (see RECORD FORMAT)
-** m bytes: new.* record (see RECORD FORMAT)
-**
-** The SessionChange object passed as the third argument contains the
-** values that were stored in the row when the session began (the old.*
-** values). The statement handle passed as the second argument points
-** at the current version of the row (the new.* values).
-**
-** If all of the old.* values are equal to their corresponding new.* value
-** (i.e. nothing has changed), then no data at all is appended to the buffer.
-**
-** Otherwise, the old.* record contains all primary key values and the
-** original values of any fields that have been modified. The new.* record
-** contains the new values of only those fields that have been modified.
-*/
-static int sessionAppendUpdate(
- SessionBuffer *pBuf, /* Buffer to append to */
- int bPatchset, /* True for "patchset", 0 for "changeset" */
- sqlite3_stmt *pStmt, /* Statement handle pointing at new row */
- SessionChange *p, /* Object containing old values */
- u8 *abPK /* Boolean array - true for PK columns */
-){
- int rc = SQLITE_OK;
- SessionBuffer buf2 = {0,0,0}; /* Buffer to accumulate new.* record in */
- int bNoop = 1; /* Set to zero if any values are modified */
- int nRewind = pBuf->nBuf; /* Set to zero if any values are modified */
- int i; /* Used to iterate through columns */
- u8 *pCsr = p->aRecord; /* Used to iterate through old.* values */
-
- sessionAppendByte(pBuf, SQLITE_UPDATE, &rc);
- sessionAppendByte(pBuf, p->bIndirect, &rc);
- for(i=0; i<sqlite3_column_count(pStmt); i++){
- int bChanged = 0;
- int nAdvance;
- int eType = *pCsr;
- switch( eType ){
- case SQLITE_NULL:
- nAdvance = 1;
- if( sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
- bChanged = 1;
- }
- break;
-
- case SQLITE_FLOAT:
- case SQLITE_INTEGER: {
- nAdvance = 9;
- if( eType==sqlite3_column_type(pStmt, i) ){
- sqlite3_int64 iVal = sessionGetI64(&pCsr[1]);
- if( eType==SQLITE_INTEGER ){
- if( iVal==sqlite3_column_int64(pStmt, i) ) break;
- }else{
- double dVal;
- memcpy(&dVal, &iVal, 8);
- if( dVal==sqlite3_column_double(pStmt, i) ) break;
- }
- }
- bChanged = 1;
- break;
- }
-
- default: {
- int nByte;
- int nHdr = 1 + sessionVarintGet(&pCsr[1], &nByte);
- assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
- nAdvance = nHdr + nByte;
- if( eType==sqlite3_column_type(pStmt, i)
- && nByte==sqlite3_column_bytes(pStmt, i)
- && 0==memcmp(&pCsr[nHdr], sqlite3_column_blob(pStmt, i), nByte)
- ){
- break;
- }
- bChanged = 1;
- }
- }
-
- /* If at least one field has been modified, this is not a no-op. */
- if( bChanged ) bNoop = 0;
-
- /* Add a field to the old.* record. This is omitted if this modules is
- ** currently generating a patchset. */
- if( bPatchset==0 ){
- if( bChanged || abPK[i] ){
- sessionAppendBlob(pBuf, pCsr, nAdvance, &rc);
- }else{
- sessionAppendByte(pBuf, 0, &rc);
- }
- }
-
- /* Add a field to the new.* record. Or the only record if currently
- ** generating a patchset. */
- if( bChanged || (bPatchset && abPK[i]) ){
- sessionAppendCol(&buf2, pStmt, i, &rc);
- }else{
- sessionAppendByte(&buf2, 0, &rc);
- }
-
- pCsr += nAdvance;
- }
-
- if( bNoop ){
- pBuf->nBuf = nRewind;
- }else{
- sessionAppendBlob(pBuf, buf2.aBuf, buf2.nBuf, &rc);
- }
- sqlite3_free(buf2.aBuf);
-
- return rc;
-}
-
-/*
-** Append a DELETE change to the buffer passed as the first argument. Use
-** the changeset format if argument bPatchset is zero, or the patchset
-** format otherwise.
-*/
-static int sessionAppendDelete(
- SessionBuffer *pBuf, /* Buffer to append to */
- int bPatchset, /* True for "patchset", 0 for "changeset" */
- SessionChange *p, /* Object containing old values */
- int nCol, /* Number of columns in table */
- u8 *abPK /* Boolean array - true for PK columns */
-){
- int rc = SQLITE_OK;
-
- sessionAppendByte(pBuf, SQLITE_DELETE, &rc);
- sessionAppendByte(pBuf, p->bIndirect, &rc);
-
- if( bPatchset==0 ){
- sessionAppendBlob(pBuf, p->aRecord, p->nRecord, &rc);
- }else{
- int i;
- u8 *a = p->aRecord;
- for(i=0; i<nCol; i++){
- u8 *pStart = a;
- int eType = *a++;
-
- switch( eType ){
- case 0:
- case SQLITE_NULL:
- assert( abPK[i]==0 );
- break;
-
- case SQLITE_FLOAT:
- case SQLITE_INTEGER:
- a += 8;
- break;
-
- default: {
- int n;
- a += sessionVarintGet(a, &n);
- a += n;
- break;
- }
- }
- if( abPK[i] ){
- sessionAppendBlob(pBuf, pStart, (int)(a-pStart), &rc);
- }
- }
- assert( (a - p->aRecord)==p->nRecord );
- }
-
- return rc;
-}
-
-/*
-** Formulate and prepare a SELECT statement to retrieve a row from table
-** zTab in database zDb based on its primary key. i.e.
-**
-** SELECT * FROM zDb.zTab WHERE pk1 = ? AND pk2 = ? AND ...
-*/
-static int sessionSelectStmt(
- sqlite3 *db, /* Database handle */
- const char *zDb, /* Database name */
- const char *zTab, /* Table name */
- int nCol, /* Number of columns in table */
- const char **azCol, /* Names of table columns */
- u8 *abPK, /* PRIMARY KEY array */
- sqlite3_stmt **ppStmt /* OUT: Prepared SELECT statement */
-){
- int rc = SQLITE_OK;
- int i;
- const char *zSep = "";
- SessionBuffer buf = {0, 0, 0};
-
- sessionAppendStr(&buf, "SELECT * FROM ", &rc);
- sessionAppendIdent(&buf, zDb, &rc);
- sessionAppendStr(&buf, ".", &rc);
- sessionAppendIdent(&buf, zTab, &rc);
- sessionAppendStr(&buf, " WHERE ", &rc);
- for(i=0; i<nCol; i++){
- if( abPK[i] ){
- sessionAppendStr(&buf, zSep, &rc);
- sessionAppendIdent(&buf, azCol[i], &rc);
- sessionAppendStr(&buf, " = ?", &rc);
- sessionAppendInteger(&buf, i+1, &rc);
- zSep = " AND ";
- }
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, ppStmt, 0);
- }
- sqlite3_free(buf.aBuf);
- return rc;
-}
-
-/*
-** Bind the PRIMARY KEY values from the change passed in argument pChange
-** to the SELECT statement passed as the first argument. The SELECT statement
-** is as prepared by function sessionSelectStmt().
-**
-** Return SQLITE_OK if all PK values are successfully bound, or an SQLite
-** error code (e.g. SQLITE_NOMEM) otherwise.
-*/
-static int sessionSelectBind(
- sqlite3_stmt *pSelect, /* SELECT from sessionSelectStmt() */
- int nCol, /* Number of columns in table */
- u8 *abPK, /* PRIMARY KEY array */
- SessionChange *pChange /* Change structure */
-){
- int i;
- int rc = SQLITE_OK;
- u8 *a = pChange->aRecord;
-
- for(i=0; i<nCol && rc==SQLITE_OK; i++){
- int eType = *a++;
-
- switch( eType ){
- case 0:
- case SQLITE_NULL:
- assert( abPK[i]==0 );
- break;
-
- case SQLITE_INTEGER: {
- if( abPK[i] ){
- i64 iVal = sessionGetI64(a);
- rc = sqlite3_bind_int64(pSelect, i+1, iVal);
- }
- a += 8;
- break;
- }
-
- case SQLITE_FLOAT: {
- if( abPK[i] ){
- double rVal;
- i64 iVal = sessionGetI64(a);
- memcpy(&rVal, &iVal, 8);
- rc = sqlite3_bind_double(pSelect, i+1, rVal);
- }
- a += 8;
- break;
- }
-
- case SQLITE_TEXT: {
- int n;
- a += sessionVarintGet(a, &n);
- if( abPK[i] ){
- rc = sqlite3_bind_text(pSelect, i+1, (char *)a, n, SQLITE_TRANSIENT);
- }
- a += n;
- break;
- }
-
- default: {
- int n;
- assert( eType==SQLITE_BLOB );
- a += sessionVarintGet(a, &n);
- if( abPK[i] ){
- rc = sqlite3_bind_blob(pSelect, i+1, a, n, SQLITE_TRANSIENT);
- }
- a += n;
- break;
- }
- }
- }
-
- return rc;
-}
-
-/*
-** This function is a no-op if *pRc is set to other than SQLITE_OK when it
-** is called. Otherwise, append a serialized table header (part of the binary
-** changeset format) to buffer *pBuf. If an error occurs, set *pRc to an
-** SQLite error code before returning.
-*/
-static void sessionAppendTableHdr(
- SessionBuffer *pBuf, /* Append header to this buffer */
- int bPatchset, /* Use the patchset format if true */
- SessionTable *pTab, /* Table object to append header for */
- int *pRc /* IN/OUT: Error code */
-){
- /* Write a table header */
- sessionAppendByte(pBuf, (bPatchset ? 'P' : 'T'), pRc);
- sessionAppendVarint(pBuf, pTab->nCol, pRc);
- sessionAppendBlob(pBuf, pTab->abPK, pTab->nCol, pRc);
- sessionAppendBlob(pBuf, (u8 *)pTab->zName, (int)strlen(pTab->zName)+1, pRc);
-}
-
-/*
-** Generate either a changeset (if argument bPatchset is zero) or a patchset
-** (if it is non-zero) based on the current contents of the session object
-** passed as the first argument.
-**
-** If no error occurs, SQLITE_OK is returned and the new changeset/patchset
-** stored in output variables *pnChangeset and *ppChangeset. Or, if an error
-** occurs, an SQLite error code is returned and both output variables set
-** to 0.
-*/
-static int sessionGenerateChangeset(
- sqlite3_session *pSession, /* Session object */
- int bPatchset, /* True for patchset, false for changeset */
- int (*xOutput)(void *pOut, const void *pData, int nData),
- void *pOut, /* First argument for xOutput */
- int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */
- void **ppChangeset /* OUT: Buffer containing changeset */
-){
- sqlite3 *db = pSession->db; /* Source database handle */
- SessionTable *pTab; /* Used to iterate through attached tables */
- SessionBuffer buf = {0,0,0}; /* Buffer in which to accumlate changeset */
- int rc; /* Return code */
-
- assert( xOutput==0 || (pnChangeset==0 && ppChangeset==0 ) );
-
- /* Zero the output variables in case an error occurs. If this session
- ** object is already in the error state (sqlite3_session.rc != SQLITE_OK),
- ** this call will be a no-op. */
- if( xOutput==0 ){
- *pnChangeset = 0;
- *ppChangeset = 0;
- }
-
- if( pSession->rc ) return pSession->rc;
- rc = sqlite3_exec(pSession->db, "SAVEPOINT changeset", 0, 0, 0);
- if( rc!=SQLITE_OK ) return rc;
-
- sqlite3_mutex_enter(sqlite3_db_mutex(db));
-
- for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
- if( pTab->nEntry ){
- const char *zName = pTab->zName;
- int nCol; /* Number of columns in table */
- u8 *abPK; /* Primary key array */
- const char **azCol = 0; /* Table columns */
- int i; /* Used to iterate through hash buckets */
- sqlite3_stmt *pSel = 0; /* SELECT statement to query table pTab */
- int nRewind = buf.nBuf; /* Initial size of write buffer */
- int nNoop; /* Size of buffer after writing tbl header */
-
- /* Check the table schema is still Ok. */
- rc = sessionTableInfo(db, pSession->zDb, zName, &nCol, 0, &azCol, &abPK);
- if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){
- rc = SQLITE_SCHEMA;
- }
-
- /* Write a table header */
- sessionAppendTableHdr(&buf, bPatchset, pTab, &rc);
-
- /* Build and compile a statement to execute: */
- if( rc==SQLITE_OK ){
- rc = sessionSelectStmt(
- db, pSession->zDb, zName, nCol, azCol, abPK, &pSel);
- }
-
- nNoop = buf.nBuf;
- for(i=0; i<pTab->nChange && rc==SQLITE_OK; i++){
- SessionChange *p; /* Used to iterate through changes */
-
- for(p=pTab->apChange[i]; rc==SQLITE_OK && p; p=p->pNext){
- rc = sessionSelectBind(pSel, nCol, abPK, p);
- if( rc!=SQLITE_OK ) continue;
- if( sqlite3_step(pSel)==SQLITE_ROW ){
- if( p->op==SQLITE_INSERT ){
- int iCol;
- sessionAppendByte(&buf, SQLITE_INSERT, &rc);
- sessionAppendByte(&buf, p->bIndirect, &rc);
- for(iCol=0; iCol<nCol; iCol++){
- sessionAppendCol(&buf, pSel, iCol, &rc);
- }
- }else{
- rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, abPK);
- }
- }else if( p->op!=SQLITE_INSERT ){
- rc = sessionAppendDelete(&buf, bPatchset, p, nCol, abPK);
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3_reset(pSel);
- }
-
- /* If the buffer is now larger than SESSIONS_STRM_CHUNK_SIZE, pass
- ** its contents to the xOutput() callback. */
- if( xOutput
- && rc==SQLITE_OK
- && buf.nBuf>nNoop
- && buf.nBuf>SESSIONS_STRM_CHUNK_SIZE
- ){
- rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf);
- nNoop = -1;
- buf.nBuf = 0;
- }
-
- }
- }
-
- sqlite3_finalize(pSel);
- if( buf.nBuf==nNoop ){
- buf.nBuf = nRewind;
- }
- sqlite3_free((char*)azCol); /* cast works around VC++ bug */
- }
- }
-
- if( rc==SQLITE_OK ){
- if( xOutput==0 ){
- *pnChangeset = buf.nBuf;
- *ppChangeset = buf.aBuf;
- buf.aBuf = 0;
- }else if( buf.nBuf>0 ){
- rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf);
- }
- }
-
- sqlite3_free(buf.aBuf);
- sqlite3_exec(db, "RELEASE changeset", 0, 0, 0);
- sqlite3_mutex_leave(sqlite3_db_mutex(db));
- return rc;
-}
-
-/*
-** Obtain a changeset object containing all changes recorded by the
-** session object passed as the first argument.
-**
-** It is the responsibility of the caller to eventually free the buffer
-** using sqlite3_free().
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3session_changeset(
- sqlite3_session *pSession, /* Session object */
- int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */
- void **ppChangeset /* OUT: Buffer containing changeset */
-){
- return sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset, ppChangeset);
-}
-
-/*
-** Streaming version of sqlite3session_changeset().
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3session_changeset_strm(
- sqlite3_session *pSession,
- int (*xOutput)(void *pOut, const void *pData, int nData),
- void *pOut
-){
- return sessionGenerateChangeset(pSession, 0, xOutput, pOut, 0, 0);
-}
-
-/*
-** Streaming version of sqlite3session_patchset().
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3session_patchset_strm(
- sqlite3_session *pSession,
- int (*xOutput)(void *pOut, const void *pData, int nData),
- void *pOut
-){
- return sessionGenerateChangeset(pSession, 1, xOutput, pOut, 0, 0);
-}
-
-/*
-** Obtain a patchset object containing all changes recorded by the
-** session object passed as the first argument.
-**
-** It is the responsibility of the caller to eventually free the buffer
-** using sqlite3_free().
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3session_patchset(
- sqlite3_session *pSession, /* Session object */
- int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */
- void **ppPatchset /* OUT: Buffer containing changeset */
-){
- return sessionGenerateChangeset(pSession, 1, 0, 0, pnPatchset, ppPatchset);
-}
-
-/*
-** Enable or disable the session object passed as the first argument.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3session_enable(sqlite3_session *pSession, int bEnable){
- int ret;
- sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
- if( bEnable>=0 ){
- pSession->bEnable = bEnable;
- }
- ret = pSession->bEnable;
- sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
- return ret;
-}
-
-/*
-** Enable or disable the session object passed as the first argument.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3session_indirect(sqlite3_session *pSession, int bIndirect){
- int ret;
- sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
- if( bIndirect>=0 ){
- pSession->bIndirect = bIndirect;
- }
- ret = pSession->bIndirect;
- sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
- return ret;
-}
-
-/*
-** Return true if there have been no changes to monitored tables recorded
-** by the session object passed as the only argument.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3session_isempty(sqlite3_session *pSession){
- int ret = 0;
- SessionTable *pTab;
-
- sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
- for(pTab=pSession->pTable; pTab && ret==0; pTab=pTab->pNext){
- ret = (pTab->nEntry>0);
- }
- sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
-
- return (ret==0);
-}
-
-/*
-** Do the work for either sqlite3changeset_start() or start_strm().
-*/
-static int sessionChangesetStart(
- sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */
- int (*xInput)(void *pIn, void *pData, int *pnData),
- void *pIn,
- int nChangeset, /* Size of buffer pChangeset in bytes */
- void *pChangeset /* Pointer to buffer containing changeset */
-){
- sqlite3_changeset_iter *pRet; /* Iterator to return */
- int nByte; /* Number of bytes to allocate for iterator */
-
- assert( xInput==0 || (pChangeset==0 && nChangeset==0) );
-
- /* Zero the output variable in case an error occurs. */
- *pp = 0;
-
- /* Allocate and initialize the iterator structure. */
- nByte = sizeof(sqlite3_changeset_iter);
- pRet = (sqlite3_changeset_iter *)sqlite3_malloc(nByte);
- if( !pRet ) return SQLITE_NOMEM;
- memset(pRet, 0, sizeof(sqlite3_changeset_iter));
- pRet->in.aData = (u8 *)pChangeset;
- pRet->in.nData = nChangeset;
- pRet->in.xInput = xInput;
- pRet->in.pIn = pIn;
- pRet->in.bEof = (xInput ? 0 : 1);
-
- /* Populate the output variable and return success. */
- *pp = pRet;
- return SQLITE_OK;
-}
-
-/*
-** Create an iterator used to iterate through the contents of a changeset.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changeset_start(
- sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */
- int nChangeset, /* Size of buffer pChangeset in bytes */
- void *pChangeset /* Pointer to buffer containing changeset */
-){
- return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset);
-}
-
-/*
-** Streaming version of sqlite3changeset_start().
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changeset_start_strm(
- sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */
- int (*xInput)(void *pIn, void *pData, int *pnData),
- void *pIn
-){
- return sessionChangesetStart(pp, xInput, pIn, 0, 0);
-}
-
-/*
-** If the SessionInput object passed as the only argument is a streaming
-** object and the buffer is full, discard some data to free up space.
-*/
-static void sessionDiscardData(SessionInput *pIn){
- if( pIn->bEof && pIn->xInput && pIn->iNext>=SESSIONS_STRM_CHUNK_SIZE ){
- int nMove = pIn->buf.nBuf - pIn->iNext;
- assert( nMove>=0 );
- if( nMove>0 ){
- memmove(pIn->buf.aBuf, &pIn->buf.aBuf[pIn->iNext], nMove);
- }
- pIn->buf.nBuf -= pIn->iNext;
- pIn->iNext = 0;
- pIn->nData = pIn->buf.nBuf;
- }
-}
-
-/*
-** Ensure that there are at least nByte bytes available in the buffer. Or,
-** if there are not nByte bytes remaining in the input, that all available
-** data is in the buffer.
-**
-** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise.
-*/
-static int sessionInputBuffer(SessionInput *pIn, int nByte){
- int rc = SQLITE_OK;
- if( pIn->xInput ){
- while( !pIn->bEof && (pIn->iNext+nByte)>=pIn->nData && rc==SQLITE_OK ){
- int nNew = SESSIONS_STRM_CHUNK_SIZE;
-
- if( pIn->bNoDiscard==0 ) sessionDiscardData(pIn);
- if( SQLITE_OK==sessionBufferGrow(&pIn->buf, nNew, &rc) ){
- rc = pIn->xInput(pIn->pIn, &pIn->buf.aBuf[pIn->buf.nBuf], &nNew);
- if( nNew==0 ){
- pIn->bEof = 1;
- }else{
- pIn->buf.nBuf += nNew;
- }
- }
-
- pIn->aData = pIn->buf.aBuf;
- pIn->nData = pIn->buf.nBuf;
- }
- }
- return rc;
-}
-
-/*
-** When this function is called, *ppRec points to the start of a record
-** that contains nCol values. This function advances the pointer *ppRec
-** until it points to the byte immediately following that record.
-*/
-static void sessionSkipRecord(
- u8 **ppRec, /* IN/OUT: Record pointer */
- int nCol /* Number of values in record */
-){
- u8 *aRec = *ppRec;
- int i;
- for(i=0; i<nCol; i++){
- int eType = *aRec++;
- if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
- int nByte;
- aRec += sessionVarintGet((u8*)aRec, &nByte);
- aRec += nByte;
- }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
- aRec += 8;
- }
- }
-
- *ppRec = aRec;
-}
-
-/*
-** This function sets the value of the sqlite3_value object passed as the
-** first argument to a copy of the string or blob held in the aData[]
-** buffer. SQLITE_OK is returned if successful, or SQLITE_NOMEM if an OOM
-** error occurs.
-*/
-static int sessionValueSetStr(
- sqlite3_value *pVal, /* Set the value of this object */
- u8 *aData, /* Buffer containing string or blob data */
- int nData, /* Size of buffer aData[] in bytes */
- u8 enc /* String encoding (0 for blobs) */
-){
- /* In theory this code could just pass SQLITE_TRANSIENT as the final
- ** argument to sqlite3ValueSetStr() and have the copy created
- ** automatically. But doing so makes it difficult to detect any OOM
- ** error. Hence the code to create the copy externally. */
- u8 *aCopy = sqlite3_malloc(nData+1);
- if( aCopy==0 ) return SQLITE_NOMEM;
- memcpy(aCopy, aData, nData);
- sqlite3ValueSetStr(pVal, nData, (char*)aCopy, enc, sqlite3_free);
- return SQLITE_OK;
-}
-
-/*
-** Deserialize a single record from a buffer in memory. See "RECORD FORMAT"
-** for details.
-**
-** When this function is called, *paChange points to the start of the record
-** to deserialize. Assuming no error occurs, *paChange is set to point to
-** one byte after the end of the same record before this function returns.
-** If the argument abPK is NULL, then the record contains nCol values. Or,
-** if abPK is other than NULL, then the record contains only the PK fields
-** (in other words, it is a patchset DELETE record).
-**
-** If successful, each element of the apOut[] array (allocated by the caller)
-** is set to point to an sqlite3_value object containing the value read
-** from the corresponding position in the record. If that value is not
-** included in the record (i.e. because the record is part of an UPDATE change
-** and the field was not modified), the corresponding element of apOut[] is
-** set to NULL.
-**
-** It is the responsibility of the caller to free all sqlite_value structures
-** using sqlite3_free().
-**
-** If an error occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
-** The apOut[] array may have been partially populated in this case.
-*/
-static int sessionReadRecord(
- SessionInput *pIn, /* Input data */
- int nCol, /* Number of values in record */
- u8 *abPK, /* Array of primary key flags, or NULL */
- sqlite3_value **apOut /* Write values to this array */
-){
- int i; /* Used to iterate through columns */
- int rc = SQLITE_OK;
-
- for(i=0; i<nCol && rc==SQLITE_OK; i++){
- int eType = 0; /* Type of value (SQLITE_NULL, TEXT etc.) */
- if( abPK && abPK[i]==0 ) continue;
- rc = sessionInputBuffer(pIn, 9);
- if( rc==SQLITE_OK ){
- eType = pIn->aData[pIn->iNext++];
- }
-
- assert( apOut[i]==0 );
- if( eType ){
- apOut[i] = sqlite3ValueNew(0);
- if( !apOut[i] ) rc = SQLITE_NOMEM;
- }
-
- if( rc==SQLITE_OK ){
- u8 *aVal = &pIn->aData[pIn->iNext];
- if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
- int nByte;
- pIn->iNext += sessionVarintGet(aVal, &nByte);
- rc = sessionInputBuffer(pIn, nByte);
- if( rc==SQLITE_OK ){
- u8 enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0);
- rc = sessionValueSetStr(apOut[i],&pIn->aData[pIn->iNext],nByte,enc);
- }
- pIn->iNext += nByte;
- }
- if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
- sqlite3_int64 v = sessionGetI64(aVal);
- if( eType==SQLITE_INTEGER ){
- sqlite3VdbeMemSetInt64(apOut[i], v);
- }else{
- double d;
- memcpy(&d, &v, 8);
- sqlite3VdbeMemSetDouble(apOut[i], d);
- }
- pIn->iNext += 8;
- }
- }
- }
-
- return rc;
-}
-
-/*
-** The input pointer currently points to the second byte of a table-header.
-** Specifically, to the following:
-**
-** + number of columns in table (varint)
-** + array of PK flags (1 byte per column),
-** + table name (nul terminated).
-**
-** This function ensures that all of the above is present in the input
-** buffer (i.e. that it can be accessed without any calls to xInput()).
-** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code.
-** The input pointer is not moved.
-*/
-static int sessionChangesetBufferTblhdr(SessionInput *pIn, int *pnByte){
- int rc = SQLITE_OK;
- int nCol = 0;
- int nRead = 0;
-
- rc = sessionInputBuffer(pIn, 9);
- if( rc==SQLITE_OK ){
- nRead += sessionVarintGet(&pIn->aData[pIn->iNext + nRead], &nCol);
- rc = sessionInputBuffer(pIn, nRead+nCol+100);
- nRead += nCol;
- }
-
- while( rc==SQLITE_OK ){
- while( (pIn->iNext + nRead)<pIn->nData && pIn->aData[pIn->iNext + nRead] ){
- nRead++;
- }
- if( (pIn->iNext + nRead)<pIn->nData ) break;
- rc = sessionInputBuffer(pIn, nRead + 100);
- }
- *pnByte = nRead+1;
- return rc;
-}
-
-/*
-** The input pointer currently points to the first byte of the first field
-** of a record consisting of nCol columns. This function ensures the entire
-** record is buffered. It does not move the input pointer.
-**
-** If successful, SQLITE_OK is returned and *pnByte is set to the size of
-** the record in bytes. Otherwise, an SQLite error code is returned. The
-** final value of *pnByte is undefined in this case.
-*/
-static int sessionChangesetBufferRecord(
- SessionInput *pIn, /* Input data */
- int nCol, /* Number of columns in record */
- int *pnByte /* OUT: Size of record in bytes */
-){
- int rc = SQLITE_OK;
- int nByte = 0;
- int i;
- for(i=0; rc==SQLITE_OK && i<nCol; i++){
- int eType;
- rc = sessionInputBuffer(pIn, nByte + 10);
- if( rc==SQLITE_OK ){
- eType = pIn->aData[pIn->iNext + nByte++];
- if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
- int n;
- nByte += sessionVarintGet(&pIn->aData[pIn->iNext+nByte], &n);
- nByte += n;
- rc = sessionInputBuffer(pIn, nByte);
- }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
- nByte += 8;
- }
- }
- }
- *pnByte = nByte;
- return rc;
-}
-
-/*
-** The input pointer currently points to the second byte of a table-header.
-** Specifically, to the following:
-**
-** + number of columns in table (varint)
-** + array of PK flags (1 byte per column),
-** + table name (nul terminated).
-**
-** This function decodes the table-header and populates the p->nCol,
-** p->zTab and p->abPK[] variables accordingly. The p->apValue[] array is
-** also allocated or resized according to the new value of p->nCol. The
-** input pointer is left pointing to the byte following the table header.
-**
-** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code
-** is returned and the final values of the various fields enumerated above
-** are undefined.
-*/
-static int sessionChangesetReadTblhdr(sqlite3_changeset_iter *p){
- int rc;
- int nCopy;
- assert( p->rc==SQLITE_OK );
-
- rc = sessionChangesetBufferTblhdr(&p->in, &nCopy);
- if( rc==SQLITE_OK ){
- int nByte;
- int nVarint;
- nVarint = sessionVarintGet(&p->in.aData[p->in.iNext], &p->nCol);
- nCopy -= nVarint;
- p->in.iNext += nVarint;
- nByte = p->nCol * sizeof(sqlite3_value*) * 2 + nCopy;
- p->tblhdr.nBuf = 0;
- sessionBufferGrow(&p->tblhdr, nByte, &rc);
- }
-
- if( rc==SQLITE_OK ){
- int iPK = sizeof(sqlite3_value*)*p->nCol*2;
- memset(p->tblhdr.aBuf, 0, iPK);
- memcpy(&p->tblhdr.aBuf[iPK], &p->in.aData[p->in.iNext], nCopy);
- p->in.iNext += nCopy;
- }
-
- p->apValue = (sqlite3_value**)p->tblhdr.aBuf;
- p->abPK = (u8*)&p->apValue[p->nCol*2];
- p->zTab = (char*)&p->abPK[p->nCol];
- return (p->rc = rc);
-}
-
-/*
-** Advance the changeset iterator to the next change.
-**
-** If both paRec and pnRec are NULL, then this function works like the public
-** API sqlite3changeset_next(). If SQLITE_ROW is returned, then the
-** sqlite3changeset_new() and old() APIs may be used to query for values.
-**
-** Otherwise, if paRec and pnRec are not NULL, then a pointer to the change
-** record is written to *paRec before returning and the number of bytes in
-** the record to *pnRec.
-**
-** Either way, this function returns SQLITE_ROW if the iterator is
-** successfully advanced to the next change in the changeset, an SQLite
-** error code if an error occurs, or SQLITE_DONE if there are no further
-** changes in the changeset.
-*/
-static int sessionChangesetNext(
- sqlite3_changeset_iter *p, /* Changeset iterator */
- u8 **paRec, /* If non-NULL, store record pointer here */
- int *pnRec /* If non-NULL, store size of record here */
-){
- int i;
- u8 op;
-
- assert( (paRec==0 && pnRec==0) || (paRec && pnRec) );
-
- /* If the iterator is in the error-state, return immediately. */
- if( p->rc!=SQLITE_OK ) return p->rc;
-
- /* Free the current contents of p->apValue[], if any. */
- if( p->apValue ){
- for(i=0; i<p->nCol*2; i++){
- sqlite3ValueFree(p->apValue[i]);
- }
- memset(p->apValue, 0, sizeof(sqlite3_value*)*p->nCol*2);
- }
-
- /* Make sure the buffer contains at least 10 bytes of input data, or all
- ** remaining data if there are less than 10 bytes available. This is
- ** sufficient either for the 'T' or 'P' byte and the varint that follows
- ** it, or for the two single byte values otherwise. */
- p->rc = sessionInputBuffer(&p->in, 2);
- if( p->rc!=SQLITE_OK ) return p->rc;
-
- /* If the iterator is already at the end of the changeset, return DONE. */
- if( p->in.iNext>=p->in.nData ){
- return SQLITE_DONE;
- }
-
- sessionDiscardData(&p->in);
- p->in.iCurrent = p->in.iNext;
-
- op = p->in.aData[p->in.iNext++];
- if( op=='T' || op=='P' ){
- p->bPatchset = (op=='P');
- if( sessionChangesetReadTblhdr(p) ) return p->rc;
- if( (p->rc = sessionInputBuffer(&p->in, 2)) ) return p->rc;
- p->in.iCurrent = p->in.iNext;
- op = p->in.aData[p->in.iNext++];
- }
-
- p->op = op;
- p->bIndirect = p->in.aData[p->in.iNext++];
- if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){
- return (p->rc = SQLITE_CORRUPT_BKPT);
- }
-
- if( paRec ){
- int nVal; /* Number of values to buffer */
- if( p->bPatchset==0 && op==SQLITE_UPDATE ){
- nVal = p->nCol * 2;
- }else if( p->bPatchset && op==SQLITE_DELETE ){
- nVal = 0;
- for(i=0; i<p->nCol; i++) if( p->abPK[i] ) nVal++;
- }else{
- nVal = p->nCol;
- }
- p->rc = sessionChangesetBufferRecord(&p->in, nVal, pnRec);
- if( p->rc!=SQLITE_OK ) return p->rc;
- *paRec = &p->in.aData[p->in.iNext];
- p->in.iNext += *pnRec;
- }else{
-
- /* If this is an UPDATE or DELETE, read the old.* record. */
- if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){
- u8 *abPK = p->bPatchset ? p->abPK : 0;
- p->rc = sessionReadRecord(&p->in, p->nCol, abPK, p->apValue);
- if( p->rc!=SQLITE_OK ) return p->rc;
- }
-
- /* If this is an INSERT or UPDATE, read the new.* record. */
- if( p->op!=SQLITE_DELETE ){
- p->rc = sessionReadRecord(&p->in, p->nCol, 0, &p->apValue[p->nCol]);
- if( p->rc!=SQLITE_OK ) return p->rc;
- }
-
- if( p->bPatchset && p->op==SQLITE_UPDATE ){
- /* If this is an UPDATE that is part of a patchset, then all PK and
- ** modified fields are present in the new.* record. The old.* record
- ** is currently completely empty. This block shifts the PK fields from
- ** new.* to old.*, to accommodate the code that reads these arrays. */
- for(i=0; i<p->nCol; i++){
- assert( p->apValue[i]==0 );
- assert( p->abPK[i]==0 || p->apValue[i+p->nCol] );
- if( p->abPK[i] ){
- p->apValue[i] = p->apValue[i+p->nCol];
- p->apValue[i+p->nCol] = 0;
- }
- }
- }
- }
-
- return SQLITE_ROW;
-}
-
-/*
-** Advance an iterator created by sqlite3changeset_start() to the next
-** change in the changeset. This function may return SQLITE_ROW, SQLITE_DONE
-** or SQLITE_CORRUPT.
-**
-** This function may not be called on iterators passed to a conflict handler
-** callback by changeset_apply().
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changeset_next(sqlite3_changeset_iter *p){
- return sessionChangesetNext(p, 0, 0);
-}
-
-/*
-** The following function extracts information on the current change
-** from a changeset iterator. It may only be called after changeset_next()
-** has returned SQLITE_ROW.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changeset_op(
- sqlite3_changeset_iter *pIter, /* Iterator handle */
- const char **pzTab, /* OUT: Pointer to table name */
- int *pnCol, /* OUT: Number of columns in table */
- int *pOp, /* OUT: SQLITE_INSERT, DELETE or UPDATE */
- int *pbIndirect /* OUT: True if change is indirect */
-){
- *pOp = pIter->op;
- *pnCol = pIter->nCol;
- *pzTab = pIter->zTab;
- if( pbIndirect ) *pbIndirect = pIter->bIndirect;
- return SQLITE_OK;
-}
-
-/*
-** Return information regarding the PRIMARY KEY and number of columns in
-** the database table affected by the change that pIter currently points
-** to. This function may only be called after changeset_next() returns
-** SQLITE_ROW.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changeset_pk(
- sqlite3_changeset_iter *pIter, /* Iterator object */
- unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */
- int *pnCol /* OUT: Number of entries in output array */
-){
- *pabPK = pIter->abPK;
- if( pnCol ) *pnCol = pIter->nCol;
- return SQLITE_OK;
-}
-
-/*
-** This function may only be called while the iterator is pointing to an
-** SQLITE_UPDATE or SQLITE_DELETE change (see sqlite3changeset_op()).
-** Otherwise, SQLITE_MISUSE is returned.
-**
-** It sets *ppValue to point to an sqlite3_value structure containing the
-** iVal'th value in the old.* record. Or, if that particular value is not
-** included in the record (because the change is an UPDATE and the field
-** was not modified and is not a PK column), set *ppValue to NULL.
-**
-** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is
-** not modified. Otherwise, SQLITE_OK.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changeset_old(
- sqlite3_changeset_iter *pIter, /* Changeset iterator */
- int iVal, /* Index of old.* value to retrieve */
- sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */
-){
- if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_DELETE ){
- return SQLITE_MISUSE;
- }
- if( iVal<0 || iVal>=pIter->nCol ){
- return SQLITE_RANGE;
- }
- *ppValue = pIter->apValue[iVal];
- return SQLITE_OK;
-}
-
-/*
-** This function may only be called while the iterator is pointing to an
-** SQLITE_UPDATE or SQLITE_INSERT change (see sqlite3changeset_op()).
-** Otherwise, SQLITE_MISUSE is returned.
-**
-** It sets *ppValue to point to an sqlite3_value structure containing the
-** iVal'th value in the new.* record. Or, if that particular value is not
-** included in the record (because the change is an UPDATE and the field
-** was not modified), set *ppValue to NULL.
-**
-** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is
-** not modified. Otherwise, SQLITE_OK.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changeset_new(
- sqlite3_changeset_iter *pIter, /* Changeset iterator */
- int iVal, /* Index of new.* value to retrieve */
- sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */
-){
- if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_INSERT ){
- return SQLITE_MISUSE;
- }
- if( iVal<0 || iVal>=pIter->nCol ){
- return SQLITE_RANGE;
- }
- *ppValue = pIter->apValue[pIter->nCol+iVal];
- return SQLITE_OK;
-}
-
-/*
-** The following two macros are used internally. They are similar to the
-** sqlite3changeset_new() and sqlite3changeset_old() functions, except that
-** they omit all error checking and return a pointer to the requested value.
-*/
-#define sessionChangesetNew(pIter, iVal) (pIter)->apValue[(pIter)->nCol+(iVal)]
-#define sessionChangesetOld(pIter, iVal) (pIter)->apValue[(iVal)]
-
-/*
-** This function may only be called with a changeset iterator that has been
-** passed to an SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT
-** conflict-handler function. Otherwise, SQLITE_MISUSE is returned.
-**
-** If successful, *ppValue is set to point to an sqlite3_value structure
-** containing the iVal'th value of the conflicting record.
-**
-** If value iVal is out-of-range or some other error occurs, an SQLite error
-** code is returned. Otherwise, SQLITE_OK.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changeset_conflict(
- sqlite3_changeset_iter *pIter, /* Changeset iterator */
- int iVal, /* Index of conflict record value to fetch */
- sqlite3_value **ppValue /* OUT: Value from conflicting row */
-){
- if( !pIter->pConflict ){
- return SQLITE_MISUSE;
- }
- if( iVal<0 || iVal>=sqlite3_column_count(pIter->pConflict) ){
- return SQLITE_RANGE;
- }
- *ppValue = sqlite3_column_value(pIter->pConflict, iVal);
- return SQLITE_OK;
-}
-
-/*
-** This function may only be called with an iterator passed to an
-** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case
-** it sets the output variable to the total number of known foreign key
-** violations in the destination database and returns SQLITE_OK.
-**
-** In all other cases this function returns SQLITE_MISUSE.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changeset_fk_conflicts(
- sqlite3_changeset_iter *pIter, /* Changeset iterator */
- int *pnOut /* OUT: Number of FK violations */
-){
- if( pIter->pConflict || pIter->apValue ){
- return SQLITE_MISUSE;
- }
- *pnOut = pIter->nCol;
- return SQLITE_OK;
-}
-
-
-/*
-** Finalize an iterator allocated with sqlite3changeset_start().
-**
-** This function may not be called on iterators passed to a conflict handler
-** callback by changeset_apply().
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changeset_finalize(sqlite3_changeset_iter *p){
- int rc = SQLITE_OK;
- if( p ){
- int i; /* Used to iterate through p->apValue[] */
- rc = p->rc;
- if( p->apValue ){
- for(i=0; i<p->nCol*2; i++) sqlite3ValueFree(p->apValue[i]);
- }
- sqlite3_free(p->tblhdr.aBuf);
- sqlite3_free(p->in.buf.aBuf);
- sqlite3_free(p);
- }
- return rc;
-}
-
-static int sessionChangesetInvert(
- SessionInput *pInput, /* Input changeset */
- int (*xOutput)(void *pOut, const void *pData, int nData),
- void *pOut,
- int *pnInverted, /* OUT: Number of bytes in output changeset */
- void **ppInverted /* OUT: Inverse of pChangeset */
-){
- int rc = SQLITE_OK; /* Return value */
- SessionBuffer sOut; /* Output buffer */
- int nCol = 0; /* Number of cols in current table */
- u8 *abPK = 0; /* PK array for current table */
- sqlite3_value **apVal = 0; /* Space for values for UPDATE inversion */
- SessionBuffer sPK = {0, 0, 0}; /* PK array for current table */
-
- /* Initialize the output buffer */
- memset(&sOut, 0, sizeof(SessionBuffer));
-
- /* Zero the output variables in case an error occurs. */
- if( ppInverted ){
- *ppInverted = 0;
- *pnInverted = 0;
- }
-
- while( 1 ){
- u8 eType;
-
- /* Test for EOF. */
- if( (rc = sessionInputBuffer(pInput, 2)) ) goto finished_invert;
- if( pInput->iNext>=pInput->nData ) break;
- eType = pInput->aData[pInput->iNext];
-
- switch( eType ){
- case 'T': {
- /* A 'table' record consists of:
- **
- ** * A constant 'T' character,
- ** * Number of columns in said table (a varint),
- ** * An array of nCol bytes (sPK),
- ** * A nul-terminated table name.
- */
- int nByte;
- int nVar;
- pInput->iNext++;
- if( (rc = sessionChangesetBufferTblhdr(pInput, &nByte)) ){
- goto finished_invert;
- }
- nVar = sessionVarintGet(&pInput->aData[pInput->iNext], &nCol);
- sPK.nBuf = 0;
- sessionAppendBlob(&sPK, &pInput->aData[pInput->iNext+nVar], nCol, &rc);
- sessionAppendByte(&sOut, eType, &rc);
- sessionAppendBlob(&sOut, &pInput->aData[pInput->iNext], nByte, &rc);
- if( rc ) goto finished_invert;
-
- pInput->iNext += nByte;
- sqlite3_free(apVal);
- apVal = 0;
- abPK = sPK.aBuf;
- break;
- }
-
- case SQLITE_INSERT:
- case SQLITE_DELETE: {
- int nByte;
- int bIndirect = pInput->aData[pInput->iNext+1];
- int eType2 = (eType==SQLITE_DELETE ? SQLITE_INSERT : SQLITE_DELETE);
- pInput->iNext += 2;
- assert( rc==SQLITE_OK );
- rc = sessionChangesetBufferRecord(pInput, nCol, &nByte);
- sessionAppendByte(&sOut, eType2, &rc);
- sessionAppendByte(&sOut, bIndirect, &rc);
- sessionAppendBlob(&sOut, &pInput->aData[pInput->iNext], nByte, &rc);
- pInput->iNext += nByte;
- if( rc ) goto finished_invert;
- break;
- }
-
- case SQLITE_UPDATE: {
- int iCol;
-
- if( 0==apVal ){
- apVal = (sqlite3_value **)sqlite3_malloc(sizeof(apVal[0])*nCol*2);
- if( 0==apVal ){
- rc = SQLITE_NOMEM;
- goto finished_invert;
- }
- memset(apVal, 0, sizeof(apVal[0])*nCol*2);
- }
-
- /* Write the header for the new UPDATE change. Same as the original. */
- sessionAppendByte(&sOut, eType, &rc);
- sessionAppendByte(&sOut, pInput->aData[pInput->iNext+1], &rc);
-
- /* Read the old.* and new.* records for the update change. */
- pInput->iNext += 2;
- rc = sessionReadRecord(pInput, nCol, 0, &apVal[0]);
- if( rc==SQLITE_OK ){
- rc = sessionReadRecord(pInput, nCol, 0, &apVal[nCol]);
- }
-
- /* Write the new old.* record. Consists of the PK columns from the
- ** original old.* record, and the other values from the original
- ** new.* record. */
- for(iCol=0; iCol<nCol; iCol++){
- sqlite3_value *pVal = apVal[iCol + (abPK[iCol] ? 0 : nCol)];
- sessionAppendValue(&sOut, pVal, &rc);
- }
-
- /* Write the new new.* record. Consists of a copy of all values
- ** from the original old.* record, except for the PK columns, which
- ** are set to "undefined". */
- for(iCol=0; iCol<nCol; iCol++){
- sqlite3_value *pVal = (abPK[iCol] ? 0 : apVal[iCol]);
- sessionAppendValue(&sOut, pVal, &rc);
- }
-
- for(iCol=0; iCol<nCol*2; iCol++){
- sqlite3ValueFree(apVal[iCol]);
- }
- memset(apVal, 0, sizeof(apVal[0])*nCol*2);
- if( rc!=SQLITE_OK ){
- goto finished_invert;
- }
-
- break;
- }
-
- default:
- rc = SQLITE_CORRUPT_BKPT;
- goto finished_invert;
- }
-
- assert( rc==SQLITE_OK );
- if( xOutput && sOut.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){
- rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
- sOut.nBuf = 0;
- if( rc!=SQLITE_OK ) goto finished_invert;
- }
- }
-
- assert( rc==SQLITE_OK );
- if( pnInverted ){
- *pnInverted = sOut.nBuf;
- *ppInverted = sOut.aBuf;
- sOut.aBuf = 0;
- }else if( sOut.nBuf>0 ){
- rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
- }
-
- finished_invert:
- sqlite3_free(sOut.aBuf);
- sqlite3_free(apVal);
- sqlite3_free(sPK.aBuf);
- return rc;
-}
-
-
-/*
-** Invert a changeset object.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changeset_invert(
- int nChangeset, /* Number of bytes in input */
- const void *pChangeset, /* Input changeset */
- int *pnInverted, /* OUT: Number of bytes in output changeset */
- void **ppInverted /* OUT: Inverse of pChangeset */
-){
- SessionInput sInput;
-
- /* Set up the input stream */
- memset(&sInput, 0, sizeof(SessionInput));
- sInput.nData = nChangeset;
- sInput.aData = (u8*)pChangeset;
-
- return sessionChangesetInvert(&sInput, 0, 0, pnInverted, ppInverted);
-}
-
-/*
-** Streaming version of sqlite3changeset_invert().
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changeset_invert_strm(
- int (*xInput)(void *pIn, void *pData, int *pnData),
- void *pIn,
- int (*xOutput)(void *pOut, const void *pData, int nData),
- void *pOut
-){
- SessionInput sInput;
- int rc;
-
- /* Set up the input stream */
- memset(&sInput, 0, sizeof(SessionInput));
- sInput.xInput = xInput;
- sInput.pIn = pIn;
-
- rc = sessionChangesetInvert(&sInput, xOutput, pOut, 0, 0);
- sqlite3_free(sInput.buf.aBuf);
- return rc;
-}
-
-typedef struct SessionApplyCtx SessionApplyCtx;
-struct SessionApplyCtx {
- sqlite3 *db;
- sqlite3_stmt *pDelete; /* DELETE statement */
- sqlite3_stmt *pUpdate; /* UPDATE statement */
- sqlite3_stmt *pInsert; /* INSERT statement */
- sqlite3_stmt *pSelect; /* SELECT statement */
- int nCol; /* Size of azCol[] and abPK[] arrays */
- const char **azCol; /* Array of column names */
- u8 *abPK; /* Boolean array - true if column is in PK */
-
- int bDeferConstraints; /* True to defer constraints */
- SessionBuffer constraints; /* Deferred constraints are stored here */
-};
-
-/*
-** Formulate a statement to DELETE a row from database db. Assuming a table
-** structure like this:
-**
-** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
-**
-** The DELETE statement looks like this:
-**
-** DELETE FROM x WHERE a = :1 AND c = :3 AND (:5 OR b IS :2 AND d IS :4)
-**
-** Variable :5 (nCol+1) is a boolean. It should be set to 0 if we require
-** matching b and d values, or 1 otherwise. The second case comes up if the
-** conflict handler is invoked with NOTFOUND and returns CHANGESET_REPLACE.
-**
-** If successful, SQLITE_OK is returned and SessionApplyCtx.pDelete is left
-** pointing to the prepared version of the SQL statement.
-*/
-static int sessionDeleteRow(
- sqlite3 *db, /* Database handle */
- const char *zTab, /* Table name */
- SessionApplyCtx *p /* Session changeset-apply context */
-){
- int i;
- const char *zSep = "";
- int rc = SQLITE_OK;
- SessionBuffer buf = {0, 0, 0};
- int nPk = 0;
-
- sessionAppendStr(&buf, "DELETE FROM ", &rc);
- sessionAppendIdent(&buf, zTab, &rc);
- sessionAppendStr(&buf, " WHERE ", &rc);
-
- for(i=0; i<p->nCol; i++){
- if( p->abPK[i] ){
- nPk++;
- sessionAppendStr(&buf, zSep, &rc);
- sessionAppendIdent(&buf, p->azCol[i], &rc);
- sessionAppendStr(&buf, " = ?", &rc);
- sessionAppendInteger(&buf, i+1, &rc);
- zSep = " AND ";
- }
- }
-
- if( nPk<p->nCol ){
- sessionAppendStr(&buf, " AND (?", &rc);
- sessionAppendInteger(&buf, p->nCol+1, &rc);
- sessionAppendStr(&buf, " OR ", &rc);
-
- zSep = "";
- for(i=0; i<p->nCol; i++){
- if( !p->abPK[i] ){
- sessionAppendStr(&buf, zSep, &rc);
- sessionAppendIdent(&buf, p->azCol[i], &rc);
- sessionAppendStr(&buf, " IS ?", &rc);
- sessionAppendInteger(&buf, i+1, &rc);
- zSep = "AND ";
- }
- }
- sessionAppendStr(&buf, ")", &rc);
- }
-
- if( rc==SQLITE_OK ){
- rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pDelete, 0);
- }
- sqlite3_free(buf.aBuf);
-
- return rc;
-}
-
-/*
-** Formulate and prepare a statement to UPDATE a row from database db.
-** Assuming a table structure like this:
-**
-** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
-**
-** The UPDATE statement looks like this:
-**
-** UPDATE x SET
-** a = CASE WHEN ?2 THEN ?3 ELSE a END,
-** b = CASE WHEN ?5 THEN ?6 ELSE b END,
-** c = CASE WHEN ?8 THEN ?9 ELSE c END,
-** d = CASE WHEN ?11 THEN ?12 ELSE d END
-** WHERE a = ?1 AND c = ?7 AND (?13 OR
-** (?5==0 OR b IS ?4) AND (?11==0 OR d IS ?10) AND
-** )
-**
-** For each column in the table, there are three variables to bind:
-**
-** ?(i*3+1) The old.* value of the column, if any.
-** ?(i*3+2) A boolean flag indicating that the value is being modified.
-** ?(i*3+3) The new.* value of the column, if any.
-**
-** Also, a boolean flag that, if set to true, causes the statement to update
-** a row even if the non-PK values do not match. This is required if the
-** conflict-handler is invoked with CHANGESET_DATA and returns
-** CHANGESET_REPLACE. This is variable "?(nCol*3+1)".
-**
-** If successful, SQLITE_OK is returned and SessionApplyCtx.pUpdate is left
-** pointing to the prepared version of the SQL statement.
-*/
-static int sessionUpdateRow(
- sqlite3 *db, /* Database handle */
- const char *zTab, /* Table name */
- SessionApplyCtx *p /* Session changeset-apply context */
-){
- int rc = SQLITE_OK;
- int i;
- const char *zSep = "";
- SessionBuffer buf = {0, 0, 0};
-
- /* Append "UPDATE tbl SET " */
- sessionAppendStr(&buf, "UPDATE ", &rc);
- sessionAppendIdent(&buf, zTab, &rc);
- sessionAppendStr(&buf, " SET ", &rc);
-
- /* Append the assignments */
- for(i=0; i<p->nCol; i++){
- sessionAppendStr(&buf, zSep, &rc);
- sessionAppendIdent(&buf, p->azCol[i], &rc);
- sessionAppendStr(&buf, " = CASE WHEN ?", &rc);
- sessionAppendInteger(&buf, i*3+2, &rc);
- sessionAppendStr(&buf, " THEN ?", &rc);
- sessionAppendInteger(&buf, i*3+3, &rc);
- sessionAppendStr(&buf, " ELSE ", &rc);
- sessionAppendIdent(&buf, p->azCol[i], &rc);
- sessionAppendStr(&buf, " END", &rc);
- zSep = ", ";
- }
-
- /* Append the PK part of the WHERE clause */
- sessionAppendStr(&buf, " WHERE ", &rc);
- for(i=0; i<p->nCol; i++){
- if( p->abPK[i] ){
- sessionAppendIdent(&buf, p->azCol[i], &rc);
- sessionAppendStr(&buf, " = ?", &rc);
- sessionAppendInteger(&buf, i*3+1, &rc);
- sessionAppendStr(&buf, " AND ", &rc);
- }
- }
-
- /* Append the non-PK part of the WHERE clause */
- sessionAppendStr(&buf, " (?", &rc);
- sessionAppendInteger(&buf, p->nCol*3+1, &rc);
- sessionAppendStr(&buf, " OR 1", &rc);
- for(i=0; i<p->nCol; i++){
- if( !p->abPK[i] ){
- sessionAppendStr(&buf, " AND (?", &rc);
- sessionAppendInteger(&buf, i*3+2, &rc);
- sessionAppendStr(&buf, "=0 OR ", &rc);
- sessionAppendIdent(&buf, p->azCol[i], &rc);
- sessionAppendStr(&buf, " IS ?", &rc);
- sessionAppendInteger(&buf, i*3+1, &rc);
- sessionAppendStr(&buf, ")", &rc);
- }
- }
- sessionAppendStr(&buf, ")", &rc);
-
- if( rc==SQLITE_OK ){
- rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pUpdate, 0);
- }
- sqlite3_free(buf.aBuf);
-
- return rc;
-}
-
-/*
-** Formulate and prepare an SQL statement to query table zTab by primary
-** key. Assuming the following table structure:
-**
-** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
-**
-** The SELECT statement looks like this:
-**
-** SELECT * FROM x WHERE a = ?1 AND c = ?3
-**
-** If successful, SQLITE_OK is returned and SessionApplyCtx.pSelect is left
-** pointing to the prepared version of the SQL statement.
-*/
-static int sessionSelectRow(
- sqlite3 *db, /* Database handle */
- const char *zTab, /* Table name */
- SessionApplyCtx *p /* Session changeset-apply context */
-){
- return sessionSelectStmt(
- db, "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect);
-}
-
-/*
-** Formulate and prepare an INSERT statement to add a record to table zTab.
-** For example:
-**
-** INSERT INTO main."zTab" VALUES(?1, ?2, ?3 ...);
-**
-** If successful, SQLITE_OK is returned and SessionApplyCtx.pInsert is left
-** pointing to the prepared version of the SQL statement.
-*/
-static int sessionInsertRow(
- sqlite3 *db, /* Database handle */
- const char *zTab, /* Table name */
- SessionApplyCtx *p /* Session changeset-apply context */
-){
- int rc = SQLITE_OK;
- int i;
- SessionBuffer buf = {0, 0, 0};
-
- sessionAppendStr(&buf, "INSERT INTO main.", &rc);
- sessionAppendIdent(&buf, zTab, &rc);
- sessionAppendStr(&buf, " VALUES(?", &rc);
- for(i=1; i<p->nCol; i++){
- sessionAppendStr(&buf, ", ?", &rc);
- }
- sessionAppendStr(&buf, ")", &rc);
-
- if( rc==SQLITE_OK ){
- rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pInsert, 0);
- }
- sqlite3_free(buf.aBuf);
- return rc;
-}
-
-/*
-** A wrapper around sqlite3_bind_value() that detects an extra problem.
-** See comments in the body of this function for details.
-*/
-static int sessionBindValue(
- sqlite3_stmt *pStmt, /* Statement to bind value to */
- int i, /* Parameter number to bind to */
- sqlite3_value *pVal /* Value to bind */
-){
- int eType = sqlite3_value_type(pVal);
- /* COVERAGE: The (pVal->z==0) branch is never true using current versions
- ** of SQLite. If a malloc fails in an sqlite3_value_xxx() function, either
- ** the (pVal->z) variable remains as it was or the type of the value is
- ** set to SQLITE_NULL. */
- if( (eType==SQLITE_TEXT || eType==SQLITE_BLOB) && pVal->z==0 ){
- /* This condition occurs when an earlier OOM in a call to
- ** sqlite3_value_text() or sqlite3_value_blob() (perhaps from within
- ** a conflict-handler) has zeroed the pVal->z pointer. Return NOMEM. */
- return SQLITE_NOMEM;
- }
- return sqlite3_bind_value(pStmt, i, pVal);
-}
-
-/*
-** Iterator pIter must point to an SQLITE_INSERT entry. This function
-** transfers new.* values from the current iterator entry to statement
-** pStmt. The table being inserted into has nCol columns.
-**
-** New.* value $i from the iterator is bound to variable ($i+1) of
-** statement pStmt. If parameter abPK is NULL, all values from 0 to (nCol-1)
-** are transfered to the statement. Otherwise, if abPK is not NULL, it points
-** to an array nCol elements in size. In this case only those values for
-** which abPK[$i] is true are read from the iterator and bound to the
-** statement.
-**
-** An SQLite error code is returned if an error occurs. Otherwise, SQLITE_OK.
-*/
-static int sessionBindRow(
- sqlite3_changeset_iter *pIter, /* Iterator to read values from */
- int(*xValue)(sqlite3_changeset_iter *, int, sqlite3_value **),
- int nCol, /* Number of columns */
- u8 *abPK, /* If not NULL, bind only if true */
- sqlite3_stmt *pStmt /* Bind values to this statement */
-){
- int i;
- int rc = SQLITE_OK;
-
- /* Neither sqlite3changeset_old or sqlite3changeset_new can fail if the
- ** argument iterator points to a suitable entry. Make sure that xValue
- ** is one of these to guarantee that it is safe to ignore the return
- ** in the code below. */
- assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new );
-
- for(i=0; rc==SQLITE_OK && i<nCol; i++){
- if( !abPK || abPK[i] ){
- sqlite3_value *pVal;
- (void)xValue(pIter, i, &pVal);
- rc = sessionBindValue(pStmt, i+1, pVal);
- }
- }
- return rc;
-}
-
-/*
-** SQL statement pSelect is as generated by the sessionSelectRow() function.
-** This function binds the primary key values from the change that changeset
-** iterator pIter points to to the SELECT and attempts to seek to the table
-** entry. If a row is found, the SELECT statement left pointing at the row
-** and SQLITE_ROW is returned. Otherwise, if no row is found and no error
-** has occured, the statement is reset and SQLITE_OK is returned. If an
-** error occurs, the statement is reset and an SQLite error code is returned.
-**
-** If this function returns SQLITE_ROW, the caller must eventually reset()
-** statement pSelect. If any other value is returned, the statement does
-** not require a reset().
-**
-** If the iterator currently points to an INSERT record, bind values from the
-** new.* record to the SELECT statement. Or, if it points to a DELETE or
-** UPDATE, bind values from the old.* record.
-*/
-static int sessionSeekToRow(
- sqlite3 *db, /* Database handle */
- sqlite3_changeset_iter *pIter, /* Changeset iterator */
- u8 *abPK, /* Primary key flags array */
- sqlite3_stmt *pSelect /* SELECT statement from sessionSelectRow() */
-){
- int rc; /* Return code */
- int nCol; /* Number of columns in table */
- int op; /* Changset operation (SQLITE_UPDATE etc.) */
- const char *zDummy; /* Unused */
-
- sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
- rc = sessionBindRow(pIter,
- op==SQLITE_INSERT ? sqlite3changeset_new : sqlite3changeset_old,
- nCol, abPK, pSelect
- );
-
- if( rc==SQLITE_OK ){
- rc = sqlite3_step(pSelect);
- if( rc!=SQLITE_ROW ) rc = sqlite3_reset(pSelect);
- }
-
- return rc;
-}
-
-/*
-** Invoke the conflict handler for the change that the changeset iterator
-** currently points to.
-**
-** Argument eType must be either CHANGESET_DATA or CHANGESET_CONFLICT.
-** If argument pbReplace is NULL, then the type of conflict handler invoked
-** depends solely on eType, as follows:
-**
-** eType value Value passed to xConflict
-** -------------------------------------------------
-** CHANGESET_DATA CHANGESET_NOTFOUND
-** CHANGESET_CONFLICT CHANGESET_CONSTRAINT
-**
-** Or, if pbReplace is not NULL, then an attempt is made to find an existing
-** record with the same primary key as the record about to be deleted, updated
-** or inserted. If such a record can be found, it is available to the conflict
-** handler as the "conflicting" record. In this case the type of conflict
-** handler invoked is as follows:
-**
-** eType value PK Record found? Value passed to xConflict
-** ----------------------------------------------------------------
-** CHANGESET_DATA Yes CHANGESET_DATA
-** CHANGESET_DATA No CHANGESET_NOTFOUND
-** CHANGESET_CONFLICT Yes CHANGESET_CONFLICT
-** CHANGESET_CONFLICT No CHANGESET_CONSTRAINT
-**
-** If pbReplace is not NULL, and a record with a matching PK is found, and
-** the conflict handler function returns SQLITE_CHANGESET_REPLACE, *pbReplace
-** is set to non-zero before returning SQLITE_OK.
-**
-** If the conflict handler returns SQLITE_CHANGESET_ABORT, SQLITE_ABORT is
-** returned. Or, if the conflict handler returns an invalid value,
-** SQLITE_MISUSE. If the conflict handler returns SQLITE_CHANGESET_OMIT,
-** this function returns SQLITE_OK.
-*/
-static int sessionConflictHandler(
- int eType, /* Either CHANGESET_DATA or CONFLICT */
- SessionApplyCtx *p, /* changeset_apply() context */
- sqlite3_changeset_iter *pIter, /* Changeset iterator */
- int(*xConflict)(void *, int, sqlite3_changeset_iter*),
- void *pCtx, /* First argument for conflict handler */
- int *pbReplace /* OUT: Set to true if PK row is found */
-){
- int res = 0; /* Value returned by conflict handler */
- int rc;
- int nCol;
- int op;
- const char *zDummy;
-
- sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
-
- assert( eType==SQLITE_CHANGESET_CONFLICT || eType==SQLITE_CHANGESET_DATA );
- assert( SQLITE_CHANGESET_CONFLICT+1==SQLITE_CHANGESET_CONSTRAINT );
- assert( SQLITE_CHANGESET_DATA+1==SQLITE_CHANGESET_NOTFOUND );
-
- /* Bind the new.* PRIMARY KEY values to the SELECT statement. */
- if( pbReplace ){
- rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
- }else{
- rc = SQLITE_OK;
- }
-
- if( rc==SQLITE_ROW ){
- /* There exists another row with the new.* primary key. */
- pIter->pConflict = p->pSelect;
- res = xConflict(pCtx, eType, pIter);
- pIter->pConflict = 0;
- rc = sqlite3_reset(p->pSelect);
- }else if( rc==SQLITE_OK ){
- if( p->bDeferConstraints && eType==SQLITE_CHANGESET_CONFLICT ){
- /* Instead of invoking the conflict handler, append the change blob
- ** to the SessionApplyCtx.constraints buffer. */
- u8 *aBlob = &pIter->in.aData[pIter->in.iCurrent];
- int nBlob = pIter->in.iNext - pIter->in.iCurrent;
- sessionAppendBlob(&p->constraints, aBlob, nBlob, &rc);
- res = SQLITE_CHANGESET_OMIT;
- }else{
- /* No other row with the new.* primary key. */
- res = xConflict(pCtx, eType+1, pIter);
- if( res==SQLITE_CHANGESET_REPLACE ) rc = SQLITE_MISUSE;
- }
- }
-
- if( rc==SQLITE_OK ){
- switch( res ){
- case SQLITE_CHANGESET_REPLACE:
- assert( pbReplace );
- *pbReplace = 1;
- break;
-
- case SQLITE_CHANGESET_OMIT:
- break;
-
- case SQLITE_CHANGESET_ABORT:
- rc = SQLITE_ABORT;
- break;
-
- default:
- rc = SQLITE_MISUSE;
- break;
- }
- }
-
- return rc;
-}
-
-/*
-** Attempt to apply the change that the iterator passed as the first argument
-** currently points to to the database. If a conflict is encountered, invoke
-** the conflict handler callback.
-**
-** If argument pbRetry is NULL, then ignore any CHANGESET_DATA conflict. If
-** one is encountered, update or delete the row with the matching primary key
-** instead. Or, if pbRetry is not NULL and a CHANGESET_DATA conflict occurs,
-** invoke the conflict handler. If it returns CHANGESET_REPLACE, set *pbRetry
-** to true before returning. In this case the caller will invoke this function
-** again, this time with pbRetry set to NULL.
-**
-** If argument pbReplace is NULL and a CHANGESET_CONFLICT conflict is
-** encountered invoke the conflict handler with CHANGESET_CONSTRAINT instead.
-** Or, if pbReplace is not NULL, invoke it with CHANGESET_CONFLICT. If such
-** an invocation returns SQLITE_CHANGESET_REPLACE, set *pbReplace to true
-** before retrying. In this case the caller attempts to remove the conflicting
-** row before invoking this function again, this time with pbReplace set
-** to NULL.
-**
-** If any conflict handler returns SQLITE_CHANGESET_ABORT, this function
-** returns SQLITE_ABORT. Otherwise, if no error occurs, SQLITE_OK is
-** returned.
-*/
-static int sessionApplyOneOp(
- sqlite3_changeset_iter *pIter, /* Changeset iterator */
- SessionApplyCtx *p, /* changeset_apply() context */
- int(*xConflict)(void *, int, sqlite3_changeset_iter *),
- void *pCtx, /* First argument for the conflict handler */
- int *pbReplace, /* OUT: True to remove PK row and retry */
- int *pbRetry /* OUT: True to retry. */
-){
- const char *zDummy;
- int op;
- int nCol;
- int rc = SQLITE_OK;
-
- assert( p->pDelete && p->pUpdate && p->pInsert && p->pSelect );
- assert( p->azCol && p->abPK );
- assert( !pbReplace || *pbReplace==0 );
-
- sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
-
- if( op==SQLITE_DELETE ){
-
- /* Bind values to the DELETE statement. If conflict handling is required,
- ** bind values for all columns and set bound variable (nCol+1) to true.
- ** Or, if conflict handling is not required, bind just the PK column
- ** values and, if it exists, set (nCol+1) to false. Conflict handling
- ** is not required if:
- **
- ** * this is a patchset, or
- ** * (pbRetry==0), or
- ** * all columns of the table are PK columns (in this case there is
- ** no (nCol+1) variable to bind to).
- */
- u8 *abPK = (pIter->bPatchset ? p->abPK : 0);
- rc = sessionBindRow(pIter, sqlite3changeset_old, nCol, abPK, p->pDelete);
- if( rc==SQLITE_OK && sqlite3_bind_parameter_count(p->pDelete)>nCol ){
- rc = sqlite3_bind_int(p->pDelete, nCol+1, (pbRetry==0 || abPK));
- }
- if( rc!=SQLITE_OK ) return rc;
-
- sqlite3_step(p->pDelete);
- rc = sqlite3_reset(p->pDelete);
- if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
- rc = sessionConflictHandler(
- SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
- );
- }else if( (rc&0xff)==SQLITE_CONSTRAINT ){
- rc = sessionConflictHandler(
- SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0
- );
- }
-
- }else if( op==SQLITE_UPDATE ){
- int i;
-
- /* Bind values to the UPDATE statement. */
- for(i=0; rc==SQLITE_OK && i<nCol; i++){
- sqlite3_value *pOld = sessionChangesetOld(pIter, i);
- sqlite3_value *pNew = sessionChangesetNew(pIter, i);
-
- sqlite3_bind_int(p->pUpdate, i*3+2, !!pNew);
- if( pOld ){
- rc = sessionBindValue(p->pUpdate, i*3+1, pOld);
- }
- if( rc==SQLITE_OK && pNew ){
- rc = sessionBindValue(p->pUpdate, i*3+3, pNew);
- }
- }
- if( rc==SQLITE_OK ){
- sqlite3_bind_int(p->pUpdate, nCol*3+1, pbRetry==0 || pIter->bPatchset);
- }
- if( rc!=SQLITE_OK ) return rc;
-
- /* Attempt the UPDATE. In the case of a NOTFOUND or DATA conflict,
- ** the result will be SQLITE_OK with 0 rows modified. */
- sqlite3_step(p->pUpdate);
- rc = sqlite3_reset(p->pUpdate);
-
- if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
- /* A NOTFOUND or DATA error. Search the table to see if it contains
- ** a row with a matching primary key. If so, this is a DATA conflict.
- ** Otherwise, if there is no primary key match, it is a NOTFOUND. */
-
- rc = sessionConflictHandler(
- SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
- );
-
- }else if( (rc&0xff)==SQLITE_CONSTRAINT ){
- /* This is always a CONSTRAINT conflict. */
- rc = sessionConflictHandler(
- SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0
- );
- }
-
- }else{
- assert( op==SQLITE_INSERT );
- rc = sessionBindRow(pIter, sqlite3changeset_new, nCol, 0, p->pInsert);
- if( rc!=SQLITE_OK ) return rc;
-
- sqlite3_step(p->pInsert);
- rc = sqlite3_reset(p->pInsert);
- if( (rc&0xff)==SQLITE_CONSTRAINT ){
- rc = sessionConflictHandler(
- SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, pbReplace
- );
- }
- }
-
- return rc;
-}
-
-/*
-** Attempt to apply the change that the iterator passed as the first argument
-** currently points to to the database. If a conflict is encountered, invoke
-** the conflict handler callback.
-**
-** The difference between this function and sessionApplyOne() is that this
-** function handles the case where the conflict-handler is invoked and
-** returns SQLITE_CHANGESET_REPLACE - indicating that the change should be
-** retried in some manner.
-*/
-static int sessionApplyOneWithRetry(
- sqlite3 *db, /* Apply change to "main" db of this handle */
- sqlite3_changeset_iter *pIter, /* Changeset iterator to read change from */
- SessionApplyCtx *pApply, /* Apply context */
- int(*xConflict)(void*, int, sqlite3_changeset_iter*),
- void *pCtx /* First argument passed to xConflict */
-){
- int bReplace = 0;
- int bRetry = 0;
- int rc;
-
- rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, &bReplace, &bRetry);
- assert( rc==SQLITE_OK || (bRetry==0 && bReplace==0) );
-
- /* If the bRetry flag is set, the change has not been applied due to an
- ** SQLITE_CHANGESET_DATA problem (i.e. this is an UPDATE or DELETE and
- ** a row with the correct PK is present in the db, but one or more other
- ** fields do not contain the expected values) and the conflict handler
- ** returned SQLITE_CHANGESET_REPLACE. In this case retry the operation,
- ** but pass NULL as the final argument so that sessionApplyOneOp() ignores
- ** the SQLITE_CHANGESET_DATA problem. */
- if( bRetry ){
- assert( pIter->op==SQLITE_UPDATE || pIter->op==SQLITE_DELETE );
- rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0);
- }
-
- /* If the bReplace flag is set, the change is an INSERT that has not
- ** been performed because the database already contains a row with the
- ** specified primary key and the conflict handler returned
- ** SQLITE_CHANGESET_REPLACE. In this case remove the conflicting row
- ** before reattempting the INSERT. */
- else if( bReplace ){
- assert( pIter->op==SQLITE_INSERT );
- rc = sqlite3_exec(db, "SAVEPOINT replace_op", 0, 0, 0);
- if( rc==SQLITE_OK ){
- rc = sessionBindRow(pIter,
- sqlite3changeset_new, pApply->nCol, pApply->abPK, pApply->pDelete);
- sqlite3_bind_int(pApply->pDelete, pApply->nCol+1, 1);
- }
- if( rc==SQLITE_OK ){
- sqlite3_step(pApply->pDelete);
- rc = sqlite3_reset(pApply->pDelete);
- }
- if( rc==SQLITE_OK ){
- rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0);
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3_exec(db, "RELEASE replace_op", 0, 0, 0);
- }
- }
-
- return rc;
-}
-
-/*
-** Retry the changes accumulated in the pApply->constraints buffer.
-*/
-static int sessionRetryConstraints(
- sqlite3 *db,
- int bPatchset,
- const char *zTab,
- SessionApplyCtx *pApply,
- int(*xConflict)(void*, int, sqlite3_changeset_iter*),
- void *pCtx /* First argument passed to xConflict */
-){
- int rc = SQLITE_OK;
-
- while( pApply->constraints.nBuf ){
- sqlite3_changeset_iter *pIter2 = 0;
- SessionBuffer cons = pApply->constraints;
- memset(&pApply->constraints, 0, sizeof(SessionBuffer));
-
- rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf);
- if( rc==SQLITE_OK ){
- int nByte = 2*pApply->nCol*sizeof(sqlite3_value*);
- int rc2;
- pIter2->bPatchset = bPatchset;
- pIter2->zTab = (char*)zTab;
- pIter2->nCol = pApply->nCol;
- pIter2->abPK = pApply->abPK;
- sessionBufferGrow(&pIter2->tblhdr, nByte, &rc);
- pIter2->apValue = (sqlite3_value**)pIter2->tblhdr.aBuf;
- if( rc==SQLITE_OK ) memset(pIter2->apValue, 0, nByte);
-
- while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter2) ){
- rc = sessionApplyOneWithRetry(db, pIter2, pApply, xConflict, pCtx);
- }
-
- rc2 = sqlite3changeset_finalize(pIter2);
- if( rc==SQLITE_OK ) rc = rc2;
- }
- assert( pApply->bDeferConstraints || pApply->constraints.nBuf==0 );
-
- sqlite3_free(cons.aBuf);
- if( rc!=SQLITE_OK ) break;
- if( pApply->constraints.nBuf>=cons.nBuf ){
- /* No progress was made on the last round. */
- pApply->bDeferConstraints = 0;
- }
- }
-
- return rc;
-}
-
-/*
-** Argument pIter is a changeset iterator that has been initialized, but
-** not yet passed to sqlite3changeset_next(). This function applies the
-** changeset to the main database attached to handle "db". The supplied
-** conflict handler callback is invoked to resolve any conflicts encountered
-** while applying the change.
-*/
-static int sessionChangesetApply(
- sqlite3 *db, /* Apply change to "main" db of this handle */
- sqlite3_changeset_iter *pIter, /* Changeset to apply */
- int(*xFilter)(
- void *pCtx, /* Copy of sixth arg to _apply() */
- const char *zTab /* Table name */
- ),
- int(*xConflict)(
- void *pCtx, /* Copy of fifth arg to _apply() */
- int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
- sqlite3_changeset_iter *p /* Handle describing change and conflict */
- ),
- void *pCtx /* First argument passed to xConflict */
-){
- int schemaMismatch = 0;
- int rc; /* Return code */
- const char *zTab = 0; /* Name of current table */
- int nTab = 0; /* Result of sqlite3Strlen30(zTab) */
- SessionApplyCtx sApply; /* changeset_apply() context object */
- int bPatchset;
-
- assert( xConflict!=0 );
-
- pIter->in.bNoDiscard = 1;
- memset(&sApply, 0, sizeof(sApply));
- sqlite3_mutex_enter(sqlite3_db_mutex(db));
- rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
- if( rc==SQLITE_OK ){
- rc = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 1", 0, 0, 0);
- }
- while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter) ){
- int nCol;
- int op;
- const char *zNew;
-
- sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0);
-
- if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){
- u8 *abPK;
-
- rc = sessionRetryConstraints(
- db, pIter->bPatchset, zTab, &sApply, xConflict, pCtx
- );
- if( rc!=SQLITE_OK ) break;
-
- sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */
- sqlite3_finalize(sApply.pDelete);
- sqlite3_finalize(sApply.pUpdate);
- sqlite3_finalize(sApply.pInsert);
- sqlite3_finalize(sApply.pSelect);
- memset(&sApply, 0, sizeof(sApply));
- sApply.db = db;
- sApply.bDeferConstraints = 1;
-
- /* If an xFilter() callback was specified, invoke it now. If the
- ** xFilter callback returns zero, skip this table. If it returns
- ** non-zero, proceed. */
- schemaMismatch = (xFilter && (0==xFilter(pCtx, zNew)));
- if( schemaMismatch ){
- zTab = sqlite3_mprintf("%s", zNew);
- if( zTab==0 ){
- rc = SQLITE_NOMEM;
- break;
- }
- nTab = (int)strlen(zTab);
- sApply.azCol = (const char **)zTab;
- }else{
- sqlite3changeset_pk(pIter, &abPK, 0);
- rc = sessionTableInfo(
- db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK
- );
- if( rc!=SQLITE_OK ) break;
-
- if( sApply.nCol==0 ){
- schemaMismatch = 1;
- sqlite3_log(SQLITE_SCHEMA,
- "sqlite3changeset_apply(): no such table: %s", zTab
- );
- }
- else if( sApply.nCol!=nCol ){
- schemaMismatch = 1;
- sqlite3_log(SQLITE_SCHEMA,
- "sqlite3changeset_apply(): table %s has %d columns, expected %d",
- zTab, sApply.nCol, nCol
- );
- }
- else if( memcmp(sApply.abPK, abPK, nCol)!=0 ){
- schemaMismatch = 1;
- sqlite3_log(SQLITE_SCHEMA, "sqlite3changeset_apply(): "
- "primary key mismatch for table %s", zTab
- );
- }
- else if(
- (rc = sessionSelectRow(db, zTab, &sApply))
- || (rc = sessionUpdateRow(db, zTab, &sApply))
- || (rc = sessionDeleteRow(db, zTab, &sApply))
- || (rc = sessionInsertRow(db, zTab, &sApply))
- ){
- break;
- }
- nTab = sqlite3Strlen30(zTab);
- }
- }
-
- /* If there is a schema mismatch on the current table, proceed to the
- ** next change. A log message has already been issued. */
- if( schemaMismatch ) continue;
-
- rc = sessionApplyOneWithRetry(db, pIter, &sApply, xConflict, pCtx);
- }
-
- bPatchset = pIter->bPatchset;
- if( rc==SQLITE_OK ){
- rc = sqlite3changeset_finalize(pIter);
- }else{
- sqlite3changeset_finalize(pIter);
- }
-
- if( rc==SQLITE_OK ){
- rc = sessionRetryConstraints(db, bPatchset, zTab, &sApply, xConflict, pCtx);
- }
-
- if( rc==SQLITE_OK ){
- int nFk, notUsed;
- sqlite3_db_status(db, SQLITE_DBSTATUS_DEFERRED_FKS, &nFk, &notUsed, 0);
- if( nFk!=0 ){
- int res = SQLITE_CHANGESET_ABORT;
- sqlite3_changeset_iter sIter;
- memset(&sIter, 0, sizeof(sIter));
- sIter.nCol = nFk;
- res = xConflict(pCtx, SQLITE_CHANGESET_FOREIGN_KEY, &sIter);
- if( res!=SQLITE_CHANGESET_OMIT ){
- rc = SQLITE_CONSTRAINT;
- }
- }
- }
- sqlite3_exec(db, "PRAGMA defer_foreign_keys = 0", 0, 0, 0);
-
- if( rc==SQLITE_OK ){
- rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
- }else{
- sqlite3_exec(db, "ROLLBACK TO changeset_apply", 0, 0, 0);
- sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
- }
-
- sqlite3_finalize(sApply.pInsert);
- sqlite3_finalize(sApply.pDelete);
- sqlite3_finalize(sApply.pUpdate);
- sqlite3_finalize(sApply.pSelect);
- sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */
- sqlite3_free((char*)sApply.constraints.aBuf);
- sqlite3_mutex_leave(sqlite3_db_mutex(db));
- return rc;
-}
-
-/*
-** Apply the changeset passed via pChangeset/nChangeset to the main database
-** attached to handle "db". Invoke the supplied conflict handler callback
-** to resolve any conflicts encountered while applying the change.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changeset_apply(
- sqlite3 *db, /* Apply change to "main" db of this handle */
- int nChangeset, /* Size of changeset in bytes */
- void *pChangeset, /* Changeset blob */
- int(*xFilter)(
- void *pCtx, /* Copy of sixth arg to _apply() */
- const char *zTab /* Table name */
- ),
- int(*xConflict)(
- void *pCtx, /* Copy of fifth arg to _apply() */
- int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
- sqlite3_changeset_iter *p /* Handle describing change and conflict */
- ),
- void *pCtx /* First argument passed to xConflict */
-){
- sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
- int rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
- if( rc==SQLITE_OK ){
- rc = sessionChangesetApply(db, pIter, xFilter, xConflict, pCtx);
- }
- return rc;
-}
-
-/*
-** Apply the changeset passed via xInput/pIn to the main database
-** attached to handle "db". Invoke the supplied conflict handler callback
-** to resolve any conflicts encountered while applying the change.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changeset_apply_strm(
- sqlite3 *db, /* Apply change to "main" db of this handle */
- int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
- void *pIn, /* First arg for xInput */
- int(*xFilter)(
- void *pCtx, /* Copy of sixth arg to _apply() */
- const char *zTab /* Table name */
- ),
- int(*xConflict)(
- void *pCtx, /* Copy of sixth arg to _apply() */
- int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
- sqlite3_changeset_iter *p /* Handle describing change and conflict */
- ),
- void *pCtx /* First argument passed to xConflict */
-){
- sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
- int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
- if( rc==SQLITE_OK ){
- rc = sessionChangesetApply(db, pIter, xFilter, xConflict, pCtx);
- }
- return rc;
-}
-
-/*
-** sqlite3_changegroup handle.
-*/
-struct sqlite3_changegroup {
- int rc; /* Error code */
- int bPatch; /* True to accumulate patchsets */
- SessionTable *pList; /* List of tables in current patch */
-};
-
-/*
-** This function is called to merge two changes to the same row together as
-** part of an sqlite3changeset_concat() operation. A new change object is
-** allocated and a pointer to it stored in *ppNew.
-*/
-static int sessionChangeMerge(
- SessionTable *pTab, /* Table structure */
- int bPatchset, /* True for patchsets */
- SessionChange *pExist, /* Existing change */
- int op2, /* Second change operation */
- int bIndirect, /* True if second change is indirect */
- u8 *aRec, /* Second change record */
- int nRec, /* Number of bytes in aRec */
- SessionChange **ppNew /* OUT: Merged change */
-){
- SessionChange *pNew = 0;
-
- if( !pExist ){
- pNew = (SessionChange *)sqlite3_malloc(sizeof(SessionChange) + nRec);
- if( !pNew ){
- return SQLITE_NOMEM;
- }
- memset(pNew, 0, sizeof(SessionChange));
- pNew->op = op2;
- pNew->bIndirect = bIndirect;
- pNew->nRecord = nRec;
- pNew->aRecord = (u8*)&pNew[1];
- memcpy(pNew->aRecord, aRec, nRec);
- }else{
- int op1 = pExist->op;
-
- /*
- ** op1=INSERT, op2=INSERT -> Unsupported. Discard op2.
- ** op1=INSERT, op2=UPDATE -> INSERT.
- ** op1=INSERT, op2=DELETE -> (none)
- **
- ** op1=UPDATE, op2=INSERT -> Unsupported. Discard op2.
- ** op1=UPDATE, op2=UPDATE -> UPDATE.
- ** op1=UPDATE, op2=DELETE -> DELETE.
- **
- ** op1=DELETE, op2=INSERT -> UPDATE.
- ** op1=DELETE, op2=UPDATE -> Unsupported. Discard op2.
- ** op1=DELETE, op2=DELETE -> Unsupported. Discard op2.
- */
- if( (op1==SQLITE_INSERT && op2==SQLITE_INSERT)
- || (op1==SQLITE_UPDATE && op2==SQLITE_INSERT)
- || (op1==SQLITE_DELETE && op2==SQLITE_UPDATE)
- || (op1==SQLITE_DELETE && op2==SQLITE_DELETE)
- ){
- pNew = pExist;
- }else if( op1==SQLITE_INSERT && op2==SQLITE_DELETE ){
- sqlite3_free(pExist);
- assert( pNew==0 );
- }else{
- u8 *aExist = pExist->aRecord;
- int nByte;
- u8 *aCsr;
-
- /* Allocate a new SessionChange object. Ensure that the aRecord[]
- ** buffer of the new object is large enough to hold any record that
- ** may be generated by combining the input records. */
- nByte = sizeof(SessionChange) + pExist->nRecord + nRec;
- pNew = (SessionChange *)sqlite3_malloc(nByte);
- if( !pNew ){
- sqlite3_free(pExist);
- return SQLITE_NOMEM;
- }
- memset(pNew, 0, sizeof(SessionChange));
- pNew->bIndirect = (bIndirect && pExist->bIndirect);
- aCsr = pNew->aRecord = (u8 *)&pNew[1];
-
- if( op1==SQLITE_INSERT ){ /* INSERT + UPDATE */
- u8 *a1 = aRec;
- assert( op2==SQLITE_UPDATE );
- pNew->op = SQLITE_INSERT;
- if( bPatchset==0 ) sessionSkipRecord(&a1, pTab->nCol);
- sessionMergeRecord(&aCsr, pTab->nCol, aExist, a1);
- }else if( op1==SQLITE_DELETE ){ /* DELETE + INSERT */
- assert( op2==SQLITE_INSERT );
- pNew->op = SQLITE_UPDATE;
- if( bPatchset ){
- memcpy(aCsr, aRec, nRec);
- aCsr += nRec;
- }else{
- if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aExist, 0,aRec,0) ){
- sqlite3_free(pNew);
- pNew = 0;
- }
- }
- }else if( op2==SQLITE_UPDATE ){ /* UPDATE + UPDATE */
- u8 *a1 = aExist;
- u8 *a2 = aRec;
- assert( op1==SQLITE_UPDATE );
- if( bPatchset==0 ){
- sessionSkipRecord(&a1, pTab->nCol);
- sessionSkipRecord(&a2, pTab->nCol);
- }
- pNew->op = SQLITE_UPDATE;
- if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aRec, aExist,a1,a2) ){
- sqlite3_free(pNew);
- pNew = 0;
- }
- }else{ /* UPDATE + DELETE */
- assert( op1==SQLITE_UPDATE && op2==SQLITE_DELETE );
- pNew->op = SQLITE_DELETE;
- if( bPatchset ){
- memcpy(aCsr, aRec, nRec);
- aCsr += nRec;
- }else{
- sessionMergeRecord(&aCsr, pTab->nCol, aRec, aExist);
- }
- }
-
- if( pNew ){
- pNew->nRecord = (int)(aCsr - pNew->aRecord);
- }
- sqlite3_free(pExist);
- }
- }
-
- *ppNew = pNew;
- return SQLITE_OK;
-}
-
-/*
-** Add all changes in the changeset traversed by the iterator passed as
-** the first argument to the changegroup hash tables.
-*/
-static int sessionChangesetToHash(
- sqlite3_changeset_iter *pIter, /* Iterator to read from */
- sqlite3_changegroup *pGrp /* Changegroup object to add changeset to */
-){
- u8 *aRec;
- int nRec;
- int rc = SQLITE_OK;
- SessionTable *pTab = 0;
-
-
- while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec) ){
- const char *zNew;
- int nCol;
- int op;
- int iHash;
- int bIndirect;
- SessionChange *pChange;
- SessionChange *pExist = 0;
- SessionChange **pp;
-
- if( pGrp->pList==0 ){
- pGrp->bPatch = pIter->bPatchset;
- }else if( pIter->bPatchset!=pGrp->bPatch ){
- rc = SQLITE_ERROR;
- break;
- }
-
- sqlite3changeset_op(pIter, &zNew, &nCol, &op, &bIndirect);
- if( !pTab || sqlite3_stricmp(zNew, pTab->zName) ){
- /* Search the list for a matching table */
- int nNew = (int)strlen(zNew);
- u8 *abPK;
-
- sqlite3changeset_pk(pIter, &abPK, 0);
- for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){
- if( 0==sqlite3_strnicmp(pTab->zName, zNew, nNew+1) ) break;
- }
- if( !pTab ){
- SessionTable **ppTab;
-
- pTab = sqlite3_malloc(sizeof(SessionTable) + nCol + nNew+1);
- if( !pTab ){
- rc = SQLITE_NOMEM;
- break;
- }
- memset(pTab, 0, sizeof(SessionTable));
- pTab->nCol = nCol;
- pTab->abPK = (u8*)&pTab[1];
- memcpy(pTab->abPK, abPK, nCol);
- pTab->zName = (char*)&pTab->abPK[nCol];
- memcpy(pTab->zName, zNew, nNew+1);
-
- /* The new object must be linked on to the end of the list, not
- ** simply added to the start of it. This is to ensure that the
- ** tables within the output of sqlite3changegroup_output() are in
- ** the right order. */
- for(ppTab=&pGrp->pList; *ppTab; ppTab=&(*ppTab)->pNext);
- *ppTab = pTab;
- }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){
- rc = SQLITE_SCHEMA;
- break;
- }
- }
-
- if( sessionGrowHash(pIter->bPatchset, pTab) ){
- rc = SQLITE_NOMEM;
- break;
- }
- iHash = sessionChangeHash(
- pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange
- );
-
- /* Search for existing entry. If found, remove it from the hash table.
- ** Code below may link it back in.
- */
- for(pp=&pTab->apChange[iHash]; *pp; pp=&(*pp)->pNext){
- int bPkOnly1 = 0;
- int bPkOnly2 = 0;
- if( pIter->bPatchset ){
- bPkOnly1 = (*pp)->op==SQLITE_DELETE;
- bPkOnly2 = op==SQLITE_DELETE;
- }
- if( sessionChangeEqual(pTab, bPkOnly1, (*pp)->aRecord, bPkOnly2, aRec) ){
- pExist = *pp;
- *pp = (*pp)->pNext;
- pTab->nEntry--;
- break;
- }
- }
-
- rc = sessionChangeMerge(pTab,
- pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange
- );
- if( rc ) break;
- if( pChange ){
- pChange->pNext = pTab->apChange[iHash];
- pTab->apChange[iHash] = pChange;
- pTab->nEntry++;
- }
- }
-
- if( rc==SQLITE_OK ) rc = pIter->rc;
- return rc;
-}
-
-/*
-** Serialize a changeset (or patchset) based on all changesets (or patchsets)
-** added to the changegroup object passed as the first argument.
-**
-** If xOutput is not NULL, then the changeset/patchset is returned to the
-** user via one or more calls to xOutput, as with the other streaming
-** interfaces.
-**
-** Or, if xOutput is NULL, then (*ppOut) is populated with a pointer to a
-** buffer containing the output changeset before this function returns. In
-** this case (*pnOut) is set to the size of the output buffer in bytes. It
-** is the responsibility of the caller to free the output buffer using
-** sqlite3_free() when it is no longer required.
-**
-** If successful, SQLITE_OK is returned. Or, if an error occurs, an SQLite
-** error code. If an error occurs and xOutput is NULL, (*ppOut) and (*pnOut)
-** are both set to 0 before returning.
-*/
-static int sessionChangegroupOutput(
- sqlite3_changegroup *pGrp,
- int (*xOutput)(void *pOut, const void *pData, int nData),
- void *pOut,
- int *pnOut,
- void **ppOut
-){
- int rc = SQLITE_OK;
- SessionBuffer buf = {0, 0, 0};
- SessionTable *pTab;
- assert( xOutput==0 || (ppOut==0 && pnOut==0) );
-
- /* Create the serialized output changeset based on the contents of the
- ** hash tables attached to the SessionTable objects in list p->pList.
- */
- for(pTab=pGrp->pList; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
- int i;
- if( pTab->nEntry==0 ) continue;
-
- sessionAppendTableHdr(&buf, pGrp->bPatch, pTab, &rc);
- for(i=0; i<pTab->nChange; i++){
- SessionChange *p;
- for(p=pTab->apChange[i]; p; p=p->pNext){
- sessionAppendByte(&buf, p->op, &rc);
- sessionAppendByte(&buf, p->bIndirect, &rc);
- sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc);
- }
- }
-
- if( rc==SQLITE_OK && xOutput && buf.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){
- rc = xOutput(pOut, buf.aBuf, buf.nBuf);
- buf.nBuf = 0;
- }
- }
-
- if( rc==SQLITE_OK ){
- if( xOutput ){
- if( buf.nBuf>0 ) rc = xOutput(pOut, buf.aBuf, buf.nBuf);
- }else{
- *ppOut = buf.aBuf;
- *pnOut = buf.nBuf;
- buf.aBuf = 0;
- }
- }
- sqlite3_free(buf.aBuf);
-
- return rc;
-}
-
-/*
-** Allocate a new, empty, sqlite3_changegroup.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changegroup_new(sqlite3_changegroup **pp){
- int rc = SQLITE_OK; /* Return code */
- sqlite3_changegroup *p; /* New object */
- p = (sqlite3_changegroup*)sqlite3_malloc(sizeof(sqlite3_changegroup));
- if( p==0 ){
- rc = SQLITE_NOMEM;
- }else{
- memset(p, 0, sizeof(sqlite3_changegroup));
- }
- *pp = p;
- return rc;
-}
-
-/*
-** Add the changeset currently stored in buffer pData, size nData bytes,
-** to changeset-group p.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changegroup_add(sqlite3_changegroup *pGrp, int nData, void *pData){
- sqlite3_changeset_iter *pIter; /* Iterator opened on pData/nData */
- int rc; /* Return code */
-
- rc = sqlite3changeset_start(&pIter, nData, pData);
- if( rc==SQLITE_OK ){
- rc = sessionChangesetToHash(pIter, pGrp);
- }
- sqlite3changeset_finalize(pIter);
- return rc;
-}
-
-/*
-** Obtain a buffer containing a changeset representing the concatenation
-** of all changesets added to the group so far.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changegroup_output(
- sqlite3_changegroup *pGrp,
- int *pnData,
- void **ppData
-){
- return sessionChangegroupOutput(pGrp, 0, 0, pnData, ppData);
-}
-
-/*
-** Streaming versions of changegroup_add().
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changegroup_add_strm(
- sqlite3_changegroup *pGrp,
- int (*xInput)(void *pIn, void *pData, int *pnData),
- void *pIn
-){
- sqlite3_changeset_iter *pIter; /* Iterator opened on pData/nData */
- int rc; /* Return code */
-
- rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
- if( rc==SQLITE_OK ){
- rc = sessionChangesetToHash(pIter, pGrp);
- }
- sqlite3changeset_finalize(pIter);
- return rc;
-}
-
-/*
-** Streaming versions of changegroup_output().
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changegroup_output_strm(
- sqlite3_changegroup *pGrp,
- int (*xOutput)(void *pOut, const void *pData, int nData),
- void *pOut
-){
- return sessionChangegroupOutput(pGrp, xOutput, pOut, 0, 0);
-}
-
-/*
-** Delete a changegroup object.
-*/
-SQLITE_API void SQLITE_STDCALL sqlite3changegroup_delete(sqlite3_changegroup *pGrp){
- if( pGrp ){
- sessionDeleteTable(pGrp->pList);
- sqlite3_free(pGrp);
- }
-}
-
-/*
-** Combine two changesets together.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changeset_concat(
- int nLeft, /* Number of bytes in lhs input */
- void *pLeft, /* Lhs input changeset */
- int nRight /* Number of bytes in rhs input */,
- void *pRight, /* Rhs input changeset */
- int *pnOut, /* OUT: Number of bytes in output changeset */
- void **ppOut /* OUT: changeset (left <concat> right) */
-){
- sqlite3_changegroup *pGrp;
- int rc;
-
- rc = sqlite3changegroup_new(&pGrp);
- if( rc==SQLITE_OK ){
- rc = sqlite3changegroup_add(pGrp, nLeft, pLeft);
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3changegroup_add(pGrp, nRight, pRight);
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3changegroup_output(pGrp, pnOut, ppOut);
- }
- sqlite3changegroup_delete(pGrp);
-
- return rc;
-}
-
-/*
-** Streaming version of sqlite3changeset_concat().
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3changeset_concat_strm(
- int (*xInputA)(void *pIn, void *pData, int *pnData),
- void *pInA,
- int (*xInputB)(void *pIn, void *pData, int *pnData),
- void *pInB,
- int (*xOutput)(void *pOut, const void *pData, int nData),
- void *pOut
-){
- sqlite3_changegroup *pGrp;
- int rc;
-
- rc = sqlite3changegroup_new(&pGrp);
- if( rc==SQLITE_OK ){
- rc = sqlite3changegroup_add_strm(pGrp, xInputA, pInA);
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3changegroup_add_strm(pGrp, xInputB, pInB);
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3changegroup_output_strm(pGrp, xOutput, pOut);
- }
- sqlite3changegroup_delete(pGrp);
-
- return rc;
-}
-
-#endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */
-
-/************** End of sqlite3session.c **************************************/
-/************** Begin file json1.c *******************************************/
-/*
-** 2015-08-12
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This SQLite extension implements JSON functions. The interface is
-** modeled after MySQL JSON functions:
-**
-** https://dev.mysql.com/doc/refman/5.7/en/json.html
-**
-** For the time being, all JSON is stored as pure text. (We might add
-** a JSONB type in the future which stores a binary encoding of JSON in
-** a BLOB, but there is no support for JSONB in the current implementation.
-** This implementation parses JSON text at 250 MB/s, so it is hard to see
-** how JSONB might improve on that.)
-*/
-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1)
-#if !defined(_SQLITEINT_H_)
-/* #include "sqlite3ext.h" */
-#endif
-SQLITE_EXTENSION_INIT1
-/* #include <assert.h> */
-/* #include <string.h> */
-/* #include <stdlib.h> */
-/* #include <stdarg.h> */
-
-/* Mark a function parameter as unused, to suppress nuisance compiler
-** warnings. */
-#ifndef UNUSED_PARAM
-# define UNUSED_PARAM(X) (void)(X)
-#endif
-
-#ifndef LARGEST_INT64
-# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
-# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
-#endif
-
-/*
-** Versions of isspace(), isalnum() and isdigit() to which it is safe
-** to pass signed char values.
-*/
-#ifdef sqlite3Isdigit
- /* Use the SQLite core versions if this routine is part of the
- ** SQLite amalgamation */
-# define safe_isdigit(x) sqlite3Isdigit(x)
-# define safe_isalnum(x) sqlite3Isalnum(x)
-#else
- /* Use the standard library for separate compilation */
-#include <ctype.h> /* amalgamator: keep */
-# define safe_isdigit(x) isdigit((unsigned char)(x))
-# define safe_isalnum(x) isalnum((unsigned char)(x))
-#endif
-
-/*
-** Growing our own isspace() routine this way is twice as fast as
-** the library isspace() function, resulting in a 7% overall performance
-** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
-*/
-static const char jsonIsSpace[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-#define safe_isspace(x) (jsonIsSpace[(unsigned char)x])
-
-#ifndef SQLITE_AMALGAMATION
- /* Unsigned integer types. These are already defined in the sqliteInt.h,
- ** but the definitions need to be repeated for separate compilation. */
- typedef sqlite3_uint64 u64;
- typedef unsigned int u32;
- typedef unsigned char u8;
-#endif
-
-/* Objects */
-typedef struct JsonString JsonString;
-typedef struct JsonNode JsonNode;
-typedef struct JsonParse JsonParse;
-
-/* An instance of this object represents a JSON string
-** under construction. Really, this is a generic string accumulator
-** that can be and is used to create strings other than JSON.
-*/
-struct JsonString {
- sqlite3_context *pCtx; /* Function context - put error messages here */
- char *zBuf; /* Append JSON content here */
- u64 nAlloc; /* Bytes of storage available in zBuf[] */
- u64 nUsed; /* Bytes of zBuf[] currently used */
- u8 bStatic; /* True if zBuf is static space */
- u8 bErr; /* True if an error has been encountered */
- char zSpace[100]; /* Initial static space */
-};
-
-/* JSON type values
-*/
-#define JSON_NULL 0
-#define JSON_TRUE 1
-#define JSON_FALSE 2
-#define JSON_INT 3
-#define JSON_REAL 4
-#define JSON_STRING 5
-#define JSON_ARRAY 6
-#define JSON_OBJECT 7
-
-/* The "subtype" set for JSON values */
-#define JSON_SUBTYPE 74 /* Ascii for "J" */
-
-/*
-** Names of the various JSON types:
-*/
-static const char * const jsonType[] = {
- "null", "true", "false", "integer", "real", "text", "array", "object"
-};
-
-/* Bit values for the JsonNode.jnFlag field
-*/
-#define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */
-#define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */
-#define JNODE_REMOVE 0x04 /* Do not output */
-#define JNODE_REPLACE 0x08 /* Replace with JsonNode.iVal */
-#define JNODE_APPEND 0x10 /* More ARRAY/OBJECT entries at u.iAppend */
-#define JNODE_LABEL 0x20 /* Is a label of an object */
-
-
-/* A single node of parsed JSON
-*/
-struct JsonNode {
- u8 eType; /* One of the JSON_ type values */
- u8 jnFlags; /* JNODE flags */
- u8 iVal; /* Replacement value when JNODE_REPLACE */
- u32 n; /* Bytes of content, or number of sub-nodes */
- union {
- const char *zJContent; /* Content for INT, REAL, and STRING */
- u32 iAppend; /* More terms for ARRAY and OBJECT */
- u32 iKey; /* Key for ARRAY objects in json_tree() */
- } u;
-};
-
-/* A completely parsed JSON string
-*/
-struct JsonParse {
- u32 nNode; /* Number of slots of aNode[] used */
- u32 nAlloc; /* Number of slots of aNode[] allocated */
- JsonNode *aNode; /* Array of nodes containing the parse */
- const char *zJson; /* Original JSON string */
- u32 *aUp; /* Index of parent of each node */
- u8 oom; /* Set to true if out of memory */
- u8 nErr; /* Number of errors seen */
-};
-
-/**************************************************************************
-** Utility routines for dealing with JsonString objects
-**************************************************************************/
-
-/* Set the JsonString object to an empty string
-*/
-static void jsonZero(JsonString *p){
- p->zBuf = p->zSpace;
- p->nAlloc = sizeof(p->zSpace);
- p->nUsed = 0;
- p->bStatic = 1;
-}
-
-/* Initialize the JsonString object
-*/
-static void jsonInit(JsonString *p, sqlite3_context *pCtx){
- p->pCtx = pCtx;
- p->bErr = 0;
- jsonZero(p);
-}
-
-
-/* Free all allocated memory and reset the JsonString object back to its
-** initial state.
-*/
-static void jsonReset(JsonString *p){
- if( !p->bStatic ) sqlite3_free(p->zBuf);
- jsonZero(p);
-}
-
-
-/* Report an out-of-memory (OOM) condition
-*/
-static void jsonOom(JsonString *p){
- p->bErr = 1;
- sqlite3_result_error_nomem(p->pCtx);
- jsonReset(p);
-}
-
-/* Enlarge pJson->zBuf so that it can hold at least N more bytes.
-** Return zero on success. Return non-zero on an OOM error
-*/
-static int jsonGrow(JsonString *p, u32 N){
- u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10;
- char *zNew;
- if( p->bStatic ){
- if( p->bErr ) return 1;
- zNew = sqlite3_malloc64(nTotal);
- if( zNew==0 ){
- jsonOom(p);
- return SQLITE_NOMEM;
- }
- memcpy(zNew, p->zBuf, (size_t)p->nUsed);
- p->zBuf = zNew;
- p->bStatic = 0;
- }else{
- zNew = sqlite3_realloc64(p->zBuf, nTotal);
- if( zNew==0 ){
- jsonOom(p);
- return SQLITE_NOMEM;
- }
- p->zBuf = zNew;
- }
- p->nAlloc = nTotal;
- return SQLITE_OK;
-}
-
-/* Append N bytes from zIn onto the end of the JsonString string.
-*/
-static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
- if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
- memcpy(p->zBuf+p->nUsed, zIn, N);
- p->nUsed += N;
-}
-
-/* Append formatted text (not to exceed N bytes) to the JsonString.
-*/
-static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
- va_list ap;
- if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return;
- va_start(ap, zFormat);
- sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap);
- va_end(ap);
- p->nUsed += (int)strlen(p->zBuf+p->nUsed);
-}
-
-/* Append a single character
-*/
-static void jsonAppendChar(JsonString *p, char c){
- if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return;
- p->zBuf[p->nUsed++] = c;
-}
-
-/* Append a comma separator to the output buffer, if the previous
-** character is not '[' or '{'.
-*/
-static void jsonAppendSeparator(JsonString *p){
- char c;
- if( p->nUsed==0 ) return;
- c = p->zBuf[p->nUsed-1];
- if( c!='[' && c!='{' ) jsonAppendChar(p, ',');
-}
-
-/* Append the N-byte string in zIn to the end of the JsonString string
-** under construction. Enclose the string in "..." and escape
-** any double-quotes or backslash characters contained within the
-** string.
-*/
-static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
- u32 i;
- if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return;
- p->zBuf[p->nUsed++] = '"';
- for(i=0; i<N; i++){
- unsigned char c = ((unsigned const char*)zIn)[i];
- if( c=='"' || c=='\\' ){
- json_simple_escape:
- if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return;
- p->zBuf[p->nUsed++] = '\\';
- }else if( c<=0x1f ){
- static const char aSpecial[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
- assert( sizeof(aSpecial)==32 );
- assert( aSpecial['\b']=='b' );
- assert( aSpecial['\f']=='f' );
- assert( aSpecial['\n']=='n' );
- assert( aSpecial['\r']=='r' );
- assert( aSpecial['\t']=='t' );
- if( aSpecial[c] ){
- c = aSpecial[c];
- goto json_simple_escape;
- }
- if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return;
- p->zBuf[p->nUsed++] = '\\';
- p->zBuf[p->nUsed++] = 'u';
- p->zBuf[p->nUsed++] = '0';
- p->zBuf[p->nUsed++] = '0';
- p->zBuf[p->nUsed++] = '0' + (c>>4);
- c = "0123456789abcdef"[c&0xf];
- }
- p->zBuf[p->nUsed++] = c;
- }
- p->zBuf[p->nUsed++] = '"';
- assert( p->nUsed<p->nAlloc );
-}
-
-/*
-** Append a function parameter value to the JSON string under
-** construction.
-*/
-static void jsonAppendValue(
- JsonString *p, /* Append to this JSON string */
- sqlite3_value *pValue /* Value to append */
-){
- switch( sqlite3_value_type(pValue) ){
- case SQLITE_NULL: {
- jsonAppendRaw(p, "null", 4);
- break;
- }
- case SQLITE_INTEGER:
- case SQLITE_FLOAT: {
- const char *z = (const char*)sqlite3_value_text(pValue);
- u32 n = (u32)sqlite3_value_bytes(pValue);
- jsonAppendRaw(p, z, n);
- break;
- }
- case SQLITE_TEXT: {
- const char *z = (const char*)sqlite3_value_text(pValue);
- u32 n = (u32)sqlite3_value_bytes(pValue);
- if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){
- jsonAppendRaw(p, z, n);
- }else{
- jsonAppendString(p, z, n);
- }
- break;
- }
- default: {
- if( p->bErr==0 ){
- sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1);
- p->bErr = 2;
- jsonReset(p);
- }
- break;
- }
- }
-}
-
-
-/* Make the JSON in p the result of the SQL function.
-*/
-static void jsonResult(JsonString *p){
- if( p->bErr==0 ){
- sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
- p->bStatic ? SQLITE_TRANSIENT : sqlite3_free,
- SQLITE_UTF8);
- jsonZero(p);
- }
- assert( p->bStatic );
-}
-
-/**************************************************************************
-** Utility routines for dealing with JsonNode and JsonParse objects
-**************************************************************************/
-
-/*
-** Return the number of consecutive JsonNode slots need to represent
-** the parsed JSON at pNode. The minimum answer is 1. For ARRAY and
-** OBJECT types, the number might be larger.
-**
-** Appended elements are not counted. The value returned is the number
-** by which the JsonNode counter should increment in order to go to the
-** next peer value.
-*/
-static u32 jsonNodeSize(JsonNode *pNode){
- return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1;
-}
-
-/*
-** Reclaim all memory allocated by a JsonParse object. But do not
-** delete the JsonParse object itself.
-*/
-static void jsonParseReset(JsonParse *pParse){
- sqlite3_free(pParse->aNode);
- pParse->aNode = 0;
- pParse->nNode = 0;
- pParse->nAlloc = 0;
- sqlite3_free(pParse->aUp);
- pParse->aUp = 0;
-}
-
-/*
-** Convert the JsonNode pNode into a pure JSON string and
-** append to pOut. Subsubstructure is also included. Return
-** the number of JsonNode objects that are encoded.
-*/
-static void jsonRenderNode(
- JsonNode *pNode, /* The node to render */
- JsonString *pOut, /* Write JSON here */
- sqlite3_value **aReplace /* Replacement values */
-){
- switch( pNode->eType ){
- default: {
- assert( pNode->eType==JSON_NULL );
- jsonAppendRaw(pOut, "null", 4);
- break;
- }
- case JSON_TRUE: {
- jsonAppendRaw(pOut, "true", 4);
- break;
- }
- case JSON_FALSE: {
- jsonAppendRaw(pOut, "false", 5);
- break;
- }
- case JSON_STRING: {
- if( pNode->jnFlags & JNODE_RAW ){
- jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
- break;
- }
- /* Fall through into the next case */
- }
- case JSON_REAL:
- case JSON_INT: {
- jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
- break;
- }
- case JSON_ARRAY: {
- u32 j = 1;
- jsonAppendChar(pOut, '[');
- for(;;){
- while( j<=pNode->n ){
- if( pNode[j].jnFlags & (JNODE_REMOVE|JNODE_REPLACE) ){
- if( pNode[j].jnFlags & JNODE_REPLACE ){
- jsonAppendSeparator(pOut);
- jsonAppendValue(pOut, aReplace[pNode[j].iVal]);
- }
- }else{
- jsonAppendSeparator(pOut);
- jsonRenderNode(&pNode[j], pOut, aReplace);
- }
- j += jsonNodeSize(&pNode[j]);
- }
- if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
- pNode = &pNode[pNode->u.iAppend];
- j = 1;
- }
- jsonAppendChar(pOut, ']');
- break;
- }
- case JSON_OBJECT: {
- u32 j = 1;
- jsonAppendChar(pOut, '{');
- for(;;){
- while( j<=pNode->n ){
- if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){
- jsonAppendSeparator(pOut);
- jsonRenderNode(&pNode[j], pOut, aReplace);
- jsonAppendChar(pOut, ':');
- if( pNode[j+1].jnFlags & JNODE_REPLACE ){
- jsonAppendValue(pOut, aReplace[pNode[j+1].iVal]);
- }else{
- jsonRenderNode(&pNode[j+1], pOut, aReplace);
- }
- }
- j += 1 + jsonNodeSize(&pNode[j+1]);
- }
- if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
- pNode = &pNode[pNode->u.iAppend];
- j = 1;
- }
- jsonAppendChar(pOut, '}');
- break;
- }
- }
-}
-
-/*
-** Return a JsonNode and all its descendents as a JSON string.
-*/
-static void jsonReturnJson(
- JsonNode *pNode, /* Node to return */
- sqlite3_context *pCtx, /* Return value for this function */
- sqlite3_value **aReplace /* Array of replacement values */
-){
- JsonString s;
- jsonInit(&s, pCtx);
- jsonRenderNode(pNode, &s, aReplace);
- jsonResult(&s);
- sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
-}
-
-/*
-** Make the JsonNode the return value of the function.
-*/
-static void jsonReturn(
- JsonNode *pNode, /* Node to return */
- sqlite3_context *pCtx, /* Return value for this function */
- sqlite3_value **aReplace /* Array of replacement values */
-){
- switch( pNode->eType ){
- default: {
- assert( pNode->eType==JSON_NULL );
- sqlite3_result_null(pCtx);
- break;
- }
- case JSON_TRUE: {
- sqlite3_result_int(pCtx, 1);
- break;
- }
- case JSON_FALSE: {
- sqlite3_result_int(pCtx, 0);
- break;
- }
- case JSON_INT: {
- sqlite3_int64 i = 0;
- const char *z = pNode->u.zJContent;
- if( z[0]=='-' ){ z++; }
- while( z[0]>='0' && z[0]<='9' ){
- unsigned v = *(z++) - '0';
- if( i>=LARGEST_INT64/10 ){
- if( i>LARGEST_INT64/10 ) goto int_as_real;
- if( z[0]>='0' && z[0]<='9' ) goto int_as_real;
- if( v==9 ) goto int_as_real;
- if( v==8 ){
- if( pNode->u.zJContent[0]=='-' ){
- sqlite3_result_int64(pCtx, SMALLEST_INT64);
- goto int_done;
- }else{
- goto int_as_real;
- }
- }
- }
- i = i*10 + v;
- }
- if( pNode->u.zJContent[0]=='-' ){ i = -i; }
- sqlite3_result_int64(pCtx, i);
- int_done:
- break;
- int_as_real: /* fall through to real */;
- }
- case JSON_REAL: {
- double r;
-#ifdef SQLITE_AMALGAMATION
- const char *z = pNode->u.zJContent;
- sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
-#else
- r = strtod(pNode->u.zJContent, 0);
-#endif
- sqlite3_result_double(pCtx, r);
- break;
- }
- case JSON_STRING: {
-#if 0 /* Never happens because JNODE_RAW is only set by json_set(),
- ** json_insert() and json_replace() and those routines do not
- ** call jsonReturn() */
- if( pNode->jnFlags & JNODE_RAW ){
- sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n,
- SQLITE_TRANSIENT);
- }else
-#endif
- assert( (pNode->jnFlags & JNODE_RAW)==0 );
- if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
- /* JSON formatted without any backslash-escapes */
- sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2,
- SQLITE_TRANSIENT);
- }else{
- /* Translate JSON formatted string into raw text */
- u32 i;
- u32 n = pNode->n;
- const char *z = pNode->u.zJContent;
- char *zOut;
- u32 j;
- zOut = sqlite3_malloc( n+1 );
- if( zOut==0 ){
- sqlite3_result_error_nomem(pCtx);
- break;
- }
- for(i=1, j=0; i<n-1; i++){
- char c = z[i];
- if( c!='\\' ){
- zOut[j++] = c;
- }else{
- c = z[++i];
- if( c=='u' ){
- u32 v = 0, k;
- for(k=0; k<4 && i<n-2; i++, k++){
- c = z[i+1];
- if( c>='0' && c<='9' ) v = v*16 + c - '0';
- else if( c>='A' && c<='F' ) v = v*16 + c - 'A' + 10;
- else if( c>='a' && c<='f' ) v = v*16 + c - 'a' + 10;
- else break;
- }
- if( v==0 ) break;
- if( v<=0x7f ){
- zOut[j++] = (char)v;
- }else if( v<=0x7ff ){
- zOut[j++] = (char)(0xc0 | (v>>6));
- zOut[j++] = 0x80 | (v&0x3f);
- }else{
- zOut[j++] = (char)(0xe0 | (v>>12));
- zOut[j++] = 0x80 | ((v>>6)&0x3f);
- zOut[j++] = 0x80 | (v&0x3f);
- }
- }else{
- if( c=='b' ){
- c = '\b';
- }else if( c=='f' ){
- c = '\f';
- }else if( c=='n' ){
- c = '\n';
- }else if( c=='r' ){
- c = '\r';
- }else if( c=='t' ){
- c = '\t';
- }
- zOut[j++] = c;
- }
- }
- }
- zOut[j] = 0;
- sqlite3_result_text(pCtx, zOut, j, sqlite3_free);
- }
- break;
- }
- case JSON_ARRAY:
- case JSON_OBJECT: {
- jsonReturnJson(pNode, pCtx, aReplace);
- break;
- }
- }
-}
-
-/* Forward reference */
-static int jsonParseAddNode(JsonParse*,u32,u32,const char*);
-
-/*
-** A macro to hint to the compiler that a function should not be
-** inlined.
-*/
-#if defined(__GNUC__)
-# define JSON_NOINLINE __attribute__((noinline))
-#elif defined(_MSC_VER) && _MSC_VER>=1310
-# define JSON_NOINLINE __declspec(noinline)
-#else
-# define JSON_NOINLINE
-#endif
-
-
-static JSON_NOINLINE int jsonParseAddNodeExpand(
- JsonParse *pParse, /* Append the node to this object */
- u32 eType, /* Node type */
- u32 n, /* Content size or sub-node count */
- const char *zContent /* Content */
-){
- u32 nNew;
- JsonNode *pNew;
- assert( pParse->nNode>=pParse->nAlloc );
- if( pParse->oom ) return -1;
- nNew = pParse->nAlloc*2 + 10;
- pNew = sqlite3_realloc(pParse->aNode, sizeof(JsonNode)*nNew);
- if( pNew==0 ){
- pParse->oom = 1;
- return -1;
- }
- pParse->nAlloc = nNew;
- pParse->aNode = pNew;
- assert( pParse->nNode<pParse->nAlloc );
- return jsonParseAddNode(pParse, eType, n, zContent);
-}
-
-/*
-** Create a new JsonNode instance based on the arguments and append that
-** instance to the JsonParse. Return the index in pParse->aNode[] of the
-** new node, or -1 if a memory allocation fails.
-*/
-static int jsonParseAddNode(
- JsonParse *pParse, /* Append the node to this object */
- u32 eType, /* Node type */
- u32 n, /* Content size or sub-node count */
- const char *zContent /* Content */
-){
- JsonNode *p;
- if( pParse->nNode>=pParse->nAlloc ){
- return jsonParseAddNodeExpand(pParse, eType, n, zContent);
- }
- p = &pParse->aNode[pParse->nNode];
- p->eType = (u8)eType;
- p->jnFlags = 0;
- p->iVal = 0;
- p->n = n;
- p->u.zJContent = zContent;
- return pParse->nNode++;
-}
-
-/*
-** Parse a single JSON value which begins at pParse->zJson[i]. Return the
-** index of the first character past the end of the value parsed.
-**
-** Return negative for a syntax error. Special cases: return -2 if the
-** first non-whitespace character is '}' and return -3 if the first
-** non-whitespace character is ']'.
-*/
-static int jsonParseValue(JsonParse *pParse, u32 i){
- char c;
- u32 j;
- int iThis;
- int x;
- JsonNode *pNode;
- while( safe_isspace(pParse->zJson[i]) ){ i++; }
- if( (c = pParse->zJson[i])=='{' ){
- /* Parse object */
- iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
- if( iThis<0 ) return -1;
- for(j=i+1;;j++){
- while( safe_isspace(pParse->zJson[j]) ){ j++; }
- x = jsonParseValue(pParse, j);
- if( x<0 ){
- if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
- return -1;
- }
- if( pParse->oom ) return -1;
- pNode = &pParse->aNode[pParse->nNode-1];
- if( pNode->eType!=JSON_STRING ) return -1;
- pNode->jnFlags |= JNODE_LABEL;
- j = x;
- while( safe_isspace(pParse->zJson[j]) ){ j++; }
- if( pParse->zJson[j]!=':' ) return -1;
- j++;
- x = jsonParseValue(pParse, j);
- if( x<0 ) return -1;
- j = x;
- while( safe_isspace(pParse->zJson[j]) ){ j++; }
- c = pParse->zJson[j];
- if( c==',' ) continue;
- if( c!='}' ) return -1;
- break;
- }
- pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
- return j+1;
- }else if( c=='[' ){
- /* Parse array */
- iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
- if( iThis<0 ) return -1;
- for(j=i+1;;j++){
- while( safe_isspace(pParse->zJson[j]) ){ j++; }
- x = jsonParseValue(pParse, j);
- if( x<0 ){
- if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1;
- return -1;
- }
- j = x;
- while( safe_isspace(pParse->zJson[j]) ){ j++; }
- c = pParse->zJson[j];
- if( c==',' ) continue;
- if( c!=']' ) return -1;
- break;
- }
- pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
- return j+1;
- }else if( c=='"' ){
- /* Parse string */
- u8 jnFlags = 0;
- j = i+1;
- for(;;){
- c = pParse->zJson[j];
- if( c==0 ) return -1;
- if( c=='\\' ){
- c = pParse->zJson[++j];
- if( c==0 ) return -1;
- jnFlags = JNODE_ESCAPE;
- }else if( c=='"' ){
- break;
- }
- j++;
- }
- jsonParseAddNode(pParse, JSON_STRING, j+1-i, &pParse->zJson[i]);
- if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags;
- return j+1;
- }else if( c=='n'
- && strncmp(pParse->zJson+i,"null",4)==0
- && !safe_isalnum(pParse->zJson[i+4]) ){
- jsonParseAddNode(pParse, JSON_NULL, 0, 0);
- return i+4;
- }else if( c=='t'
- && strncmp(pParse->zJson+i,"true",4)==0
- && !safe_isalnum(pParse->zJson[i+4]) ){
- jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
- return i+4;
- }else if( c=='f'
- && strncmp(pParse->zJson+i,"false",5)==0
- && !safe_isalnum(pParse->zJson[i+5]) ){
- jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
- return i+5;
- }else if( c=='-' || (c>='0' && c<='9') ){
- /* Parse number */
- u8 seenDP = 0;
- u8 seenE = 0;
- j = i+1;
- for(;; j++){
- c = pParse->zJson[j];
- if( c>='0' && c<='9' ) continue;
- if( c=='.' ){
- if( pParse->zJson[j-1]=='-' ) return -1;
- if( seenDP ) return -1;
- seenDP = 1;
- continue;
- }
- if( c=='e' || c=='E' ){
- if( pParse->zJson[j-1]<'0' ) return -1;
- if( seenE ) return -1;
- seenDP = seenE = 1;
- c = pParse->zJson[j+1];
- if( c=='+' || c=='-' ){
- j++;
- c = pParse->zJson[j+1];
- }
- if( c<'0' || c>'9' ) return -1;
- continue;
- }
- break;
- }
- if( pParse->zJson[j-1]<'0' ) return -1;
- jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT,
- j - i, &pParse->zJson[i]);
- return j;
- }else if( c=='}' ){
- return -2; /* End of {...} */
- }else if( c==']' ){
- return -3; /* End of [...] */
- }else if( c==0 ){
- return 0; /* End of file */
- }else{
- return -1; /* Syntax error */
- }
-}
-
-/*
-** Parse a complete JSON string. Return 0 on success or non-zero if there
-** are any errors. If an error occurs, free all memory associated with
-** pParse.
-**
-** pParse is uninitialized when this routine is called.
-*/
-static int jsonParse(
- JsonParse *pParse, /* Initialize and fill this JsonParse object */
- sqlite3_context *pCtx, /* Report errors here */
- const char *zJson /* Input JSON text to be parsed */
-){
- int i;
- memset(pParse, 0, sizeof(*pParse));
- if( zJson==0 ) return 1;
- pParse->zJson = zJson;
- i = jsonParseValue(pParse, 0);
- if( pParse->oom ) i = -1;
- if( i>0 ){
- while( safe_isspace(zJson[i]) ) i++;
- if( zJson[i] ) i = -1;
- }
- if( i<=0 ){
- if( pCtx!=0 ){
- if( pParse->oom ){
- sqlite3_result_error_nomem(pCtx);
- }else{
- sqlite3_result_error(pCtx, "malformed JSON", -1);
- }
- }
- jsonParseReset(pParse);
- return 1;
- }
- return 0;
-}
-
-/* Mark node i of pParse as being a child of iParent. Call recursively
-** to fill in all the descendants of node i.
-*/
-static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){
- JsonNode *pNode = &pParse->aNode[i];
- u32 j;
- pParse->aUp[i] = iParent;
- switch( pNode->eType ){
- case JSON_ARRAY: {
- for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){
- jsonParseFillInParentage(pParse, i+j, i);
- }
- break;
- }
- case JSON_OBJECT: {
- for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){
- pParse->aUp[i+j] = i;
- jsonParseFillInParentage(pParse, i+j+1, i);
- }
- break;
- }
- default: {
- break;
- }
- }
-}
-
-/*
-** Compute the parentage of all nodes in a completed parse.
-*/
-static int jsonParseFindParents(JsonParse *pParse){
- u32 *aUp;
- assert( pParse->aUp==0 );
- aUp = pParse->aUp = sqlite3_malloc( sizeof(u32)*pParse->nNode );
- if( aUp==0 ){
- pParse->oom = 1;
- return SQLITE_NOMEM;
- }
- jsonParseFillInParentage(pParse, 0, 0);
- return SQLITE_OK;
-}
-
-/*
-** Compare the OBJECT label at pNode against zKey,nKey. Return true on
-** a match.
-*/
-static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){
- if( pNode->jnFlags & JNODE_RAW ){
- if( pNode->n!=nKey ) return 0;
- return strncmp(pNode->u.zJContent, zKey, nKey)==0;
- }else{
- if( pNode->n!=nKey+2 ) return 0;
- return strncmp(pNode->u.zJContent+1, zKey, nKey)==0;
- }
-}
-
-/* forward declaration */
-static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**);
-
-/*
-** Search along zPath to find the node specified. Return a pointer
-** to that node, or NULL if zPath is malformed or if there is no such
-** node.
-**
-** If pApnd!=0, then try to append new nodes to complete zPath if it is
-** possible to do so and if no existing node corresponds to zPath. If
-** new nodes are appended *pApnd is set to 1.
-*/
-static JsonNode *jsonLookupStep(
- JsonParse *pParse, /* The JSON to search */
- u32 iRoot, /* Begin the search at this node */
- const char *zPath, /* The path to search */
- int *pApnd, /* Append nodes to complete path if not NULL */
- const char **pzErr /* Make *pzErr point to any syntax error in zPath */
-){
- u32 i, j, nKey;
- const char *zKey;
- JsonNode *pRoot = &pParse->aNode[iRoot];
- if( zPath[0]==0 ) return pRoot;
- if( zPath[0]=='.' ){
- if( pRoot->eType!=JSON_OBJECT ) return 0;
- zPath++;
- if( zPath[0]=='"' ){
- zKey = zPath + 1;
- for(i=1; zPath[i] && zPath[i]!='"'; i++){}
- nKey = i-1;
- if( zPath[i] ){
- i++;
- }else{
- *pzErr = zPath;
- return 0;
- }
- }else{
- zKey = zPath;
- for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){}
- nKey = i;
- }
- if( nKey==0 ){
- *pzErr = zPath;
- return 0;
- }
- j = 1;
- for(;;){
- while( j<=pRoot->n ){
- if( jsonLabelCompare(pRoot+j, zKey, nKey) ){
- return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr);
- }
- j++;
- j += jsonNodeSize(&pRoot[j]);
- }
- if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
- iRoot += pRoot->u.iAppend;
- pRoot = &pParse->aNode[iRoot];
- j = 1;
- }
- if( pApnd ){
- u32 iStart, iLabel;
- JsonNode *pNode;
- iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
- iLabel = jsonParseAddNode(pParse, JSON_STRING, i, zPath);
- zPath += i;
- pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
- if( pParse->oom ) return 0;
- if( pNode ){
- pRoot = &pParse->aNode[iRoot];
- pRoot->u.iAppend = iStart - iRoot;
- pRoot->jnFlags |= JNODE_APPEND;
- pParse->aNode[iLabel].jnFlags |= JNODE_RAW;
- }
- return pNode;
- }
- }else if( zPath[0]=='[' && safe_isdigit(zPath[1]) ){
- if( pRoot->eType!=JSON_ARRAY ) return 0;
- i = 0;
- j = 1;
- while( safe_isdigit(zPath[j]) ){
- i = i*10 + zPath[j] - '0';
- j++;
- }
- if( zPath[j]!=']' ){
- *pzErr = zPath;
- return 0;
- }
- zPath += j + 1;
- j = 1;
- for(;;){
- while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){
- if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--;
- j += jsonNodeSize(&pRoot[j]);
- }
- if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
- iRoot += pRoot->u.iAppend;
- pRoot = &pParse->aNode[iRoot];
- j = 1;
- }
- if( j<=pRoot->n ){
- return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr);
- }
- if( i==0 && pApnd ){
- u32 iStart;
- JsonNode *pNode;
- iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0);
- pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
- if( pParse->oom ) return 0;
- if( pNode ){
- pRoot = &pParse->aNode[iRoot];
- pRoot->u.iAppend = iStart - iRoot;
- pRoot->jnFlags |= JNODE_APPEND;
- }
- return pNode;
- }
- }else{
- *pzErr = zPath;
- }
- return 0;
-}
-
-/*
-** Append content to pParse that will complete zPath. Return a pointer
-** to the inserted node, or return NULL if the append fails.
-*/
-static JsonNode *jsonLookupAppend(
- JsonParse *pParse, /* Append content to the JSON parse */
- const char *zPath, /* Description of content to append */
- int *pApnd, /* Set this flag to 1 */
- const char **pzErr /* Make this point to any syntax error */
-){
- *pApnd = 1;
- if( zPath[0]==0 ){
- jsonParseAddNode(pParse, JSON_NULL, 0, 0);
- return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1];
- }
- if( zPath[0]=='.' ){
- jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
- }else if( strncmp(zPath,"[0]",3)==0 ){
- jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
- }else{
- return 0;
- }
- if( pParse->oom ) return 0;
- return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr);
-}
-
-/*
-** Return the text of a syntax error message on a JSON path. Space is
-** obtained from sqlite3_malloc().
-*/
-static char *jsonPathSyntaxError(const char *zErr){
- return sqlite3_mprintf("JSON path error near '%q'", zErr);
-}
-
-/*
-** Do a node lookup using zPath. Return a pointer to the node on success.
-** Return NULL if not found or if there is an error.
-**
-** On an error, write an error message into pCtx and increment the
-** pParse->nErr counter.
-**
-** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if
-** nodes are appended.
-*/
-static JsonNode *jsonLookup(
- JsonParse *pParse, /* The JSON to search */
- const char *zPath, /* The path to search */
- int *pApnd, /* Append nodes to complete path if not NULL */
- sqlite3_context *pCtx /* Report errors here, if not NULL */
-){
- const char *zErr = 0;
- JsonNode *pNode = 0;
- char *zMsg;
-
- if( zPath==0 ) return 0;
- if( zPath[0]!='$' ){
- zErr = zPath;
- goto lookup_err;
- }
- zPath++;
- pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr);
- if( zErr==0 ) return pNode;
-
-lookup_err:
- pParse->nErr++;
- assert( zErr!=0 && pCtx!=0 );
- zMsg = jsonPathSyntaxError(zErr);
- if( zMsg ){
- sqlite3_result_error(pCtx, zMsg, -1);
- sqlite3_free(zMsg);
- }else{
- sqlite3_result_error_nomem(pCtx);
- }
- return 0;
-}
-
-
-/*
-** Report the wrong number of arguments for json_insert(), json_replace()
-** or json_set().
-*/
-static void jsonWrongNumArgs(
- sqlite3_context *pCtx,
- const char *zFuncName
-){
- char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments",
- zFuncName);
- sqlite3_result_error(pCtx, zMsg, -1);
- sqlite3_free(zMsg);
-}
-
-
-/****************************************************************************
-** SQL functions used for testing and debugging
-****************************************************************************/
-
-#ifdef SQLITE_DEBUG
-/*
-** The json_parse(JSON) function returns a string which describes
-** a parse of the JSON provided. Or it returns NULL if JSON is not
-** well-formed.
-*/
-static void jsonParseFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonString s; /* Output string - not real JSON */
- JsonParse x; /* The parse */
- u32 i;
-
- assert( argc==1 );
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- jsonParseFindParents(&x);
- jsonInit(&s, ctx);
- for(i=0; i<x.nNode; i++){
- const char *zType;
- if( x.aNode[i].jnFlags & JNODE_LABEL ){
- assert( x.aNode[i].eType==JSON_STRING );
- zType = "label";
- }else{
- zType = jsonType[x.aNode[i].eType];
- }
- jsonPrintf(100, &s,"node %3u: %7s n=%-4d up=%-4d",
- i, zType, x.aNode[i].n, x.aUp[i]);
- if( x.aNode[i].u.zJContent!=0 ){
- jsonAppendRaw(&s, " ", 1);
- jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n);
- }
- jsonAppendRaw(&s, "\n", 1);
- }
- jsonParseReset(&x);
- jsonResult(&s);
-}
-
-/*
-** The json_test1(JSON) function return true (1) if the input is JSON
-** text generated by another json function. It returns (0) if the input
-** is not known to be JSON.
-*/
-static void jsonTest1Func(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- UNUSED_PARAM(argc);
- sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE);
-}
-#endif /* SQLITE_DEBUG */
-
-/****************************************************************************
-** Scalar SQL function implementations
-****************************************************************************/
-
-/*
-** Implementation of the json_array(VALUE,...) function. Return a JSON
-** array that contains all values given in arguments. Or if any argument
-** is a BLOB, throw an error.
-*/
-static void jsonArrayFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- int i;
- JsonString jx;
-
- jsonInit(&jx, ctx);
- jsonAppendChar(&jx, '[');
- for(i=0; i<argc; i++){
- jsonAppendSeparator(&jx);
- jsonAppendValue(&jx, argv[i]);
- }
- jsonAppendChar(&jx, ']');
- jsonResult(&jx);
- sqlite3_result_subtype(ctx, JSON_SUBTYPE);
-}
-
-
-/*
-** json_array_length(JSON)
-** json_array_length(JSON, PATH)
-**
-** Return the number of elements in the top-level JSON array.
-** Return 0 if the input is not a well-formed JSON array.
-*/
-static void jsonArrayLengthFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonParse x; /* The parse */
- sqlite3_int64 n = 0;
- u32 i;
- JsonNode *pNode;
-
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
- if( argc==2 ){
- const char *zPath = (const char*)sqlite3_value_text(argv[1]);
- pNode = jsonLookup(&x, zPath, 0, ctx);
- }else{
- pNode = x.aNode;
- }
- if( pNode==0 ){
- x.nErr = 1;
- }else if( pNode->eType==JSON_ARRAY ){
- assert( (pNode->jnFlags & JNODE_APPEND)==0 );
- for(i=1; i<=pNode->n; n++){
- i += jsonNodeSize(&pNode[i]);
- }
- }
- if( x.nErr==0 ) sqlite3_result_int64(ctx, n);
- jsonParseReset(&x);
-}
-
-/*
-** json_extract(JSON, PATH, ...)
-**
-** Return the element described by PATH. Return NULL if there is no
-** PATH element. If there are multiple PATHs, then return a JSON array
-** with the result from each path. Throw an error if the JSON or any PATH
-** is malformed.
-*/
-static void jsonExtractFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonParse x; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- JsonString jx;
- int i;
-
- if( argc<2 ) return;
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- jsonInit(&jx, ctx);
- jsonAppendChar(&jx, '[');
- for(i=1; i<argc; i++){
- zPath = (const char*)sqlite3_value_text(argv[i]);
- pNode = jsonLookup(&x, zPath, 0, ctx);
- if( x.nErr ) break;
- if( argc>2 ){
- jsonAppendSeparator(&jx);
- if( pNode ){
- jsonRenderNode(pNode, &jx, 0);
- }else{
- jsonAppendRaw(&jx, "null", 4);
- }
- }else if( pNode ){
- jsonReturn(pNode, ctx, 0);
- }
- }
- if( argc>2 && i==argc ){
- jsonAppendChar(&jx, ']');
- jsonResult(&jx);
- sqlite3_result_subtype(ctx, JSON_SUBTYPE);
- }
- jsonReset(&jx);
- jsonParseReset(&x);
-}
-
-/*
-** Implementation of the json_object(NAME,VALUE,...) function. Return a JSON
-** object that contains all name/value given in arguments. Or if any name
-** is not a string or if any value is a BLOB, throw an error.
-*/
-static void jsonObjectFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- int i;
- JsonString jx;
- const char *z;
- u32 n;
-
- if( argc&1 ){
- sqlite3_result_error(ctx, "json_object() requires an even number "
- "of arguments", -1);
- return;
- }
- jsonInit(&jx, ctx);
- jsonAppendChar(&jx, '{');
- for(i=0; i<argc; i+=2){
- if( sqlite3_value_type(argv[i])!=SQLITE_TEXT ){
- sqlite3_result_error(ctx, "json_object() labels must be TEXT", -1);
- jsonReset(&jx);
- return;
- }
- jsonAppendSeparator(&jx);
- z = (const char*)sqlite3_value_text(argv[i]);
- n = (u32)sqlite3_value_bytes(argv[i]);
- jsonAppendString(&jx, z, n);
- jsonAppendChar(&jx, ':');
- jsonAppendValue(&jx, argv[i+1]);
- }
- jsonAppendChar(&jx, '}');
- jsonResult(&jx);
- sqlite3_result_subtype(ctx, JSON_SUBTYPE);
-}
-
-
-/*
-** json_remove(JSON, PATH, ...)
-**
-** Remove the named elements from JSON and return the result. malformed
-** JSON or PATH arguments result in an error.
-*/
-static void jsonRemoveFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonParse x; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- u32 i;
-
- if( argc<1 ) return;
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
- for(i=1; i<(u32)argc; i++){
- zPath = (const char*)sqlite3_value_text(argv[i]);
- if( zPath==0 ) goto remove_done;
- pNode = jsonLookup(&x, zPath, 0, ctx);
- if( x.nErr ) goto remove_done;
- if( pNode ) pNode->jnFlags |= JNODE_REMOVE;
- }
- if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){
- jsonReturnJson(x.aNode, ctx, 0);
- }
-remove_done:
- jsonParseReset(&x);
-}
-
-/*
-** json_replace(JSON, PATH, VALUE, ...)
-**
-** Replace the value at PATH with VALUE. If PATH does not already exist,
-** this routine is a no-op. If JSON or PATH is malformed, throw an error.
-*/
-static void jsonReplaceFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonParse x; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- u32 i;
-
- if( argc<1 ) return;
- if( (argc&1)==0 ) {
- jsonWrongNumArgs(ctx, "replace");
- return;
- }
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
- for(i=1; i<(u32)argc; i+=2){
- zPath = (const char*)sqlite3_value_text(argv[i]);
- pNode = jsonLookup(&x, zPath, 0, ctx);
- if( x.nErr ) goto replace_err;
- if( pNode ){
- pNode->jnFlags |= (u8)JNODE_REPLACE;
- pNode->iVal = (u8)(i+1);
- }
- }
- if( x.aNode[0].jnFlags & JNODE_REPLACE ){
- sqlite3_result_value(ctx, argv[x.aNode[0].iVal]);
- }else{
- jsonReturnJson(x.aNode, ctx, argv);
- }
-replace_err:
- jsonParseReset(&x);
-}
-
-/*
-** json_set(JSON, PATH, VALUE, ...)
-**
-** Set the value at PATH to VALUE. Create the PATH if it does not already
-** exist. Overwrite existing values that do exist.
-** If JSON or PATH is malformed, throw an error.
-**
-** json_insert(JSON, PATH, VALUE, ...)
-**
-** Create PATH and initialize it to VALUE. If PATH already exists, this
-** routine is a no-op. If JSON or PATH is malformed, throw an error.
-*/
-static void jsonSetFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonParse x; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- u32 i;
- int bApnd;
- int bIsSet = *(int*)sqlite3_user_data(ctx);
-
- if( argc<1 ) return;
- if( (argc&1)==0 ) {
- jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert");
- return;
- }
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
- for(i=1; i<(u32)argc; i+=2){
- zPath = (const char*)sqlite3_value_text(argv[i]);
- bApnd = 0;
- pNode = jsonLookup(&x, zPath, &bApnd, ctx);
- if( x.oom ){
- sqlite3_result_error_nomem(ctx);
- goto jsonSetDone;
- }else if( x.nErr ){
- goto jsonSetDone;
- }else if( pNode && (bApnd || bIsSet) ){
- pNode->jnFlags |= (u8)JNODE_REPLACE;
- pNode->iVal = (u8)(i+1);
- }
- }
- if( x.aNode[0].jnFlags & JNODE_REPLACE ){
- sqlite3_result_value(ctx, argv[x.aNode[0].iVal]);
- }else{
- jsonReturnJson(x.aNode, ctx, argv);
- }
-jsonSetDone:
- jsonParseReset(&x);
-}
-
-/*
-** json_type(JSON)
-** json_type(JSON, PATH)
-**
-** Return the top-level "type" of a JSON string. Throw an error if
-** either the JSON or PATH inputs are not well-formed.
-*/
-static void jsonTypeFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonParse x; /* The parse */
- const char *zPath;
- JsonNode *pNode;
-
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
- if( argc==2 ){
- zPath = (const char*)sqlite3_value_text(argv[1]);
- pNode = jsonLookup(&x, zPath, 0, ctx);
- }else{
- pNode = x.aNode;
- }
- if( pNode ){
- sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC);
- }
- jsonParseReset(&x);
-}
-
-/*
-** json_valid(JSON)
-**
-** Return 1 if JSON is a well-formed JSON string according to RFC-7159.
-** Return 0 otherwise.
-*/
-static void jsonValidFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonParse x; /* The parse */
- int rc = 0;
-
- UNUSED_PARAM(argc);
- if( jsonParse(&x, 0, (const char*)sqlite3_value_text(argv[0]))==0 ){
- rc = 1;
- }
- jsonParseReset(&x);
- sqlite3_result_int(ctx, rc);
-}
-
-
-/****************************************************************************
-** Aggregate SQL function implementations
-****************************************************************************/
-/*
-** json_group_array(VALUE)
-**
-** Return a JSON array composed of all values in the aggregate.
-*/
-static void jsonArrayStep(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonString *pStr;
- UNUSED_PARAM(argc);
- pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
- if( pStr ){
- if( pStr->zBuf==0 ){
- jsonInit(pStr, ctx);
- jsonAppendChar(pStr, '[');
- }else{
- jsonAppendChar(pStr, ',');
- pStr->pCtx = ctx;
- }
- jsonAppendValue(pStr, argv[0]);
- }
-}
-static void jsonArrayFinal(sqlite3_context *ctx){
- JsonString *pStr;
- pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
- if( pStr ){
- pStr->pCtx = ctx;
- jsonAppendChar(pStr, ']');
- if( pStr->bErr ){
- if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
- assert( pStr->bStatic );
- }else{
- sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
- pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
- pStr->bStatic = 1;
- }
- }else{
- sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC);
- }
- sqlite3_result_subtype(ctx, JSON_SUBTYPE);
-}
-
-/*
-** json_group_obj(NAME,VALUE)
-**
-** Return a JSON object composed of all names and values in the aggregate.
-*/
-static void jsonObjectStep(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonString *pStr;
- const char *z;
- u32 n;
- UNUSED_PARAM(argc);
- pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
- if( pStr ){
- if( pStr->zBuf==0 ){
- jsonInit(pStr, ctx);
- jsonAppendChar(pStr, '{');
- }else{
- jsonAppendChar(pStr, ',');
- pStr->pCtx = ctx;
- }
- z = (const char*)sqlite3_value_text(argv[0]);
- n = (u32)sqlite3_value_bytes(argv[0]);
- jsonAppendString(pStr, z, n);
- jsonAppendChar(pStr, ':');
- jsonAppendValue(pStr, argv[1]);
- }
-}
-static void jsonObjectFinal(sqlite3_context *ctx){
- JsonString *pStr;
- pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
- if( pStr ){
- jsonAppendChar(pStr, '}');
- if( pStr->bErr ){
- if( pStr->bErr==0 ) sqlite3_result_error_nomem(ctx);
- assert( pStr->bStatic );
- }else{
- sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
- pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
- pStr->bStatic = 1;
- }
- }else{
- sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC);
- }
- sqlite3_result_subtype(ctx, JSON_SUBTYPE);
-}
-
-
-#ifndef SQLITE_OMIT_VIRTUALTABLE
-/****************************************************************************
-** The json_each virtual table
-****************************************************************************/
-typedef struct JsonEachCursor JsonEachCursor;
-struct JsonEachCursor {
- sqlite3_vtab_cursor base; /* Base class - must be first */
- u32 iRowid; /* The rowid */
- u32 iBegin; /* The first node of the scan */
- u32 i; /* Index in sParse.aNode[] of current row */
- u32 iEnd; /* EOF when i equals or exceeds this value */
- u8 eType; /* Type of top-level element */
- u8 bRecursive; /* True for json_tree(). False for json_each() */
- char *zJson; /* Input JSON */
- char *zRoot; /* Path by which to filter zJson */
- JsonParse sParse; /* Parse of the input JSON */
-};
-
-/* Constructor for the json_each virtual table */
-static int jsonEachConnect(
- sqlite3 *db,
- void *pAux,
- int argc, const char *const*argv,
- sqlite3_vtab **ppVtab,
- char **pzErr
-){
- sqlite3_vtab *pNew;
- int rc;
-
-/* Column numbers */
-#define JEACH_KEY 0
-#define JEACH_VALUE 1
-#define JEACH_TYPE 2
-#define JEACH_ATOM 3
-#define JEACH_ID 4
-#define JEACH_PARENT 5
-#define JEACH_FULLKEY 6
-#define JEACH_PATH 7
-#define JEACH_JSON 8
-#define JEACH_ROOT 9
-
- UNUSED_PARAM(pzErr);
- UNUSED_PARAM(argv);
- UNUSED_PARAM(argc);
- UNUSED_PARAM(pAux);
- rc = sqlite3_declare_vtab(db,
- "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path,"
- "json HIDDEN,root HIDDEN)");
- if( rc==SQLITE_OK ){
- pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
- if( pNew==0 ) return SQLITE_NOMEM;
- memset(pNew, 0, sizeof(*pNew));
- }
- return rc;
-}
-
-/* destructor for json_each virtual table */
-static int jsonEachDisconnect(sqlite3_vtab *pVtab){
- sqlite3_free(pVtab);
- return SQLITE_OK;
-}
-
-/* constructor for a JsonEachCursor object for json_each(). */
-static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
- JsonEachCursor *pCur;
-
- UNUSED_PARAM(p);
- pCur = sqlite3_malloc( sizeof(*pCur) );
- if( pCur==0 ) return SQLITE_NOMEM;
- memset(pCur, 0, sizeof(*pCur));
- *ppCursor = &pCur->base;
- return SQLITE_OK;
-}
-
-/* constructor for a JsonEachCursor object for json_tree(). */
-static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
- int rc = jsonEachOpenEach(p, ppCursor);
- if( rc==SQLITE_OK ){
- JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor;
- pCur->bRecursive = 1;
- }
- return rc;
-}
-
-/* Reset a JsonEachCursor back to its original state. Free any memory
-** held. */
-static void jsonEachCursorReset(JsonEachCursor *p){
- sqlite3_free(p->zJson);
- sqlite3_free(p->zRoot);
- jsonParseReset(&p->sParse);
- p->iRowid = 0;
- p->i = 0;
- p->iEnd = 0;
- p->eType = 0;
- p->zJson = 0;
- p->zRoot = 0;
-}
-
-/* Destructor for a jsonEachCursor object */
-static int jsonEachClose(sqlite3_vtab_cursor *cur){
- JsonEachCursor *p = (JsonEachCursor*)cur;
- jsonEachCursorReset(p);
- sqlite3_free(cur);
- return SQLITE_OK;
-}
-
-/* Return TRUE if the jsonEachCursor object has been advanced off the end
-** of the JSON object */
-static int jsonEachEof(sqlite3_vtab_cursor *cur){
- JsonEachCursor *p = (JsonEachCursor*)cur;
- return p->i >= p->iEnd;
-}
-
-/* Advance the cursor to the next element for json_tree() */
-static int jsonEachNext(sqlite3_vtab_cursor *cur){
- JsonEachCursor *p = (JsonEachCursor*)cur;
- if( p->bRecursive ){
- if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++;
- p->i++;
- p->iRowid++;
- if( p->i<p->iEnd ){
- u32 iUp = p->sParse.aUp[p->i];
- JsonNode *pUp = &p->sParse.aNode[iUp];
- p->eType = pUp->eType;
- if( pUp->eType==JSON_ARRAY ){
- if( iUp==p->i-1 ){
- pUp->u.iKey = 0;
- }else{
- pUp->u.iKey++;
- }
- }
- }
- }else{
- switch( p->eType ){
- case JSON_ARRAY: {
- p->i += jsonNodeSize(&p->sParse.aNode[p->i]);
- p->iRowid++;
- break;
- }
- case JSON_OBJECT: {
- p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]);
- p->iRowid++;
- break;
- }
- default: {
- p->i = p->iEnd;
- break;
- }
- }
- }
- return SQLITE_OK;
-}
-
-/* Append the name of the path for element i to pStr
-*/
-static void jsonEachComputePath(
- JsonEachCursor *p, /* The cursor */
- JsonString *pStr, /* Write the path here */
- u32 i /* Path to this element */
-){
- JsonNode *pNode, *pUp;
- u32 iUp;
- if( i==0 ){
- jsonAppendChar(pStr, '$');
- return;
- }
- iUp = p->sParse.aUp[i];
- jsonEachComputePath(p, pStr, iUp);
- pNode = &p->sParse.aNode[i];
- pUp = &p->sParse.aNode[iUp];
- if( pUp->eType==JSON_ARRAY ){
- jsonPrintf(30, pStr, "[%d]", pUp->u.iKey);
- }else{
- assert( pUp->eType==JSON_OBJECT );
- if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--;
- assert( pNode->eType==JSON_STRING );
- assert( pNode->jnFlags & JNODE_LABEL );
- jsonPrintf(pNode->n+1, pStr, ".%.*s", pNode->n-2, pNode->u.zJContent+1);
- }
-}
-
-/* Return the value of a column */
-static int jsonEachColumn(
- sqlite3_vtab_cursor *cur, /* The cursor */
- sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
- int i /* Which column to return */
-){
- JsonEachCursor *p = (JsonEachCursor*)cur;
- JsonNode *pThis = &p->sParse.aNode[p->i];
- switch( i ){
- case JEACH_KEY: {
- if( p->i==0 ) break;
- if( p->eType==JSON_OBJECT ){
- jsonReturn(pThis, ctx, 0);
- }else if( p->eType==JSON_ARRAY ){
- u32 iKey;
- if( p->bRecursive ){
- if( p->iRowid==0 ) break;
- iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey;
- }else{
- iKey = p->iRowid;
- }
- sqlite3_result_int64(ctx, (sqlite3_int64)iKey);
- }
- break;
- }
- case JEACH_VALUE: {
- if( pThis->jnFlags & JNODE_LABEL ) pThis++;
- jsonReturn(pThis, ctx, 0);
- break;
- }
- case JEACH_TYPE: {
- if( pThis->jnFlags & JNODE_LABEL ) pThis++;
- sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC);
- break;
- }
- case JEACH_ATOM: {
- if( pThis->jnFlags & JNODE_LABEL ) pThis++;
- if( pThis->eType>=JSON_ARRAY ) break;
- jsonReturn(pThis, ctx, 0);
- break;
- }
- case JEACH_ID: {
- sqlite3_result_int64(ctx,
- (sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0));
- break;
- }
- case JEACH_PARENT: {
- if( p->i>p->iBegin && p->bRecursive ){
- sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]);
- }
- break;
- }
- case JEACH_FULLKEY: {
- JsonString x;
- jsonInit(&x, ctx);
- if( p->bRecursive ){
- jsonEachComputePath(p, &x, p->i);
- }else{
- if( p->zRoot ){
- jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot));
- }else{
- jsonAppendChar(&x, '$');
- }
- if( p->eType==JSON_ARRAY ){
- jsonPrintf(30, &x, "[%d]", p->iRowid);
- }else{
- jsonPrintf(pThis->n, &x, ".%.*s", pThis->n-2, pThis->u.zJContent+1);
- }
- }
- jsonResult(&x);
- break;
- }
- case JEACH_PATH: {
- if( p->bRecursive ){
- JsonString x;
- jsonInit(&x, ctx);
- jsonEachComputePath(p, &x, p->sParse.aUp[p->i]);
- jsonResult(&x);
- break;
- }
- /* For json_each() path and root are the same so fall through
- ** into the root case */
- }
- case JEACH_ROOT: {
- const char *zRoot = p->zRoot;
- if( zRoot==0 ) zRoot = "$";
- sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
- break;
- }
- case JEACH_JSON: {
- assert( i==JEACH_JSON );
- sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC);
- break;
- }
- }
- return SQLITE_OK;
-}
-
-/* Return the current rowid value */
-static int jsonEachRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
- JsonEachCursor *p = (JsonEachCursor*)cur;
- *pRowid = p->iRowid;
- return SQLITE_OK;
-}
-
-/* The query strategy is to look for an equality constraint on the json
-** column. Without such a constraint, the table cannot operate. idxNum is
-** 1 if the constraint is found, 3 if the constraint and zRoot are found,
-** and 0 otherwise.
-*/
-static int jsonEachBestIndex(
- sqlite3_vtab *tab,
- sqlite3_index_info *pIdxInfo
-){
- int i;
- int jsonIdx = -1;
- int rootIdx = -1;
- const struct sqlite3_index_constraint *pConstraint;
-
- UNUSED_PARAM(tab);
- pConstraint = pIdxInfo->aConstraint;
- for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
- if( pConstraint->usable==0 ) continue;
- if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
- switch( pConstraint->iColumn ){
- case JEACH_JSON: jsonIdx = i; break;
- case JEACH_ROOT: rootIdx = i; break;
- default: /* no-op */ break;
- }
- }
- if( jsonIdx<0 ){
- pIdxInfo->idxNum = 0;
- pIdxInfo->estimatedCost = 1e99;
- }else{
- pIdxInfo->estimatedCost = 1.0;
- pIdxInfo->aConstraintUsage[jsonIdx].argvIndex = 1;
- pIdxInfo->aConstraintUsage[jsonIdx].omit = 1;
- if( rootIdx<0 ){
- pIdxInfo->idxNum = 1;
- }else{
- pIdxInfo->aConstraintUsage[rootIdx].argvIndex = 2;
- pIdxInfo->aConstraintUsage[rootIdx].omit = 1;
- pIdxInfo->idxNum = 3;
- }
- }
- return SQLITE_OK;
-}
-
-/* Start a search on a new JSON string */
-static int jsonEachFilter(
- sqlite3_vtab_cursor *cur,
- int idxNum, const char *idxStr,
- int argc, sqlite3_value **argv
-){
- JsonEachCursor *p = (JsonEachCursor*)cur;
- const char *z;
- const char *zRoot = 0;
- sqlite3_int64 n;
-
- UNUSED_PARAM(idxStr);
- UNUSED_PARAM(argc);
- jsonEachCursorReset(p);
- if( idxNum==0 ) return SQLITE_OK;
- z = (const char*)sqlite3_value_text(argv[0]);
- if( z==0 ) return SQLITE_OK;
- n = sqlite3_value_bytes(argv[0]);
- p->zJson = sqlite3_malloc64( n+1 );
- if( p->zJson==0 ) return SQLITE_NOMEM;
- memcpy(p->zJson, z, (size_t)n+1);
- if( jsonParse(&p->sParse, 0, p->zJson) ){
- int rc = SQLITE_NOMEM;
- if( p->sParse.oom==0 ){
- sqlite3_free(cur->pVtab->zErrMsg);
- cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON");
- if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR;
- }
- jsonEachCursorReset(p);
- return rc;
- }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){
- jsonEachCursorReset(p);
- return SQLITE_NOMEM;
- }else{
- JsonNode *pNode = 0;
- if( idxNum==3 ){
- const char *zErr = 0;
- zRoot = (const char*)sqlite3_value_text(argv[1]);
- if( zRoot==0 ) return SQLITE_OK;
- n = sqlite3_value_bytes(argv[1]);
- p->zRoot = sqlite3_malloc64( n+1 );
- if( p->zRoot==0 ) return SQLITE_NOMEM;
- memcpy(p->zRoot, zRoot, (size_t)n+1);
- if( zRoot[0]!='$' ){
- zErr = zRoot;
- }else{
- pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr);
- }
- if( zErr ){
- sqlite3_free(cur->pVtab->zErrMsg);
- cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr);
- jsonEachCursorReset(p);
- return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
- }else if( pNode==0 ){
- return SQLITE_OK;
- }
- }else{
- pNode = p->sParse.aNode;
- }
- p->iBegin = p->i = (int)(pNode - p->sParse.aNode);
- p->eType = pNode->eType;
- if( p->eType>=JSON_ARRAY ){
- pNode->u.iKey = 0;
- p->iEnd = p->i + pNode->n + 1;
- if( p->bRecursive ){
- p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType;
- if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){
- p->i--;
- }
- }else{
- p->i++;
- }
- }else{
- p->iEnd = p->i+1;
- }
- }
- return SQLITE_OK;
-}
-
-/* The methods of the json_each virtual table */
-static sqlite3_module jsonEachModule = {
- 0, /* iVersion */
- 0, /* xCreate */
- jsonEachConnect, /* xConnect */
- jsonEachBestIndex, /* xBestIndex */
- jsonEachDisconnect, /* xDisconnect */
- 0, /* xDestroy */
- jsonEachOpenEach, /* xOpen - open a cursor */
- jsonEachClose, /* xClose - close a cursor */
- jsonEachFilter, /* xFilter - configure scan constraints */
- jsonEachNext, /* xNext - advance a cursor */
- jsonEachEof, /* xEof - check for end of scan */
- jsonEachColumn, /* xColumn - read data */
- jsonEachRowid, /* xRowid - read data */
- 0, /* xUpdate */
- 0, /* xBegin */
- 0, /* xSync */
- 0, /* xCommit */
- 0, /* xRollback */
- 0, /* xFindMethod */
- 0, /* xRename */
- 0, /* xSavepoint */
- 0, /* xRelease */
- 0 /* xRollbackTo */
-};
-
-/* The methods of the json_tree virtual table. */
-static sqlite3_module jsonTreeModule = {
- 0, /* iVersion */
- 0, /* xCreate */
- jsonEachConnect, /* xConnect */
- jsonEachBestIndex, /* xBestIndex */
- jsonEachDisconnect, /* xDisconnect */
- 0, /* xDestroy */
- jsonEachOpenTree, /* xOpen - open a cursor */
- jsonEachClose, /* xClose - close a cursor */
- jsonEachFilter, /* xFilter - configure scan constraints */
- jsonEachNext, /* xNext - advance a cursor */
- jsonEachEof, /* xEof - check for end of scan */
- jsonEachColumn, /* xColumn - read data */
- jsonEachRowid, /* xRowid - read data */
- 0, /* xUpdate */
- 0, /* xBegin */
- 0, /* xSync */
- 0, /* xCommit */
- 0, /* xRollback */
- 0, /* xFindMethod */
- 0, /* xRename */
- 0, /* xSavepoint */
- 0, /* xRelease */
- 0 /* xRollbackTo */
-};
-#endif /* SQLITE_OMIT_VIRTUALTABLE */
-
-/****************************************************************************
-** The following routines are the only publically visible identifiers in this
-** file. Call the following routines in order to register the various SQL
-** functions and the virtual table implemented by this file.
-****************************************************************************/
-
-SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){
- int rc = SQLITE_OK;
- unsigned int i;
- static const struct {
- const char *zName;
- int nArg;
- int flag;
- void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
- } aFunc[] = {
- { "json", 1, 0, jsonRemoveFunc },
- { "json_array", -1, 0, jsonArrayFunc },
- { "json_array_length", 1, 0, jsonArrayLengthFunc },
- { "json_array_length", 2, 0, jsonArrayLengthFunc },
- { "json_extract", -1, 0, jsonExtractFunc },
- { "json_insert", -1, 0, jsonSetFunc },
- { "json_object", -1, 0, jsonObjectFunc },
- { "json_remove", -1, 0, jsonRemoveFunc },
- { "json_replace", -1, 0, jsonReplaceFunc },
- { "json_set", -1, 1, jsonSetFunc },
- { "json_type", 1, 0, jsonTypeFunc },
- { "json_type", 2, 0, jsonTypeFunc },
- { "json_valid", 1, 0, jsonValidFunc },
-
-#if SQLITE_DEBUG
- /* DEBUG and TESTING functions */
- { "json_parse", 1, 0, jsonParseFunc },
- { "json_test1", 1, 0, jsonTest1Func },
-#endif
- };
- static const struct {
- const char *zName;
- int nArg;
- void (*xStep)(sqlite3_context*,int,sqlite3_value**);
- void (*xFinal)(sqlite3_context*);
- } aAgg[] = {
- { "json_group_array", 1, jsonArrayStep, jsonArrayFinal },
- { "json_group_object", 2, jsonObjectStep, jsonObjectFinal },
- };
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- static const struct {
- const char *zName;
- sqlite3_module *pModule;
- } aMod[] = {
- { "json_each", &jsonEachModule },
- { "json_tree", &jsonTreeModule },
- };
-#endif
- for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
- rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg,
- SQLITE_UTF8 | SQLITE_DETERMINISTIC,
- (void*)&aFunc[i].flag,
- aFunc[i].xFunc, 0, 0);
- }
- for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
- rc = sqlite3_create_function(db, aAgg[i].zName, aAgg[i].nArg,
- SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
- 0, aAgg[i].xStep, aAgg[i].xFinal);
- }
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){
- rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0);
- }
-#endif
- return rc;
-}
-
-
-#ifndef SQLITE_CORE
-#ifdef _WIN32
-__declspec(dllexport)
-#endif
-SQLITE_API int SQLITE_STDCALL sqlite3_json_init(
- sqlite3 *db,
- char **pzErrMsg,
- const sqlite3_api_routines *pApi
-){
- SQLITE_EXTENSION_INIT2(pApi);
- (void)pzErrMsg; /* Unused parameter */
- return sqlite3Json1Init(db);
-}
-#endif
-#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) */
-
-/************** End of json1.c ***********************************************/
-/************** Begin file fts5.c ********************************************/
-
-
-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5)
-
-#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
-# define NDEBUG 1
-#endif
-#if defined(NDEBUG) && defined(SQLITE_DEBUG)
-# undef NDEBUG
-#endif
-
-/*
-** 2014 May 31
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** Interfaces to extend FTS5. Using the interfaces defined in this file,
-** FTS5 may be extended with:
-**
-** * custom tokenizers, and
-** * custom auxiliary functions.
-*/
-
-
-#ifndef _FTS5_H
-#define _FTS5_H
-
-/* #include "sqlite3.h" */
-
-#if 0
-extern "C" {
-#endif
-
-/*************************************************************************
-** CUSTOM AUXILIARY FUNCTIONS
-**
-** Virtual table implementations may overload SQL functions by implementing
-** the sqlite3_module.xFindFunction() method.
-*/
-
-typedef struct Fts5ExtensionApi Fts5ExtensionApi;
-typedef struct Fts5Context Fts5Context;
-typedef struct Fts5PhraseIter Fts5PhraseIter;
-
-typedef void (*fts5_extension_function)(
- const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
- Fts5Context *pFts, /* First arg to pass to pApi functions */
- sqlite3_context *pCtx, /* Context for returning result/error */
- int nVal, /* Number of values in apVal[] array */
- sqlite3_value **apVal /* Array of trailing arguments */
-);
-
-struct Fts5PhraseIter {
- const unsigned char *a;
- const unsigned char *b;
-};
-
-/*
-** EXTENSION API FUNCTIONS
-**
-** xUserData(pFts):
-** Return a copy of the context pointer the extension function was
-** registered with.
-**
-** xColumnTotalSize(pFts, iCol, pnToken):
-** If parameter iCol is less than zero, set output variable *pnToken
-** to the total number of tokens in the FTS5 table. Or, if iCol is
-** non-negative but less than the number of columns in the table, return
-** the total number of tokens in column iCol, considering all rows in
-** the FTS5 table.
-**
-** If parameter iCol is greater than or equal to the number of columns
-** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
-** an OOM condition or IO error), an appropriate SQLite error code is
-** returned.
-**
-** xColumnCount(pFts):
-** Return the number of columns in the table.
-**
-** xColumnSize(pFts, iCol, pnToken):
-** If parameter iCol is less than zero, set output variable *pnToken
-** to the total number of tokens in the current row. Or, if iCol is
-** non-negative but less than the number of columns in the table, set
-** *pnToken to the number of tokens in column iCol of the current row.
-**
-** If parameter iCol is greater than or equal to the number of columns
-** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
-** an OOM condition or IO error), an appropriate SQLite error code is
-** returned.
-**
-** This function may be quite inefficient if used with an FTS5 table
-** created with the "columnsize=0" option.
-**
-** xColumnText:
-** This function attempts to retrieve the text of column iCol of the
-** current document. If successful, (*pz) is set to point to a buffer
-** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
-** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
-** if an error occurs, an SQLite error code is returned and the final values
-** of (*pz) and (*pn) are undefined.
-**
-** xPhraseCount:
-** Returns the number of phrases in the current query expression.
-**
-** xPhraseSize:
-** Returns the number of tokens in phrase iPhrase of the query. Phrases
-** are numbered starting from zero.
-**
-** xInstCount:
-** Set *pnInst to the total number of occurrences of all phrases within
-** the query within the current row. Return SQLITE_OK if successful, or
-** an error code (i.e. SQLITE_NOMEM) if an error occurs.
-**
-** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" or "detail=column" option. If the FTS5 table is created
-** with either "detail=none" or "detail=column" and "content=" option
-** (i.e. if it is a contentless table), then this API always returns 0.
-**
-** xInst:
-** Query for the details of phrase match iIdx within the current row.
-** Phrase matches are numbered starting from zero, so the iIdx argument
-** should be greater than or equal to zero and smaller than the value
-** output by xInstCount().
-**
-** Usually, output parameter *piPhrase is set to the phrase number, *piCol
-** to the column in which it occurs and *piOff the token offset of the
-** first token of the phrase. The exception is if the table was created
-** with the offsets=0 option specified. In this case *piOff is always
-** set to -1.
-**
-** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
-** if an error occurs.
-**
-** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" or "detail=column" option.
-**
-** xRowid:
-** Returns the rowid of the current row.
-**
-** xTokenize:
-** Tokenize text using the tokenizer belonging to the FTS5 table.
-**
-** xQueryPhrase(pFts5, iPhrase, pUserData, xCallback):
-** This API function is used to query the FTS table for phrase iPhrase
-** of the current query. Specifically, a query equivalent to:
-**
-** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid
-**
-** with $p set to a phrase equivalent to the phrase iPhrase of the
-** current query is executed. Any column filter that applies to
-** phrase iPhrase of the current query is included in $p. For each
-** row visited, the callback function passed as the fourth argument
-** is invoked. The context and API objects passed to the callback
-** function may be used to access the properties of each matched row.
-** Invoking Api.xUserData() returns a copy of the pointer passed as
-** the third argument to pUserData.
-**
-** If the callback function returns any value other than SQLITE_OK, the
-** query is abandoned and the xQueryPhrase function returns immediately.
-** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
-** Otherwise, the error code is propagated upwards.
-**
-** If the query runs to completion without incident, SQLITE_OK is returned.
-** Or, if some error occurs before the query completes or is aborted by
-** the callback, an SQLite error code is returned.
-**
-**
-** xSetAuxdata(pFts5, pAux, xDelete)
-**
-** Save the pointer passed as the second argument as the extension functions
-** "auxiliary data". The pointer may then be retrieved by the current or any
-** future invocation of the same fts5 extension function made as part of
-** of the same MATCH query using the xGetAuxdata() API.
-**
-** Each extension function is allocated a single auxiliary data slot for
-** each FTS query (MATCH expression). If the extension function is invoked
-** more than once for a single FTS query, then all invocations share a
-** single auxiliary data context.
-**
-** If there is already an auxiliary data pointer when this function is
-** invoked, then it is replaced by the new pointer. If an xDelete callback
-** was specified along with the original pointer, it is invoked at this
-** point.
-**
-** The xDelete callback, if one is specified, is also invoked on the
-** auxiliary data pointer after the FTS5 query has finished.
-**
-** If an error (e.g. an OOM condition) occurs within this function, an
-** the auxiliary data is set to NULL and an error code returned. If the
-** xDelete parameter was not NULL, it is invoked on the auxiliary data
-** pointer before returning.
-**
-**
-** xGetAuxdata(pFts5, bClear)
-**
-** Returns the current auxiliary data pointer for the fts5 extension
-** function. See the xSetAuxdata() method for details.
-**
-** If the bClear argument is non-zero, then the auxiliary data is cleared
-** (set to NULL) before this function returns. In this case the xDelete,
-** if any, is not invoked.
-**
-**
-** xRowCount(pFts5, pnRow)
-**
-** This function is used to retrieve the total number of rows in the table.
-** In other words, the same value that would be returned by:
-**
-** SELECT count(*) FROM ftstable;
-**
-** xPhraseFirst()
-** This function is used, along with type Fts5PhraseIter and the xPhraseNext
-** method, to iterate through all instances of a single query phrase within
-** the current row. This is the same information as is accessible via the
-** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient
-** to use, this API may be faster under some circumstances. To iterate
-** through instances of phrase iPhrase, use the following code:
-**
-** Fts5PhraseIter iter;
-** int iCol, iOff;
-** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
-** iCol>=0;
-** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
-** ){
-** // An instance of phrase iPhrase at offset iOff of column iCol
-** }
-**
-** The Fts5PhraseIter structure is defined above. Applications should not
-** modify this structure directly - it should only be used as shown above
-** with the xPhraseFirst() and xPhraseNext() API methods (and by
-** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
-**
-** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" or "detail=column" option. If the FTS5 table is created
-** with either "detail=none" or "detail=column" and "content=" option
-** (i.e. if it is a contentless table), then this API always iterates
-** through an empty set (all calls to xPhraseFirst() set iCol to -1).
-**
-** xPhraseNext()
-** See xPhraseFirst above.
-**
-** xPhraseFirstColumn()
-** This function and xPhraseNextColumn() are similar to the xPhraseFirst()
-** and xPhraseNext() APIs described above. The difference is that instead
-** of iterating through all instances of a phrase in the current row, these
-** APIs are used to iterate through the set of columns in the current row
-** that contain one or more instances of a specified phrase. For example:
-**
-** Fts5PhraseIter iter;
-** int iCol;
-** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol);
-** iCol>=0;
-** pApi->xPhraseNextColumn(pFts, &iter, &iCol)
-** ){
-** // Column iCol contains at least one instance of phrase iPhrase
-** }
-**
-** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" option. If the FTS5 table is created with either
-** "detail=none" "content=" option (i.e. if it is a contentless table),
-** then this API always iterates through an empty set (all calls to
-** xPhraseFirstColumn() set iCol to -1).
-**
-** The information accessed using this API and its companion
-** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
-** (or xInst/xInstCount). The chief advantage of this API is that it is
-** significantly more efficient than those alternatives when used with
-** "detail=column" tables.
-**
-** xPhraseNextColumn()
-** See xPhraseFirstColumn above.
-*/
-struct Fts5ExtensionApi {
- int iVersion; /* Currently always set to 3 */
-
- void *(*xUserData)(Fts5Context*);
-
- int (*xColumnCount)(Fts5Context*);
- int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
- int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken);
-
- int (*xTokenize)(Fts5Context*,
- const char *pText, int nText, /* Text to tokenize */
- void *pCtx, /* Context passed to xToken() */
- int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
- );
-
- int (*xPhraseCount)(Fts5Context*);
- int (*xPhraseSize)(Fts5Context*, int iPhrase);
-
- int (*xInstCount)(Fts5Context*, int *pnInst);
- int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff);
-
- sqlite3_int64 (*xRowid)(Fts5Context*);
- int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn);
- int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken);
-
- int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData,
- int(*)(const Fts5ExtensionApi*,Fts5Context*,void*)
- );
- int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
- void *(*xGetAuxdata)(Fts5Context*, int bClear);
-
- int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
- void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
-
- int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
- void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
-};
-
-/*
-** CUSTOM AUXILIARY FUNCTIONS
-*************************************************************************/
-
-/*************************************************************************
-** CUSTOM TOKENIZERS
-**
-** Applications may also register custom tokenizer types. A tokenizer
-** is registered by providing fts5 with a populated instance of the
-** following structure. All structure methods must be defined, setting
-** any member of the fts5_tokenizer struct to NULL leads to undefined
-** behaviour. The structure methods are expected to function as follows:
-**
-** xCreate:
-** This function is used to allocate and inititalize a tokenizer instance.
-** A tokenizer instance is required to actually tokenize text.
-**
-** The first argument passed to this function is a copy of the (void*)
-** pointer provided by the application when the fts5_tokenizer object
-** was registered with FTS5 (the third argument to xCreateTokenizer()).
-** The second and third arguments are an array of nul-terminated strings
-** containing the tokenizer arguments, if any, specified following the
-** tokenizer name as part of the CREATE VIRTUAL TABLE statement used
-** to create the FTS5 table.
-**
-** The final argument is an output variable. If successful, (*ppOut)
-** should be set to point to the new tokenizer handle and SQLITE_OK
-** returned. If an error occurs, some value other than SQLITE_OK should
-** be returned. In this case, fts5 assumes that the final value of *ppOut
-** is undefined.
-**
-** xDelete:
-** This function is invoked to delete a tokenizer handle previously
-** allocated using xCreate(). Fts5 guarantees that this function will
-** be invoked exactly once for each successful call to xCreate().
-**
-** xTokenize:
-** This function is expected to tokenize the nText byte string indicated
-** by argument pText. pText may or may not be nul-terminated. The first
-** argument passed to this function is a pointer to an Fts5Tokenizer object
-** returned by an earlier call to xCreate().
-**
-** The second argument indicates the reason that FTS5 is requesting
-** tokenization of the supplied text. This is always one of the following
-** four values:
-**
-** <ul><li> <b>FTS5_TOKENIZE_DOCUMENT</b> - A document is being inserted into
-** or removed from the FTS table. The tokenizer is being invoked to
-** determine the set of tokens to add to (or delete from) the
-** FTS index.
-**
-** <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed
-** against the FTS index. The tokenizer is being called to tokenize
-** a bareword or quoted string specified as part of the query.
-**
-** <li> <b>(FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX)</b> - Same as
-** FTS5_TOKENIZE_QUERY, except that the bareword or quoted string is
-** followed by a "*" character, indicating that the last token
-** returned by the tokenizer will be treated as a token prefix.
-**
-** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
-** satisfy an fts5_api.xTokenize() request made by an auxiliary
-** function. Or an fts5_api.xColumnSize() request made by the same
-** on a columnsize=0 database.
-** </ul>
-**
-** For each token in the input string, the supplied callback xToken() must
-** be invoked. The first argument to it should be a copy of the pointer
-** passed as the second argument to xTokenize(). The third and fourth
-** arguments are a pointer to a buffer containing the token text, and the
-** size of the token in bytes. The 4th and 5th arguments are the byte offsets
-** of the first byte of and first byte immediately following the text from
-** which the token is derived within the input.
-**
-** The second argument passed to the xToken() callback ("tflags") should
-** normally be set to 0. The exception is if the tokenizer supports
-** synonyms. In this case see the discussion below for details.
-**
-** FTS5 assumes the xToken() callback is invoked for each token in the
-** order that they occur within the input text.
-**
-** If an xToken() callback returns any value other than SQLITE_OK, then
-** the tokenization should be abandoned and the xTokenize() method should
-** immediately return a copy of the xToken() return value. Or, if the
-** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally,
-** if an error occurs with the xTokenize() implementation itself, it
-** may abandon the tokenization and return any error code other than
-** SQLITE_OK or SQLITE_DONE.
-**
-** SYNONYM SUPPORT
-**
-** Custom tokenizers may also support synonyms. Consider a case in which a
-** user wishes to query for a phrase such as "first place". Using the
-** built-in tokenizers, the FTS5 query 'first + place' will match instances
-** of "first place" within the document set, but not alternative forms
-** such as "1st place". In some applications, it would be better to match
-** all instances of "first place" or "1st place" regardless of which form
-** the user specified in the MATCH query text.
-**
-** There are several ways to approach this in FTS5:
-**
-** <ol><li> By mapping all synonyms to a single token. In this case, the
-** In the above example, this means that the tokenizer returns the
-** same token for inputs "first" and "1st". Say that token is in
-** fact "first", so that when the user inserts the document "I won
-** 1st place" entries are added to the index for tokens "i", "won",
-** "first" and "place". If the user then queries for '1st + place',
-** the tokenizer substitutes "first" for "1st" and the query works
-** as expected.
-**
-** <li> By adding multiple synonyms for a single term to the FTS index.
-** In this case, when tokenizing query text, the tokenizer may
-** provide multiple synonyms for a single term within the document.
-** FTS5 then queries the index for each synonym individually. For
-** example, faced with the query:
-**
-** <codeblock>
-** ... MATCH 'first place'</codeblock>
-**
-** the tokenizer offers both "1st" and "first" as synonyms for the
-** first token in the MATCH query and FTS5 effectively runs a query
-** similar to:
-**
-** <codeblock>
-** ... MATCH '(first OR 1st) place'</codeblock>
-**
-** except that, for the purposes of auxiliary functions, the query
-** still appears to contain just two phrases - "(first OR 1st)"
-** being treated as a single phrase.
-**
-** <li> By adding multiple synonyms for a single term to the FTS index.
-** Using this method, when tokenizing document text, the tokenizer
-** provides multiple synonyms for each token. So that when a
-** document such as "I won first place" is tokenized, entries are
-** added to the FTS index for "i", "won", "first", "1st" and
-** "place".
-**
-** This way, even if the tokenizer does not provide synonyms
-** when tokenizing query text (it should not - to do would be
-** inefficient), it doesn't matter if the user queries for
-** 'first + place' or '1st + place', as there are entires in the
-** FTS index corresponding to both forms of the first token.
-** </ol>
-**
-** Whether it is parsing document or query text, any call to xToken that
-** specifies a <i>tflags</i> argument with the FTS5_TOKEN_COLOCATED bit
-** is considered to supply a synonym for the previous token. For example,
-** when parsing the document "I won first place", a tokenizer that supports
-** synonyms would call xToken() 5 times, as follows:
-**
-** <codeblock>
-** xToken(pCtx, 0, "i", 1, 0, 1);
-** xToken(pCtx, 0, "won", 3, 2, 5);
-** xToken(pCtx, 0, "first", 5, 6, 11);
-** xToken(pCtx, FTS5_TOKEN_COLOCATED, "1st", 3, 6, 11);
-** xToken(pCtx, 0, "place", 5, 12, 17);
-**</codeblock>
-**
-** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time
-** xToken() is called. Multiple synonyms may be specified for a single token
-** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence.
-** There is no limit to the number of synonyms that may be provided for a
-** single token.
-**
-** In many cases, method (1) above is the best approach. It does not add
-** extra data to the FTS index or require FTS5 to query for multiple terms,
-** so it is efficient in terms of disk space and query speed. However, it
-** does not support prefix queries very well. If, as suggested above, the
-** token "first" is subsituted for "1st" by the tokenizer, then the query:
-**
-** <codeblock>
-** ... MATCH '1s*'</codeblock>
-**
-** will not match documents that contain the token "1st" (as the tokenizer
-** will probably not map "1s" to any prefix of "first").
-**
-** For full prefix support, method (3) may be preferred. In this case,
-** because the index contains entries for both "first" and "1st", prefix
-** queries such as 'fi*' or '1s*' will match correctly. However, because
-** extra entries are added to the FTS index, this method uses more space
-** within the database.
-**
-** Method (2) offers a midpoint between (1) and (3). Using this method,
-** a query such as '1s*' will match documents that contain the literal
-** token "1st", but not "first" (assuming the tokenizer is not able to
-** provide synonyms for prefixes). However, a non-prefix query like '1st'
-** will match against "1st" and "first". This method does not require
-** extra disk space, as no extra entries are added to the FTS index.
-** On the other hand, it may require more CPU cycles to run MATCH queries,
-** as separate queries of the FTS index are required for each synonym.
-**
-** When using methods (2) or (3), it is important that the tokenizer only
-** provide synonyms when tokenizing document text (method (2)) or query
-** text (method (3)), not both. Doing so will not cause any errors, but is
-** inefficient.
-*/
-typedef struct Fts5Tokenizer Fts5Tokenizer;
-typedef struct fts5_tokenizer fts5_tokenizer;
-struct fts5_tokenizer {
- int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
- void (*xDelete)(Fts5Tokenizer*);
- int (*xTokenize)(Fts5Tokenizer*,
- void *pCtx,
- int flags, /* Mask of FTS5_TOKENIZE_* flags */
- const char *pText, int nText,
- int (*xToken)(
- void *pCtx, /* Copy of 2nd argument to xTokenize() */
- int tflags, /* Mask of FTS5_TOKEN_* flags */
- const char *pToken, /* Pointer to buffer containing token */
- int nToken, /* Size of token in bytes */
- int iStart, /* Byte offset of token within input text */
- int iEnd /* Byte offset of end of token within input text */
- )
- );
-};
-
-/* Flags that may be passed as the third argument to xTokenize() */
-#define FTS5_TOKENIZE_QUERY 0x0001
-#define FTS5_TOKENIZE_PREFIX 0x0002
-#define FTS5_TOKENIZE_DOCUMENT 0x0004
-#define FTS5_TOKENIZE_AUX 0x0008
-
-/* Flags that may be passed by the tokenizer implementation back to FTS5
-** as the third argument to the supplied xToken callback. */
-#define FTS5_TOKEN_COLOCATED 0x0001 /* Same position as prev. token */
-
-/*
-** END OF CUSTOM TOKENIZERS
-*************************************************************************/
-
-/*************************************************************************
-** FTS5 EXTENSION REGISTRATION API
-*/
-typedef struct fts5_api fts5_api;
-struct fts5_api {
- int iVersion; /* Currently always set to 2 */
-
- /* Create a new tokenizer */
- int (*xCreateTokenizer)(
- fts5_api *pApi,
- const char *zName,
- void *pContext,
- fts5_tokenizer *pTokenizer,
- void (*xDestroy)(void*)
- );
-
- /* Find an existing tokenizer */
- int (*xFindTokenizer)(
- fts5_api *pApi,
- const char *zName,
- void **ppContext,
- fts5_tokenizer *pTokenizer
- );
-
- /* Create a new auxiliary function */
- int (*xCreateFunction)(
- fts5_api *pApi,
- const char *zName,
- void *pContext,
- fts5_extension_function xFunction,
- void (*xDestroy)(void*)
- );
-};
-
-/*
-** END OF REGISTRATION API
-*************************************************************************/
-
-#if 0
-} /* end of the 'extern "C"' block */
-#endif
-
-#endif /* _FTS5_H */
-
-
-/*
-** 2014 May 31
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-*/
-#ifndef _FTS5INT_H
-#define _FTS5INT_H
-
-/* #include "fts5.h" */
-/* #include "sqlite3ext.h" */
-SQLITE_EXTENSION_INIT1
-
-/* #include <string.h> */
-/* #include <assert.h> */
-
-#ifndef SQLITE_AMALGAMATION
-
-typedef unsigned char u8;
-typedef unsigned int u32;
-typedef unsigned short u16;
-typedef short i16;
-typedef sqlite3_int64 i64;
-typedef sqlite3_uint64 u64;
-
-#define ArraySize(x) ((int)(sizeof(x) / sizeof(x[0])))
-
-#define testcase(x)
-#define ALWAYS(x) 1
-#define NEVER(x) 0
-
-#define MIN(x,y) (((x) < (y)) ? (x) : (y))
-#define MAX(x,y) (((x) > (y)) ? (x) : (y))
-
-/*
-** Constants for the largest and smallest possible 64-bit signed integers.
-*/
-# define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
-# define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
-
-#endif
-
-/* Truncate very long tokens to this many bytes. Hard limit is
-** (65536-1-1-4-9)==65521 bytes. The limiting factor is the 16-bit offset
-** field that occurs at the start of each leaf page (see fts5_index.c). */
-#define FTS5_MAX_TOKEN_SIZE 32768
-
-/*
-** Maximum number of prefix indexes on single FTS5 table. This must be
-** less than 32. If it is set to anything large than that, an #error
-** directive in fts5_index.c will cause the build to fail.
-*/
-#define FTS5_MAX_PREFIX_INDEXES 31
-
-#define FTS5_DEFAULT_NEARDIST 10
-#define FTS5_DEFAULT_RANK "bm25"
-
-/* Name of rank and rowid columns */
-#define FTS5_RANK_NAME "rank"
-#define FTS5_ROWID_NAME "rowid"
-
-#ifdef SQLITE_DEBUG
-# define FTS5_CORRUPT sqlite3Fts5Corrupt()
-static int sqlite3Fts5Corrupt(void);
-#else
-# define FTS5_CORRUPT SQLITE_CORRUPT_VTAB
-#endif
-
-/*
-** The assert_nc() macro is similar to the assert() macro, except that it
-** is used for assert() conditions that are true only if it can be
-** guranteed that the database is not corrupt.
-*/
-#ifdef SQLITE_DEBUG
-SQLITE_API extern int sqlite3_fts5_may_be_corrupt;
-# define assert_nc(x) assert(sqlite3_fts5_may_be_corrupt || (x))
-#else
-# define assert_nc(x) assert(x)
-#endif
-
-/* Mark a function parameter as unused, to suppress nuisance compiler
-** warnings. */
-#ifndef UNUSED_PARAM
-# define UNUSED_PARAM(X) (void)(X)
-#endif
-
-#ifndef UNUSED_PARAM2
-# define UNUSED_PARAM2(X, Y) (void)(X), (void)(Y)
-#endif
-
-typedef struct Fts5Global Fts5Global;
-typedef struct Fts5Colset Fts5Colset;
-
-/* If a NEAR() clump or phrase may only match a specific set of columns,
-** then an object of the following type is used to record the set of columns.
-** Each entry in the aiCol[] array is a column that may be matched.
-**
-** This object is used by fts5_expr.c and fts5_index.c.
-*/
-struct Fts5Colset {
- int nCol;
- int aiCol[1];
-};
-
-
-
-/**************************************************************************
-** Interface to code in fts5_config.c. fts5_config.c contains contains code
-** to parse the arguments passed to the CREATE VIRTUAL TABLE statement.
-*/
-
-typedef struct Fts5Config Fts5Config;
-
-/*
-** An instance of the following structure encodes all information that can
-** be gleaned from the CREATE VIRTUAL TABLE statement.
-**
-** And all information loaded from the %_config table.
-**
-** nAutomerge:
-** The minimum number of segments that an auto-merge operation should
-** attempt to merge together. A value of 1 sets the object to use the
-** compile time default. Zero disables auto-merge altogether.
-**
-** zContent:
-**
-** zContentRowid:
-** The value of the content_rowid= option, if one was specified. Or
-** the string "rowid" otherwise. This text is not quoted - if it is
-** used as part of an SQL statement it needs to be quoted appropriately.
-**
-** zContentExprlist:
-**
-** pzErrmsg:
-** This exists in order to allow the fts5_index.c module to return a
-** decent error message if it encounters a file-format version it does
-** not understand.
-**
-** bColumnsize:
-** True if the %_docsize table is created.
-**
-** bPrefixIndex:
-** This is only used for debugging. If set to false, any prefix indexes
-** are ignored. This value is configured using:
-**
-** INSERT INTO tbl(tbl, rank) VALUES('prefix-index', $bPrefixIndex);
-**
-*/
-struct Fts5Config {
- sqlite3 *db; /* Database handle */
- char *zDb; /* Database holding FTS index (e.g. "main") */
- char *zName; /* Name of FTS index */
- int nCol; /* Number of columns */
- char **azCol; /* Column names */
- u8 *abUnindexed; /* True for unindexed columns */
- int nPrefix; /* Number of prefix indexes */
- int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */
- int eContent; /* An FTS5_CONTENT value */
- char *zContent; /* content table */
- char *zContentRowid; /* "content_rowid=" option value */
- int bColumnsize; /* "columnsize=" option value (dflt==1) */
- int eDetail; /* FTS5_DETAIL_XXX value */
- char *zContentExprlist;
- Fts5Tokenizer *pTok;
- fts5_tokenizer *pTokApi;
-
- /* Values loaded from the %_config table */
- int iCookie; /* Incremented when %_config is modified */
- int pgsz; /* Approximate page size used in %_data */
- int nAutomerge; /* 'automerge' setting */
- int nCrisisMerge; /* Maximum allowed segments per level */
- int nUsermerge; /* 'usermerge' setting */
- int nHashSize; /* Bytes of memory for in-memory hash */
- char *zRank; /* Name of rank function */
- char *zRankArgs; /* Arguments to rank function */
-
- /* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */
- char **pzErrmsg;
-
-#ifdef SQLITE_DEBUG
- int bPrefixIndex; /* True to use prefix-indexes */
-#endif
-};
-
-/* Current expected value of %_config table 'version' field */
-#define FTS5_CURRENT_VERSION 4
-
-#define FTS5_CONTENT_NORMAL 0
-#define FTS5_CONTENT_NONE 1
-#define FTS5_CONTENT_EXTERNAL 2
-
-#define FTS5_DETAIL_FULL 0
-#define FTS5_DETAIL_NONE 1
-#define FTS5_DETAIL_COLUMNS 2
-
-
-
-static int sqlite3Fts5ConfigParse(
- Fts5Global*, sqlite3*, int, const char **, Fts5Config**, char**
-);
-static void sqlite3Fts5ConfigFree(Fts5Config*);
-
-static int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig);
-
-static int sqlite3Fts5Tokenize(
- Fts5Config *pConfig, /* FTS5 Configuration object */
- int flags, /* FTS5_TOKENIZE_* flags */
- const char *pText, int nText, /* Text to tokenize */
- void *pCtx, /* Context passed to xToken() */
- int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
-);
-
-static void sqlite3Fts5Dequote(char *z);
-
-/* Load the contents of the %_config table */
-static int sqlite3Fts5ConfigLoad(Fts5Config*, int);
-
-/* Set the value of a single config attribute */
-static int sqlite3Fts5ConfigSetValue(Fts5Config*, const char*, sqlite3_value*, int*);
-
-static int sqlite3Fts5ConfigParseRank(const char*, char**, char**);
-
-/*
-** End of interface to code in fts5_config.c.
-**************************************************************************/
-
-/**************************************************************************
-** Interface to code in fts5_buffer.c.
-*/
-
-/*
-** Buffer object for the incremental building of string data.
-*/
-typedef struct Fts5Buffer Fts5Buffer;
-struct Fts5Buffer {
- u8 *p;
- int n;
- int nSpace;
-};
-
-static int sqlite3Fts5BufferSize(int*, Fts5Buffer*, u32);
-static void sqlite3Fts5BufferAppendVarint(int*, Fts5Buffer*, i64);
-static void sqlite3Fts5BufferAppendBlob(int*, Fts5Buffer*, u32, const u8*);
-static void sqlite3Fts5BufferAppendString(int *, Fts5Buffer*, const char*);
-static void sqlite3Fts5BufferFree(Fts5Buffer*);
-static void sqlite3Fts5BufferZero(Fts5Buffer*);
-static void sqlite3Fts5BufferSet(int*, Fts5Buffer*, int, const u8*);
-static void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...);
-
-static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...);
-
-#define fts5BufferZero(x) sqlite3Fts5BufferZero(x)
-#define fts5BufferAppendVarint(a,b,c) sqlite3Fts5BufferAppendVarint(a,b,c)
-#define fts5BufferFree(a) sqlite3Fts5BufferFree(a)
-#define fts5BufferAppendBlob(a,b,c,d) sqlite3Fts5BufferAppendBlob(a,b,c,d)
-#define fts5BufferSet(a,b,c,d) sqlite3Fts5BufferSet(a,b,c,d)
-
-#define fts5BufferGrow(pRc,pBuf,nn) ( \
- (u32)((pBuf)->n) + (u32)(nn) <= (u32)((pBuf)->nSpace) ? 0 : \
- sqlite3Fts5BufferSize((pRc),(pBuf),(nn)+(pBuf)->n) \
-)
-
-/* Write and decode big-endian 32-bit integer values */
-static void sqlite3Fts5Put32(u8*, int);
-static int sqlite3Fts5Get32(const u8*);
-
-#define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32)
-#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0xFFFFFFFF)
-
-typedef struct Fts5PoslistReader Fts5PoslistReader;
-struct Fts5PoslistReader {
- /* Variables used only by sqlite3Fts5PoslistIterXXX() functions. */
- const u8 *a; /* Position list to iterate through */
- int n; /* Size of buffer at a[] in bytes */
- int i; /* Current offset in a[] */
-
- u8 bFlag; /* For client use (any custom purpose) */
-
- /* Output variables */
- u8 bEof; /* Set to true at EOF */
- i64 iPos; /* (iCol<<32) + iPos */
-};
-static int sqlite3Fts5PoslistReaderInit(
- const u8 *a, int n, /* Poslist buffer to iterate through */
- Fts5PoslistReader *pIter /* Iterator object to initialize */
-);
-static int sqlite3Fts5PoslistReaderNext(Fts5PoslistReader*);
-
-typedef struct Fts5PoslistWriter Fts5PoslistWriter;
-struct Fts5PoslistWriter {
- i64 iPrev;
-};
-static int sqlite3Fts5PoslistWriterAppend(Fts5Buffer*, Fts5PoslistWriter*, i64);
-static void sqlite3Fts5PoslistSafeAppend(Fts5Buffer*, i64*, i64);
-
-static int sqlite3Fts5PoslistNext64(
- const u8 *a, int n, /* Buffer containing poslist */
- int *pi, /* IN/OUT: Offset within a[] */
- i64 *piOff /* IN/OUT: Current offset */
-);
-
-/* Malloc utility */
-static void *sqlite3Fts5MallocZero(int *pRc, int nByte);
-static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn);
-
-/* Character set tests (like isspace(), isalpha() etc.) */
-static int sqlite3Fts5IsBareword(char t);
-
-
-/* Bucket of terms object used by the integrity-check in offsets=0 mode. */
-typedef struct Fts5Termset Fts5Termset;
-static int sqlite3Fts5TermsetNew(Fts5Termset**);
-static int sqlite3Fts5TermsetAdd(Fts5Termset*, int, const char*, int, int *pbPresent);
-static void sqlite3Fts5TermsetFree(Fts5Termset*);
-
-/*
-** End of interface to code in fts5_buffer.c.
-**************************************************************************/
-
-/**************************************************************************
-** Interface to code in fts5_index.c. fts5_index.c contains contains code
-** to access the data stored in the %_data table.
-*/
-
-typedef struct Fts5Index Fts5Index;
-typedef struct Fts5IndexIter Fts5IndexIter;
-
-struct Fts5IndexIter {
- i64 iRowid;
- const u8 *pData;
- int nData;
- u8 bEof;
-};
-
-#define sqlite3Fts5IterEof(x) ((x)->bEof)
-
-/*
-** Values used as part of the flags argument passed to IndexQuery().
-*/
-#define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */
-#define FTS5INDEX_QUERY_DESC 0x0002 /* Docs in descending rowid order */
-#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004 /* Do not use prefix index */
-#define FTS5INDEX_QUERY_SCAN 0x0008 /* Scan query (fts5vocab) */
-
-/* The following are used internally by the fts5_index.c module. They are
-** defined here only to make it easier to avoid clashes with the flags
-** above. */
-#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010
-#define FTS5INDEX_QUERY_NOOUTPUT 0x0020
-
-/*
-** Create/destroy an Fts5Index object.
-*/
-static int sqlite3Fts5IndexOpen(Fts5Config *pConfig, int bCreate, Fts5Index**, char**);
-static int sqlite3Fts5IndexClose(Fts5Index *p);
-
-/*
-** Return a simple checksum value based on the arguments.
-*/
-static u64 sqlite3Fts5IndexEntryCksum(
- i64 iRowid,
- int iCol,
- int iPos,
- int iIdx,
- const char *pTerm,
- int nTerm
-);
-
-/*
-** Argument p points to a buffer containing utf-8 text that is n bytes in
-** size. Return the number of bytes in the nChar character prefix of the
-** buffer, or 0 if there are less than nChar characters in total.
-*/
-static int sqlite3Fts5IndexCharlenToBytelen(
- const char *p,
- int nByte,
- int nChar
-);
-
-/*
-** Open a new iterator to iterate though all rowids that match the
-** specified token or token prefix.
-*/
-static int sqlite3Fts5IndexQuery(
- Fts5Index *p, /* FTS index to query */
- const char *pToken, int nToken, /* Token (or prefix) to query for */
- int flags, /* Mask of FTS5INDEX_QUERY_X flags */
- Fts5Colset *pColset, /* Match these columns only */
- Fts5IndexIter **ppIter /* OUT: New iterator object */
-);
-
-/*
-** The various operations on open token or token prefix iterators opened
-** using sqlite3Fts5IndexQuery().
-*/
-static int sqlite3Fts5IterNext(Fts5IndexIter*);
-static int sqlite3Fts5IterNextFrom(Fts5IndexIter*, i64 iMatch);
-
-/*
-** Close an iterator opened by sqlite3Fts5IndexQuery().
-*/
-static void sqlite3Fts5IterClose(Fts5IndexIter*);
-
-/*
-** This interface is used by the fts5vocab module.
-*/
-static const char *sqlite3Fts5IterTerm(Fts5IndexIter*, int*);
-static int sqlite3Fts5IterNextScan(Fts5IndexIter*);
-
-
-/*
-** Insert or remove data to or from the index. Each time a document is
-** added to or removed from the index, this function is called one or more
-** times.
-**
-** For an insert, it must be called once for each token in the new document.
-** If the operation is a delete, it must be called (at least) once for each
-** unique token in the document with an iCol value less than zero. The iPos
-** argument is ignored for a delete.
-*/
-static int sqlite3Fts5IndexWrite(
- Fts5Index *p, /* Index to write to */
- int iCol, /* Column token appears in (-ve -> delete) */
- int iPos, /* Position of token within column */
- const char *pToken, int nToken /* Token to add or remove to or from index */
-);
-
-/*
-** Indicate that subsequent calls to sqlite3Fts5IndexWrite() pertain to
-** document iDocid.
-*/
-static int sqlite3Fts5IndexBeginWrite(
- Fts5Index *p, /* Index to write to */
- int bDelete, /* True if current operation is a delete */
- i64 iDocid /* Docid to add or remove data from */
-);
-
-/*
-** Flush any data stored in the in-memory hash tables to the database.
-** If the bCommit flag is true, also close any open blob handles.
-*/
-static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit);
-
-/*
-** Discard any data stored in the in-memory hash tables. Do not write it
-** to the database. Additionally, assume that the contents of the %_data
-** table may have changed on disk. So any in-memory caches of %_data
-** records must be invalidated.
-*/
-static int sqlite3Fts5IndexRollback(Fts5Index *p);
-
-/*
-** Get or set the "averages" values.
-*/
-static int sqlite3Fts5IndexGetAverages(Fts5Index *p, i64 *pnRow, i64 *anSize);
-static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int);
-
-/*
-** Functions called by the storage module as part of integrity-check.
-*/
-static int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum);
-
-/*
-** Called during virtual module initialization to register UDF
-** fts5_decode() with SQLite
-*/
-static int sqlite3Fts5IndexInit(sqlite3*);
-
-static int sqlite3Fts5IndexSetCookie(Fts5Index*, int);
-
-/*
-** Return the total number of entries read from the %_data table by
-** this connection since it was created.
-*/
-static int sqlite3Fts5IndexReads(Fts5Index *p);
-
-static int sqlite3Fts5IndexReinit(Fts5Index *p);
-static int sqlite3Fts5IndexOptimize(Fts5Index *p);
-static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge);
-static int sqlite3Fts5IndexReset(Fts5Index *p);
-
-static int sqlite3Fts5IndexLoadConfig(Fts5Index *p);
-
-/*
-** End of interface to code in fts5_index.c.
-**************************************************************************/
-
-/**************************************************************************
-** Interface to code in fts5_varint.c.
-*/
-static int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v);
-static int sqlite3Fts5GetVarintLen(u32 iVal);
-static u8 sqlite3Fts5GetVarint(const unsigned char*, u64*);
-static int sqlite3Fts5PutVarint(unsigned char *p, u64 v);
-
-#define fts5GetVarint32(a,b) sqlite3Fts5GetVarint32(a,(u32*)&b)
-#define fts5GetVarint sqlite3Fts5GetVarint
-
-#define fts5FastGetVarint32(a, iOff, nVal) { \
- nVal = (a)[iOff++]; \
- if( nVal & 0x80 ){ \
- iOff--; \
- iOff += fts5GetVarint32(&(a)[iOff], nVal); \
- } \
-}
-
-
-/*
-** End of interface to code in fts5_varint.c.
-**************************************************************************/
-
-
-/**************************************************************************
-** Interface to code in fts5.c.
-*/
-
-static int sqlite3Fts5GetTokenizer(
- Fts5Global*,
- const char **azArg,
- int nArg,
- Fts5Tokenizer**,
- fts5_tokenizer**,
- char **pzErr
-);
-
-static Fts5Index *sqlite3Fts5IndexFromCsrid(Fts5Global*, i64, Fts5Config **);
-
-/*
-** End of interface to code in fts5.c.
-**************************************************************************/
-
-/**************************************************************************
-** Interface to code in fts5_hash.c.
-*/
-typedef struct Fts5Hash Fts5Hash;
-
-/*
-** Create a hash table, free a hash table.
-*/
-static int sqlite3Fts5HashNew(Fts5Config*, Fts5Hash**, int *pnSize);
-static void sqlite3Fts5HashFree(Fts5Hash*);
-
-static int sqlite3Fts5HashWrite(
- Fts5Hash*,
- i64 iRowid, /* Rowid for this entry */
- int iCol, /* Column token appears in (-ve -> delete) */
- int iPos, /* Position of token within column */
- char bByte,
- const char *pToken, int nToken /* Token to add or remove to or from index */
-);
-
-/*
-** Empty (but do not delete) a hash table.
-*/
-static void sqlite3Fts5HashClear(Fts5Hash*);
-
-static int sqlite3Fts5HashQuery(
- Fts5Hash*, /* Hash table to query */
- const char *pTerm, int nTerm, /* Query term */
- const u8 **ppDoclist, /* OUT: Pointer to doclist for pTerm */
- int *pnDoclist /* OUT: Size of doclist in bytes */
-);
-
-static int sqlite3Fts5HashScanInit(
- Fts5Hash*, /* Hash table to query */
- const char *pTerm, int nTerm /* Query prefix */
-);
-static void sqlite3Fts5HashScanNext(Fts5Hash*);
-static int sqlite3Fts5HashScanEof(Fts5Hash*);
-static void sqlite3Fts5HashScanEntry(Fts5Hash *,
- const char **pzTerm, /* OUT: term (nul-terminated) */
- const u8 **ppDoclist, /* OUT: pointer to doclist */
- int *pnDoclist /* OUT: size of doclist in bytes */
-);
-
-
-/*
-** End of interface to code in fts5_hash.c.
-**************************************************************************/
-
-/**************************************************************************
-** Interface to code in fts5_storage.c. fts5_storage.c contains contains
-** code to access the data stored in the %_content and %_docsize tables.
-*/
-
-#define FTS5_STMT_SCAN_ASC 0 /* SELECT rowid, * FROM ... ORDER BY 1 ASC */
-#define FTS5_STMT_SCAN_DESC 1 /* SELECT rowid, * FROM ... ORDER BY 1 DESC */
-#define FTS5_STMT_LOOKUP 2 /* SELECT rowid, * FROM ... WHERE rowid=? */
-
-typedef struct Fts5Storage Fts5Storage;
-
-static int sqlite3Fts5StorageOpen(Fts5Config*, Fts5Index*, int, Fts5Storage**, char**);
-static int sqlite3Fts5StorageClose(Fts5Storage *p);
-static int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName);
-
-static int sqlite3Fts5DropAll(Fts5Config*);
-static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **);
-
-static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**);
-static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
-static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
-
-static int sqlite3Fts5StorageIntegrity(Fts5Storage *p);
-
-static int sqlite3Fts5StorageStmt(Fts5Storage *p, int eStmt, sqlite3_stmt**, char**);
-static void sqlite3Fts5StorageStmtRelease(Fts5Storage *p, int eStmt, sqlite3_stmt*);
-
-static int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol);
-static int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnAvg);
-static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow);
-
-static int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit);
-static int sqlite3Fts5StorageRollback(Fts5Storage *p);
-
-static int sqlite3Fts5StorageConfigValue(
- Fts5Storage *p, const char*, sqlite3_value*, int
-);
-
-static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p);
-static int sqlite3Fts5StorageRebuild(Fts5Storage *p);
-static int sqlite3Fts5StorageOptimize(Fts5Storage *p);
-static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge);
-static int sqlite3Fts5StorageReset(Fts5Storage *p);
-
-/*
-** End of interface to code in fts5_storage.c.
-**************************************************************************/
-
-
-/**************************************************************************
-** Interface to code in fts5_expr.c.
-*/
-typedef struct Fts5Expr Fts5Expr;
-typedef struct Fts5ExprNode Fts5ExprNode;
-typedef struct Fts5Parse Fts5Parse;
-typedef struct Fts5Token Fts5Token;
-typedef struct Fts5ExprPhrase Fts5ExprPhrase;
-typedef struct Fts5ExprNearset Fts5ExprNearset;
-
-struct Fts5Token {
- const char *p; /* Token text (not NULL terminated) */
- int n; /* Size of buffer p in bytes */
-};
-
-/* Parse a MATCH expression. */
-static int sqlite3Fts5ExprNew(
- Fts5Config *pConfig,
- const char *zExpr,
- Fts5Expr **ppNew,
- char **pzErr
-);
-
-/*
-** for(rc = sqlite3Fts5ExprFirst(pExpr, pIdx, bDesc);
-** rc==SQLITE_OK && 0==sqlite3Fts5ExprEof(pExpr);
-** rc = sqlite3Fts5ExprNext(pExpr)
-** ){
-** // The document with rowid iRowid matches the expression!
-** i64 iRowid = sqlite3Fts5ExprRowid(pExpr);
-** }
-*/
-static int sqlite3Fts5ExprFirst(Fts5Expr*, Fts5Index *pIdx, i64 iMin, int bDesc);
-static int sqlite3Fts5ExprNext(Fts5Expr*, i64 iMax);
-static int sqlite3Fts5ExprEof(Fts5Expr*);
-static i64 sqlite3Fts5ExprRowid(Fts5Expr*);
-
-static void sqlite3Fts5ExprFree(Fts5Expr*);
-
-/* Called during startup to register a UDF with SQLite */
-static int sqlite3Fts5ExprInit(Fts5Global*, sqlite3*);
-
-static int sqlite3Fts5ExprPhraseCount(Fts5Expr*);
-static int sqlite3Fts5ExprPhraseSize(Fts5Expr*, int iPhrase);
-static int sqlite3Fts5ExprPoslist(Fts5Expr*, int, const u8 **);
-
-typedef struct Fts5PoslistPopulator Fts5PoslistPopulator;
-static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr*, int);
-static int sqlite3Fts5ExprPopulatePoslists(
- Fts5Config*, Fts5Expr*, Fts5PoslistPopulator*, int, const char*, int
-);
-static void sqlite3Fts5ExprCheckPoslists(Fts5Expr*, i64);
-static void sqlite3Fts5ExprClearEof(Fts5Expr*);
-
-static int sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**);
-
-static int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *);
-
-/*******************************************
-** The fts5_expr.c API above this point is used by the other hand-written
-** C code in this module. The interfaces below this point are called by
-** the parser code in fts5parse.y. */
-
-static void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...);
-
-static Fts5ExprNode *sqlite3Fts5ParseNode(
- Fts5Parse *pParse,
- int eType,
- Fts5ExprNode *pLeft,
- Fts5ExprNode *pRight,
- Fts5ExprNearset *pNear
-);
-
-static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
- Fts5Parse *pParse,
- Fts5ExprNode *pLeft,
- Fts5ExprNode *pRight
-);
-
-static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
- Fts5Parse *pParse,
- Fts5ExprPhrase *pPhrase,
- Fts5Token *pToken,
- int bPrefix
-);
-
-static Fts5ExprNearset *sqlite3Fts5ParseNearset(
- Fts5Parse*,
- Fts5ExprNearset*,
- Fts5ExprPhrase*
-);
-
-static Fts5Colset *sqlite3Fts5ParseColset(
- Fts5Parse*,
- Fts5Colset*,
- Fts5Token *
-);
-
-static void sqlite3Fts5ParsePhraseFree(Fts5ExprPhrase*);
-static void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset*);
-static void sqlite3Fts5ParseNodeFree(Fts5ExprNode*);
-
-static void sqlite3Fts5ParseSetDistance(Fts5Parse*, Fts5ExprNearset*, Fts5Token*);
-static void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5Colset*);
-static void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p);
-static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*);
-
-/*
-** End of interface to code in fts5_expr.c.
-**************************************************************************/
-
-
-
-/**************************************************************************
-** Interface to code in fts5_aux.c.
-*/
-
-static int sqlite3Fts5AuxInit(fts5_api*);
-/*
-** End of interface to code in fts5_aux.c.
-**************************************************************************/
-
-/**************************************************************************
-** Interface to code in fts5_tokenizer.c.
-*/
-
-static int sqlite3Fts5TokenizerInit(fts5_api*);
-/*
-** End of interface to code in fts5_tokenizer.c.
-**************************************************************************/
-
-/**************************************************************************
-** Interface to code in fts5_vocab.c.
-*/
-
-static int sqlite3Fts5VocabInit(Fts5Global*, sqlite3*);
-
-/*
-** End of interface to code in fts5_vocab.c.
-**************************************************************************/
-
-
-/**************************************************************************
-** Interface to automatically generated code in fts5_unicode2.c.
-*/
-static int sqlite3Fts5UnicodeIsalnum(int c);
-static int sqlite3Fts5UnicodeIsdiacritic(int c);
-static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
-/*
-** End of interface to code in fts5_unicode2.c.
-**************************************************************************/
-
-#endif
-
-#define FTS5_OR 1
-#define FTS5_AND 2
-#define FTS5_NOT 3
-#define FTS5_TERM 4
-#define FTS5_COLON 5
-#define FTS5_LP 6
-#define FTS5_RP 7
-#define FTS5_LCP 8
-#define FTS5_RCP 9
-#define FTS5_STRING 10
-#define FTS5_COMMA 11
-#define FTS5_PLUS 12
-#define FTS5_STAR 13
-
-/*
-** 2000-05-29
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** Driver template for the LEMON parser generator.
-**
-** The "lemon" program processes an LALR(1) input grammar file, then uses
-** this template to construct a parser. The "lemon" program inserts text
-** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the
-** interstitial "-" characters) contained in this template is changed into
-** the value of the %name directive from the grammar. Otherwise, the content
-** of this template is copied straight through into the generate parser
-** source file.
-**
-** The following is the concatenation of all %include directives from the
-** input grammar file:
-*/
-/* #include <stdio.h> */
-/************ Begin %include sections from the grammar ************************/
-
-/* #include "fts5Int.h" */
-/* #include "fts5parse.h" */
-
-/*
-** Disable all error recovery processing in the parser push-down
-** automaton.
-*/
-#define fts5YYNOERRORRECOVERY 1
-
-/*
-** Make fts5yytestcase() the same as testcase()
-*/
-#define fts5yytestcase(X) testcase(X)
-
-/*
-** Indicate that sqlite3ParserFree() will never be called with a null
-** pointer.
-*/
-#define fts5YYPARSEFREENOTNULL 1
-
-/*
-** Alternative datatype for the argument to the malloc() routine passed
-** into sqlite3ParserAlloc(). The default is size_t.
-*/
-#define fts5YYMALLOCARGTYPE u64
-
-/**************** End of %include directives **********************************/
-/* These constants specify the various numeric values for terminal symbols
-** in a format understandable to "makeheaders". This section is blank unless
-** "lemon" is run with the "-m" command-line option.
-***************** Begin makeheaders token definitions *************************/
-/**************** End makeheaders token definitions ***************************/
-
-/* The next sections is a series of control #defines.
-** various aspects of the generated parser.
-** fts5YYCODETYPE is the data type used to store the integer codes
-** that represent terminal and non-terminal symbols.
-** "unsigned char" is used if there are fewer than
-** 256 symbols. Larger types otherwise.
-** fts5YYNOCODE is a number of type fts5YYCODETYPE that is not used for
-** any terminal or nonterminal symbol.
-** fts5YYFALLBACK If defined, this indicates that one or more tokens
-** (also known as: "terminal symbols") have fall-back
-** values which should be used if the original symbol
-** would not parse. This permits keywords to sometimes
-** be used as identifiers, for example.
-** fts5YYACTIONTYPE is the data type used for "action codes" - numbers
-** that indicate what to do in response to the next
-** token.
-** sqlite3Fts5ParserFTS5TOKENTYPE is the data type used for minor type for terminal
-** symbols. Background: A "minor type" is a semantic
-** value associated with a terminal or non-terminal
-** symbols. For example, for an "ID" terminal symbol,
-** the minor type might be the name of the identifier.
-** Each non-terminal can have a different minor type.
-** Terminal symbols all have the same minor type, though.
-** This macros defines the minor type for terminal
-** symbols.
-** fts5YYMINORTYPE is the data type used for all minor types.
-** This is typically a union of many types, one of
-** which is sqlite3Fts5ParserFTS5TOKENTYPE. The entry in the union
-** for terminal symbols is called "fts5yy0".
-** fts5YYSTACKDEPTH is the maximum depth of the parser's stack. If
-** zero the stack is dynamically sized using realloc()
-** sqlite3Fts5ParserARG_SDECL A static variable declaration for the %extra_argument
-** sqlite3Fts5ParserARG_PDECL A parameter declaration for the %extra_argument
-** sqlite3Fts5ParserARG_STORE Code to store %extra_argument into fts5yypParser
-** sqlite3Fts5ParserARG_FETCH Code to extract %extra_argument from fts5yypParser
-** fts5YYERRORSYMBOL is the code number of the error symbol. If not
-** defined, then do no error processing.
-** fts5YYNSTATE the combined number of states.
-** fts5YYNRULE the number of rules in the grammar
-** fts5YY_MAX_SHIFT Maximum value for shift actions
-** fts5YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
-** fts5YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
-** fts5YY_MIN_REDUCE Maximum value for reduce actions
-** fts5YY_ERROR_ACTION The fts5yy_action[] code for syntax error
-** fts5YY_ACCEPT_ACTION The fts5yy_action[] code for accept
-** fts5YY_NO_ACTION The fts5yy_action[] code for no-op
-*/
-#ifndef INTERFACE
-# define INTERFACE 1
-#endif
-/************* Begin control #defines *****************************************/
-#define fts5YYCODETYPE unsigned char
-#define fts5YYNOCODE 27
-#define fts5YYACTIONTYPE unsigned char
-#define sqlite3Fts5ParserFTS5TOKENTYPE Fts5Token
-typedef union {
- int fts5yyinit;
- sqlite3Fts5ParserFTS5TOKENTYPE fts5yy0;
- Fts5Colset* fts5yy3;
- Fts5ExprPhrase* fts5yy11;
- Fts5ExprNode* fts5yy18;
- int fts5yy20;
- Fts5ExprNearset* fts5yy26;
-} fts5YYMINORTYPE;
-#ifndef fts5YYSTACKDEPTH
-#define fts5YYSTACKDEPTH 100
-#endif
-#define sqlite3Fts5ParserARG_SDECL Fts5Parse *pParse;
-#define sqlite3Fts5ParserARG_PDECL ,Fts5Parse *pParse
-#define sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse = fts5yypParser->pParse
-#define sqlite3Fts5ParserARG_STORE fts5yypParser->pParse = pParse
-#define fts5YYNSTATE 26
-#define fts5YYNRULE 24
-#define fts5YY_MAX_SHIFT 25
-#define fts5YY_MIN_SHIFTREDUCE 40
-#define fts5YY_MAX_SHIFTREDUCE 63
-#define fts5YY_MIN_REDUCE 64
-#define fts5YY_MAX_REDUCE 87
-#define fts5YY_ERROR_ACTION 88
-#define fts5YY_ACCEPT_ACTION 89
-#define fts5YY_NO_ACTION 90
-/************* End control #defines *******************************************/
-
-/* Define the fts5yytestcase() macro to be a no-op if is not already defined
-** otherwise.
-**
-** Applications can choose to define fts5yytestcase() in the %include section
-** to a macro that can assist in verifying code coverage. For production
-** code the fts5yytestcase() macro should be turned off. But it is useful
-** for testing.
-*/
-#ifndef fts5yytestcase
-# define fts5yytestcase(X)
-#endif
-
-
-/* Next are the tables used to determine what action to take based on the
-** current state and lookahead token. These tables are used to implement
-** functions that take a state number and lookahead value and return an
-** action integer.
-**
-** Suppose the action integer is N. Then the action is determined as
-** follows
-**
-** 0 <= N <= fts5YY_MAX_SHIFT Shift N. That is, push the lookahead
-** token onto the stack and goto state N.
-**
-** N between fts5YY_MIN_SHIFTREDUCE Shift to an arbitrary state then
-** and fts5YY_MAX_SHIFTREDUCE reduce by rule N-fts5YY_MIN_SHIFTREDUCE.
-**
-** N between fts5YY_MIN_REDUCE Reduce by rule N-fts5YY_MIN_REDUCE
-** and fts5YY_MAX_REDUCE
-
-** N == fts5YY_ERROR_ACTION A syntax error has occurred.
-**
-** N == fts5YY_ACCEPT_ACTION The parser accepts its input.
-**
-** N == fts5YY_NO_ACTION No such action. Denotes unused
-** slots in the fts5yy_action[] table.
-**
-** The action table is constructed as a single large table named fts5yy_action[].
-** Given state S and lookahead X, the action is computed as
-**
-** fts5yy_action[ fts5yy_shift_ofst[S] + X ]
-**
-** If the index value fts5yy_shift_ofst[S]+X is out of range or if the value
-** fts5yy_lookahead[fts5yy_shift_ofst[S]+X] is not equal to X or if fts5yy_shift_ofst[S]
-** is equal to fts5YY_SHIFT_USE_DFLT, it means that the action is not in the table
-** and that fts5yy_default[S] should be used instead.
-**
-** The formula above is for computing the action when the lookahead is
-** a terminal symbol. If the lookahead is a non-terminal (as occurs after
-** a reduce action) then the fts5yy_reduce_ofst[] array is used in place of
-** the fts5yy_shift_ofst[] array and fts5YY_REDUCE_USE_DFLT is used in place of
-** fts5YY_SHIFT_USE_DFLT.
-**
-** The following are the tables generated in this section:
-**
-** fts5yy_action[] A single table containing all actions.
-** fts5yy_lookahead[] A table containing the lookahead for each entry in
-** fts5yy_action. Used to detect hash collisions.
-** fts5yy_shift_ofst[] For each state, the offset into fts5yy_action for
-** shifting terminals.
-** fts5yy_reduce_ofst[] For each state, the offset into fts5yy_action for
-** shifting non-terminals after a reduce.
-** fts5yy_default[] Default action for each state.
-**
-*********** Begin parsing tables **********************************************/
-#define fts5YY_ACTTAB_COUNT (78)
-static const fts5YYACTIONTYPE fts5yy_action[] = {
- /* 0 */ 89, 15, 46, 5, 48, 24, 12, 19, 23, 14,
- /* 10 */ 46, 5, 48, 24, 20, 21, 23, 43, 46, 5,
- /* 20 */ 48, 24, 6, 18, 23, 17, 46, 5, 48, 24,
- /* 30 */ 75, 7, 23, 25, 46, 5, 48, 24, 62, 47,
- /* 40 */ 23, 48, 24, 7, 11, 23, 9, 3, 4, 2,
- /* 50 */ 62, 50, 52, 44, 64, 3, 4, 2, 49, 4,
- /* 60 */ 2, 1, 23, 11, 16, 9, 12, 2, 10, 61,
- /* 70 */ 53, 59, 62, 60, 22, 13, 55, 8,
-};
-static const fts5YYCODETYPE fts5yy_lookahead[] = {
- /* 0 */ 15, 16, 17, 18, 19, 20, 10, 11, 23, 16,
- /* 10 */ 17, 18, 19, 20, 23, 24, 23, 16, 17, 18,
- /* 20 */ 19, 20, 22, 23, 23, 16, 17, 18, 19, 20,
- /* 30 */ 5, 6, 23, 16, 17, 18, 19, 20, 13, 17,
- /* 40 */ 23, 19, 20, 6, 8, 23, 10, 1, 2, 3,
- /* 50 */ 13, 9, 10, 7, 0, 1, 2, 3, 19, 2,
- /* 60 */ 3, 6, 23, 8, 21, 10, 10, 3, 10, 25,
- /* 70 */ 10, 10, 13, 25, 12, 10, 7, 5,
-};
-#define fts5YY_SHIFT_USE_DFLT (-5)
-#define fts5YY_SHIFT_COUNT (25)
-#define fts5YY_SHIFT_MIN (-4)
-#define fts5YY_SHIFT_MAX (72)
-static const signed char fts5yy_shift_ofst[] = {
- /* 0 */ 55, 55, 55, 55, 55, 36, -4, 56, 58, 25,
- /* 10 */ 37, 60, 59, 59, 46, 54, 42, 57, 62, 61,
- /* 20 */ 62, 69, 65, 62, 72, 64,
-};
-#define fts5YY_REDUCE_USE_DFLT (-16)
-#define fts5YY_REDUCE_COUNT (13)
-#define fts5YY_REDUCE_MIN (-15)
-#define fts5YY_REDUCE_MAX (48)
-static const signed char fts5yy_reduce_ofst[] = {
- /* 0 */ -15, -7, 1, 9, 17, 22, -9, 0, 39, 44,
- /* 10 */ 44, 43, 44, 48,
-};
-static const fts5YYACTIONTYPE fts5yy_default[] = {
- /* 0 */ 88, 88, 88, 88, 88, 69, 82, 88, 88, 87,
- /* 10 */ 87, 88, 87, 87, 88, 88, 88, 66, 80, 88,
- /* 20 */ 81, 88, 88, 78, 88, 65,
-};
-/********** End of lemon-generated parsing tables *****************************/
-
-/* The next table maps tokens (terminal symbols) into fallback tokens.
-** If a construct like the following:
-**
-** %fallback ID X Y Z.
-**
-** appears in the grammar, then ID becomes a fallback token for X, Y,
-** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
-** but it does not parse, the type of the token is changed to ID and
-** the parse is retried before an error is thrown.
-**
-** This feature can be used, for example, to cause some keywords in a language
-** to revert to identifiers if they keyword does not apply in the context where
-** it appears.
-*/
-#ifdef fts5YYFALLBACK
-static const fts5YYCODETYPE fts5yyFallback[] = {
-};
-#endif /* fts5YYFALLBACK */
-
-/* The following structure represents a single element of the
-** parser's stack. Information stored includes:
-**
-** + The state number for the parser at this level of the stack.
-**
-** + The value of the token stored at this level of the stack.
-** (In other words, the "major" token.)
-**
-** + The semantic value stored at this level of the stack. This is
-** the information used by the action routines in the grammar.
-** It is sometimes called the "minor" token.
-**
-** After the "shift" half of a SHIFTREDUCE action, the stateno field
-** actually contains the reduce action for the second half of the
-** SHIFTREDUCE.
-*/
-struct fts5yyStackEntry {
- fts5YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */
- fts5YYCODETYPE major; /* The major token value. This is the code
- ** number for the token at this stack level */
- fts5YYMINORTYPE minor; /* The user-supplied minor token value. This
- ** is the value of the token */
-};
-typedef struct fts5yyStackEntry fts5yyStackEntry;
-
-/* The state of the parser is completely contained in an instance of
-** the following structure */
-struct fts5yyParser {
- int fts5yyidx; /* Index of top element in stack */
-#ifdef fts5YYTRACKMAXSTACKDEPTH
- int fts5yyidxMax; /* Maximum value of fts5yyidx */
-#endif
-#ifndef fts5YYNOERRORRECOVERY
- int fts5yyerrcnt; /* Shifts left before out of the error */
-#endif
- sqlite3Fts5ParserARG_SDECL /* A place to hold %extra_argument */
-#if fts5YYSTACKDEPTH<=0
- int fts5yystksz; /* Current side of the stack */
- fts5yyStackEntry *fts5yystack; /* The parser's stack */
-#else
- fts5yyStackEntry fts5yystack[fts5YYSTACKDEPTH]; /* The parser's stack */
-#endif
-};
-typedef struct fts5yyParser fts5yyParser;
-
-#ifndef NDEBUG
-/* #include <stdio.h> */
-static FILE *fts5yyTraceFILE = 0;
-static char *fts5yyTracePrompt = 0;
-#endif /* NDEBUG */
-
-#ifndef NDEBUG
-/*
-** Turn parser tracing on by giving a stream to which to write the trace
-** and a prompt to preface each trace message. Tracing is turned off
-** by making either argument NULL
-**
-** Inputs:
-** <ul>
-** <li> A FILE* to which trace output should be written.
-** If NULL, then tracing is turned off.
-** <li> A prefix string written at the beginning of every
-** line of trace output. If NULL, then tracing is
-** turned off.
-** </ul>
-**
-** Outputs:
-** None.
-*/
-static void sqlite3Fts5ParserTrace(FILE *TraceFILE, char *zTracePrompt){
- fts5yyTraceFILE = TraceFILE;
- fts5yyTracePrompt = zTracePrompt;
- if( fts5yyTraceFILE==0 ) fts5yyTracePrompt = 0;
- else if( fts5yyTracePrompt==0 ) fts5yyTraceFILE = 0;
-}
-#endif /* NDEBUG */
-
-#ifndef NDEBUG
-/* For tracing shifts, the names of all terminals and nonterminals
-** are required. The following table supplies these names */
-static const char *const fts5yyTokenName[] = {
- "$", "OR", "AND", "NOT",
- "TERM", "COLON", "LP", "RP",
- "LCP", "RCP", "STRING", "COMMA",
- "PLUS", "STAR", "error", "input",
- "expr", "cnearset", "exprlist", "nearset",
- "colset", "colsetlist", "nearphrases", "phrase",
- "neardist_opt", "star_opt",
-};
-#endif /* NDEBUG */
-
-#ifndef NDEBUG
-/* For tracing reduce actions, the names of all rules are required.
-*/
-static const char *const fts5yyRuleName[] = {
- /* 0 */ "input ::= expr",
- /* 1 */ "expr ::= expr AND expr",
- /* 2 */ "expr ::= expr OR expr",
- /* 3 */ "expr ::= expr NOT expr",
- /* 4 */ "expr ::= LP expr RP",
- /* 5 */ "expr ::= exprlist",
- /* 6 */ "exprlist ::= cnearset",
- /* 7 */ "exprlist ::= exprlist cnearset",
- /* 8 */ "cnearset ::= nearset",
- /* 9 */ "cnearset ::= colset COLON nearset",
- /* 10 */ "colset ::= LCP colsetlist RCP",
- /* 11 */ "colset ::= STRING",
- /* 12 */ "colsetlist ::= colsetlist STRING",
- /* 13 */ "colsetlist ::= STRING",
- /* 14 */ "nearset ::= phrase",
- /* 15 */ "nearset ::= STRING LP nearphrases neardist_opt RP",
- /* 16 */ "nearphrases ::= phrase",
- /* 17 */ "nearphrases ::= nearphrases phrase",
- /* 18 */ "neardist_opt ::=",
- /* 19 */ "neardist_opt ::= COMMA STRING",
- /* 20 */ "phrase ::= phrase PLUS STRING star_opt",
- /* 21 */ "phrase ::= STRING star_opt",
- /* 22 */ "star_opt ::= STAR",
- /* 23 */ "star_opt ::=",
-};
-#endif /* NDEBUG */
-
-
-#if fts5YYSTACKDEPTH<=0
-/*
-** Try to increase the size of the parser stack.
-*/
-static void fts5yyGrowStack(fts5yyParser *p){
- int newSize;
- fts5yyStackEntry *pNew;
-
- newSize = p->fts5yystksz*2 + 100;
- pNew = realloc(p->fts5yystack, newSize*sizeof(pNew[0]));
- if( pNew ){
- p->fts5yystack = pNew;
- p->fts5yystksz = newSize;
-#ifndef NDEBUG
- if( fts5yyTraceFILE ){
- fprintf(fts5yyTraceFILE,"%sStack grows to %d entries!\n",
- fts5yyTracePrompt, p->fts5yystksz);
- }
-#endif
- }
-}
-#endif
-
-/* Datatype of the argument to the memory allocated passed as the
-** second argument to sqlite3Fts5ParserAlloc() below. This can be changed by
-** putting an appropriate #define in the %include section of the input
-** grammar.
-*/
-#ifndef fts5YYMALLOCARGTYPE
-# define fts5YYMALLOCARGTYPE size_t
-#endif
-
-/*
-** This function allocates a new parser.
-** The only argument is a pointer to a function which works like
-** malloc.
-**
-** Inputs:
-** A pointer to the function used to allocate memory.
-**
-** Outputs:
-** A pointer to a parser. This pointer is used in subsequent calls
-** to sqlite3Fts5Parser and sqlite3Fts5ParserFree.
-*/
-static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(fts5YYMALLOCARGTYPE)){
- fts5yyParser *pParser;
- pParser = (fts5yyParser*)(*mallocProc)( (fts5YYMALLOCARGTYPE)sizeof(fts5yyParser) );
- if( pParser ){
- pParser->fts5yyidx = -1;
-#ifdef fts5YYTRACKMAXSTACKDEPTH
- pParser->fts5yyidxMax = 0;
-#endif
-#if fts5YYSTACKDEPTH<=0
- pParser->fts5yystack = NULL;
- pParser->fts5yystksz = 0;
- fts5yyGrowStack(pParser);
-#endif
- }
- return pParser;
-}
-
-/* The following function deletes the "minor type" or semantic value
-** associated with a symbol. The symbol can be either a terminal
-** or nonterminal. "fts5yymajor" is the symbol code, and "fts5yypminor" is
-** a pointer to the value to be deleted. The code used to do the
-** deletions is derived from the %destructor and/or %token_destructor
-** directives of the input grammar.
-*/
-static void fts5yy_destructor(
- fts5yyParser *fts5yypParser, /* The parser */
- fts5YYCODETYPE fts5yymajor, /* Type code for object to destroy */
- fts5YYMINORTYPE *fts5yypminor /* The object to be destroyed */
-){
- sqlite3Fts5ParserARG_FETCH;
- switch( fts5yymajor ){
- /* Here is inserted the actions which take place when a
- ** terminal or non-terminal is destroyed. This can happen
- ** when the symbol is popped from the stack during a
- ** reduce or during error processing or when a parser is
- ** being destroyed before it is finished parsing.
- **
- ** Note: during a reduce, the only symbols destroyed are those
- ** which appear on the RHS of the rule, but which are *not* used
- ** inside the C code.
- */
-/********* Begin destructor definitions ***************************************/
- case 15: /* input */
-{
- (void)pParse;
-}
- break;
- case 16: /* expr */
- case 17: /* cnearset */
- case 18: /* exprlist */
-{
- sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy18));
-}
- break;
- case 19: /* nearset */
- case 22: /* nearphrases */
-{
- sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy26));
-}
- break;
- case 20: /* colset */
- case 21: /* colsetlist */
-{
- sqlite3_free((fts5yypminor->fts5yy3));
-}
- break;
- case 23: /* phrase */
-{
- sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy11));
-}
- break;
-/********* End destructor definitions *****************************************/
- default: break; /* If no destructor action specified: do nothing */
- }
-}
-
-/*
-** Pop the parser's stack once.
-**
-** If there is a destructor routine associated with the token which
-** is popped from the stack, then call it.
-*/
-static void fts5yy_pop_parser_stack(fts5yyParser *pParser){
- fts5yyStackEntry *fts5yytos;
- assert( pParser->fts5yyidx>=0 );
- fts5yytos = &pParser->fts5yystack[pParser->fts5yyidx--];
-#ifndef NDEBUG
- if( fts5yyTraceFILE ){
- fprintf(fts5yyTraceFILE,"%sPopping %s\n",
- fts5yyTracePrompt,
- fts5yyTokenName[fts5yytos->major]);
- }
-#endif
- fts5yy_destructor(pParser, fts5yytos->major, &fts5yytos->minor);
-}
-
-/*
-** Deallocate and destroy a parser. Destructors are called for
-** all stack elements before shutting the parser down.
-**
-** If the fts5YYPARSEFREENEVERNULL macro exists (for example because it
-** is defined in a %include section of the input grammar) then it is
-** assumed that the input pointer is never NULL.
-*/
-static void sqlite3Fts5ParserFree(
- void *p, /* The parser to be deleted */
- void (*freeProc)(void*) /* Function used to reclaim memory */
-){
- fts5yyParser *pParser = (fts5yyParser*)p;
-#ifndef fts5YYPARSEFREENEVERNULL
- if( pParser==0 ) return;
-#endif
- while( pParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(pParser);
-#if fts5YYSTACKDEPTH<=0
- free(pParser->fts5yystack);
-#endif
- (*freeProc)((void*)pParser);
-}
-
-/*
-** Return the peak depth of the stack for a parser.
-*/
-#ifdef fts5YYTRACKMAXSTACKDEPTH
-static int sqlite3Fts5ParserStackPeak(void *p){
- fts5yyParser *pParser = (fts5yyParser*)p;
- return pParser->fts5yyidxMax;
-}
-#endif
-
-/*
-** Find the appropriate action for a parser given the terminal
-** look-ahead token iLookAhead.
-*/
-static unsigned int fts5yy_find_shift_action(
- fts5yyParser *pParser, /* The parser */
- fts5YYCODETYPE iLookAhead /* The look-ahead token */
-){
- int i;
- int stateno = pParser->fts5yystack[pParser->fts5yyidx].stateno;
-
- if( stateno>=fts5YY_MIN_REDUCE ) return stateno;
- assert( stateno <= fts5YY_SHIFT_COUNT );
- do{
- i = fts5yy_shift_ofst[stateno];
- if( i==fts5YY_SHIFT_USE_DFLT ) return fts5yy_default[stateno];
- assert( iLookAhead!=fts5YYNOCODE );
- i += iLookAhead;
- if( i<0 || i>=fts5YY_ACTTAB_COUNT || fts5yy_lookahead[i]!=iLookAhead ){
- if( iLookAhead>0 ){
-#ifdef fts5YYFALLBACK
- fts5YYCODETYPE iFallback; /* Fallback token */
- if( iLookAhead<sizeof(fts5yyFallback)/sizeof(fts5yyFallback[0])
- && (iFallback = fts5yyFallback[iLookAhead])!=0 ){
-#ifndef NDEBUG
- if( fts5yyTraceFILE ){
- fprintf(fts5yyTraceFILE, "%sFALLBACK %s => %s\n",
- fts5yyTracePrompt, fts5yyTokenName[iLookAhead], fts5yyTokenName[iFallback]);
- }
-#endif
- assert( fts5yyFallback[iFallback]==0 ); /* Fallback loop must terminate */
- iLookAhead = iFallback;
- continue;
- }
-#endif
-#ifdef fts5YYWILDCARD
- {
- int j = i - iLookAhead + fts5YYWILDCARD;
- if(
-#if fts5YY_SHIFT_MIN+fts5YYWILDCARD<0
- j>=0 &&
-#endif
-#if fts5YY_SHIFT_MAX+fts5YYWILDCARD>=fts5YY_ACTTAB_COUNT
- j<fts5YY_ACTTAB_COUNT &&
-#endif
- fts5yy_lookahead[j]==fts5YYWILDCARD
- ){
-#ifndef NDEBUG
- if( fts5yyTraceFILE ){
- fprintf(fts5yyTraceFILE, "%sWILDCARD %s => %s\n",
- fts5yyTracePrompt, fts5yyTokenName[iLookAhead],
- fts5yyTokenName[fts5YYWILDCARD]);
- }
-#endif /* NDEBUG */
- return fts5yy_action[j];
- }
- }
-#endif /* fts5YYWILDCARD */
- }
- return fts5yy_default[stateno];
- }else{
- return fts5yy_action[i];
- }
- }while(1);
-}
-
-/*
-** Find the appropriate action for a parser given the non-terminal
-** look-ahead token iLookAhead.
-*/
-static int fts5yy_find_reduce_action(
- int stateno, /* Current state number */
- fts5YYCODETYPE iLookAhead /* The look-ahead token */
-){
- int i;
-#ifdef fts5YYERRORSYMBOL
- if( stateno>fts5YY_REDUCE_COUNT ){
- return fts5yy_default[stateno];
- }
-#else
- assert( stateno<=fts5YY_REDUCE_COUNT );
-#endif
- i = fts5yy_reduce_ofst[stateno];
- assert( i!=fts5YY_REDUCE_USE_DFLT );
- assert( iLookAhead!=fts5YYNOCODE );
- i += iLookAhead;
-#ifdef fts5YYERRORSYMBOL
- if( i<0 || i>=fts5YY_ACTTAB_COUNT || fts5yy_lookahead[i]!=iLookAhead ){
- return fts5yy_default[stateno];
- }
-#else
- assert( i>=0 && i<fts5YY_ACTTAB_COUNT );
- assert( fts5yy_lookahead[i]==iLookAhead );
-#endif
- return fts5yy_action[i];
-}
-
-/*
-** The following routine is called if the stack overflows.
-*/
-static void fts5yyStackOverflow(fts5yyParser *fts5yypParser){
- sqlite3Fts5ParserARG_FETCH;
- fts5yypParser->fts5yyidx--;
-#ifndef NDEBUG
- if( fts5yyTraceFILE ){
- fprintf(fts5yyTraceFILE,"%sStack Overflow!\n",fts5yyTracePrompt);
- }
-#endif
- while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser);
- /* Here code is inserted which will execute if the parser
- ** stack every overflows */
-/******** Begin %stack_overflow code ******************************************/
-
- sqlite3Fts5ParseError(pParse, "fts5: parser stack overflow");
-/******** End %stack_overflow code ********************************************/
- sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument var */
-}
-
-/*
-** Print tracing information for a SHIFT action
-*/
-#ifndef NDEBUG
-static void fts5yyTraceShift(fts5yyParser *fts5yypParser, int fts5yyNewState){
- if( fts5yyTraceFILE ){
- if( fts5yyNewState<fts5YYNSTATE ){
- fprintf(fts5yyTraceFILE,"%sShift '%s', go to state %d\n",
- fts5yyTracePrompt,fts5yyTokenName[fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].major],
- fts5yyNewState);
- }else{
- fprintf(fts5yyTraceFILE,"%sShift '%s'\n",
- fts5yyTracePrompt,fts5yyTokenName[fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].major]);
- }
- }
-}
-#else
-# define fts5yyTraceShift(X,Y)
-#endif
-
-/*
-** Perform a shift action.
-*/
-static void fts5yy_shift(
- fts5yyParser *fts5yypParser, /* The parser to be shifted */
- int fts5yyNewState, /* The new state to shift in */
- int fts5yyMajor, /* The major token to shift in */
- sqlite3Fts5ParserFTS5TOKENTYPE fts5yyMinor /* The minor token to shift in */
-){
- fts5yyStackEntry *fts5yytos;
- fts5yypParser->fts5yyidx++;
-#ifdef fts5YYTRACKMAXSTACKDEPTH
- if( fts5yypParser->fts5yyidx>fts5yypParser->fts5yyidxMax ){
- fts5yypParser->fts5yyidxMax = fts5yypParser->fts5yyidx;
- }
-#endif
-#if fts5YYSTACKDEPTH>0
- if( fts5yypParser->fts5yyidx>=fts5YYSTACKDEPTH ){
- fts5yyStackOverflow(fts5yypParser);
- return;
- }
-#else
- if( fts5yypParser->fts5yyidx>=fts5yypParser->fts5yystksz ){
- fts5yyGrowStack(fts5yypParser);
- if( fts5yypParser->fts5yyidx>=fts5yypParser->fts5yystksz ){
- fts5yyStackOverflow(fts5yypParser);
- return;
- }
- }
-#endif
- fts5yytos = &fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx];
- fts5yytos->stateno = (fts5YYACTIONTYPE)fts5yyNewState;
- fts5yytos->major = (fts5YYCODETYPE)fts5yyMajor;
- fts5yytos->minor.fts5yy0 = fts5yyMinor;
- fts5yyTraceShift(fts5yypParser, fts5yyNewState);
-}
-
-/* The following table contains information about every rule that
-** is used during the reduce.
-*/
-static const struct {
- fts5YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
- unsigned char nrhs; /* Number of right-hand side symbols in the rule */
-} fts5yyRuleInfo[] = {
- { 15, 1 },
- { 16, 3 },
- { 16, 3 },
- { 16, 3 },
- { 16, 3 },
- { 16, 1 },
- { 18, 1 },
- { 18, 2 },
- { 17, 1 },
- { 17, 3 },
- { 20, 3 },
- { 20, 1 },
- { 21, 2 },
- { 21, 1 },
- { 19, 1 },
- { 19, 5 },
- { 22, 1 },
- { 22, 2 },
- { 24, 0 },
- { 24, 2 },
- { 23, 4 },
- { 23, 2 },
- { 25, 1 },
- { 25, 0 },
-};
-
-static void fts5yy_accept(fts5yyParser*); /* Forward Declaration */
-
-/*
-** Perform a reduce action and the shift that must immediately
-** follow the reduce.
-*/
-static void fts5yy_reduce(
- fts5yyParser *fts5yypParser, /* The parser */
- unsigned int fts5yyruleno /* Number of the rule by which to reduce */
-){
- int fts5yygoto; /* The next state */
- int fts5yyact; /* The next action */
- fts5yyStackEntry *fts5yymsp; /* The top of the parser's stack */
- int fts5yysize; /* Amount to pop the stack */
- sqlite3Fts5ParserARG_FETCH;
- fts5yymsp = &fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx];
-#ifndef NDEBUG
- if( fts5yyTraceFILE && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){
- fts5yysize = fts5yyRuleInfo[fts5yyruleno].nrhs;
- fprintf(fts5yyTraceFILE, "%sReduce [%s], go to state %d.\n", fts5yyTracePrompt,
- fts5yyRuleName[fts5yyruleno], fts5yymsp[-fts5yysize].stateno);
- }
-#endif /* NDEBUG */
-
- /* Check that the stack is large enough to grow by a single entry
- ** if the RHS of the rule is empty. This ensures that there is room
- ** enough on the stack to push the LHS value */
- if( fts5yyRuleInfo[fts5yyruleno].nrhs==0 ){
-#ifdef fts5YYTRACKMAXSTACKDEPTH
- if( fts5yypParser->fts5yyidx>fts5yypParser->fts5yyidxMax ){
- fts5yypParser->fts5yyidxMax = fts5yypParser->fts5yyidx;
- }
-#endif
-#if fts5YYSTACKDEPTH>0
- if( fts5yypParser->fts5yyidx>=fts5YYSTACKDEPTH-1 ){
- fts5yyStackOverflow(fts5yypParser);
- return;
- }
-#else
- if( fts5yypParser->fts5yyidx>=fts5yypParser->fts5yystksz-1 ){
- fts5yyGrowStack(fts5yypParser);
- if( fts5yypParser->fts5yyidx>=fts5yypParser->fts5yystksz-1 ){
- fts5yyStackOverflow(fts5yypParser);
- return;
- }
- }
-#endif
- }
-
- switch( fts5yyruleno ){
- /* Beginning here are the reduction cases. A typical example
- ** follows:
- ** case 0:
- ** #line <lineno> <grammarfile>
- ** { ... } // User supplied code
- ** #line <lineno> <thisfile>
- ** break;
- */
-/********** Begin reduce actions **********************************************/
- fts5YYMINORTYPE fts5yylhsminor;
- case 0: /* input ::= expr */
-{ sqlite3Fts5ParseFinished(pParse, fts5yymsp[0].minor.fts5yy18); }
- break;
- case 1: /* expr ::= expr AND expr */
-{
- fts5yylhsminor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0);
-}
- fts5yymsp[-2].minor.fts5yy18 = fts5yylhsminor.fts5yy18;
- break;
- case 2: /* expr ::= expr OR expr */
-{
- fts5yylhsminor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_OR, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0);
-}
- fts5yymsp[-2].minor.fts5yy18 = fts5yylhsminor.fts5yy18;
- break;
- case 3: /* expr ::= expr NOT expr */
-{
- fts5yylhsminor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_NOT, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0);
-}
- fts5yymsp[-2].minor.fts5yy18 = fts5yylhsminor.fts5yy18;
- break;
- case 4: /* expr ::= LP expr RP */
-{fts5yymsp[-2].minor.fts5yy18 = fts5yymsp[-1].minor.fts5yy18;}
- break;
- case 5: /* expr ::= exprlist */
- case 6: /* exprlist ::= cnearset */ fts5yytestcase(fts5yyruleno==6);
-{fts5yylhsminor.fts5yy18 = fts5yymsp[0].minor.fts5yy18;}
- fts5yymsp[0].minor.fts5yy18 = fts5yylhsminor.fts5yy18;
- break;
- case 7: /* exprlist ::= exprlist cnearset */
-{
- fts5yylhsminor.fts5yy18 = sqlite3Fts5ParseImplicitAnd(pParse, fts5yymsp[-1].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18);
-}
- fts5yymsp[-1].minor.fts5yy18 = fts5yylhsminor.fts5yy18;
- break;
- case 8: /* cnearset ::= nearset */
-{
- fts5yylhsminor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy26);
-}
- fts5yymsp[0].minor.fts5yy18 = fts5yylhsminor.fts5yy18;
- break;
- case 9: /* cnearset ::= colset COLON nearset */
-{
- sqlite3Fts5ParseSetColset(pParse, fts5yymsp[0].minor.fts5yy26, fts5yymsp[-2].minor.fts5yy3);
- fts5yylhsminor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy26);
-}
- fts5yymsp[-2].minor.fts5yy18 = fts5yylhsminor.fts5yy18;
- break;
- case 10: /* colset ::= LCP colsetlist RCP */
-{ fts5yymsp[-2].minor.fts5yy3 = fts5yymsp[-1].minor.fts5yy3; }
- break;
- case 11: /* colset ::= STRING */
-{
- fts5yylhsminor.fts5yy3 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
-}
- fts5yymsp[0].minor.fts5yy3 = fts5yylhsminor.fts5yy3;
- break;
- case 12: /* colsetlist ::= colsetlist STRING */
-{
- fts5yylhsminor.fts5yy3 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy3, &fts5yymsp[0].minor.fts5yy0); }
- fts5yymsp[-1].minor.fts5yy3 = fts5yylhsminor.fts5yy3;
- break;
- case 13: /* colsetlist ::= STRING */
-{
- fts5yylhsminor.fts5yy3 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
-}
- fts5yymsp[0].minor.fts5yy3 = fts5yylhsminor.fts5yy3;
- break;
- case 14: /* nearset ::= phrase */
-{ fts5yylhsminor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); }
- fts5yymsp[0].minor.fts5yy26 = fts5yylhsminor.fts5yy26;
- break;
- case 15: /* nearset ::= STRING LP nearphrases neardist_opt RP */
-{
- sqlite3Fts5ParseNear(pParse, &fts5yymsp[-4].minor.fts5yy0);
- sqlite3Fts5ParseSetDistance(pParse, fts5yymsp[-2].minor.fts5yy26, &fts5yymsp[-1].minor.fts5yy0);
- fts5yylhsminor.fts5yy26 = fts5yymsp[-2].minor.fts5yy26;
-}
- fts5yymsp[-4].minor.fts5yy26 = fts5yylhsminor.fts5yy26;
- break;
- case 16: /* nearphrases ::= phrase */
-{
- fts5yylhsminor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11);
-}
- fts5yymsp[0].minor.fts5yy26 = fts5yylhsminor.fts5yy26;
- break;
- case 17: /* nearphrases ::= nearphrases phrase */
-{
- fts5yylhsminor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, fts5yymsp[-1].minor.fts5yy26, fts5yymsp[0].minor.fts5yy11);
-}
- fts5yymsp[-1].minor.fts5yy26 = fts5yylhsminor.fts5yy26;
- break;
- case 18: /* neardist_opt ::= */
-{ fts5yymsp[1].minor.fts5yy0.p = 0; fts5yymsp[1].minor.fts5yy0.n = 0; }
- break;
- case 19: /* neardist_opt ::= COMMA STRING */
-{ fts5yymsp[-1].minor.fts5yy0 = fts5yymsp[0].minor.fts5yy0; }
- break;
- case 20: /* phrase ::= phrase PLUS STRING star_opt */
-{
- fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, fts5yymsp[-3].minor.fts5yy11, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy20);
-}
- fts5yymsp[-3].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
- break;
- case 21: /* phrase ::= STRING star_opt */
-{
- fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, 0, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy20);
-}
- fts5yymsp[-1].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
- break;
- case 22: /* star_opt ::= STAR */
-{ fts5yymsp[0].minor.fts5yy20 = 1; }
- break;
- case 23: /* star_opt ::= */
-{ fts5yymsp[1].minor.fts5yy20 = 0; }
- break;
- default:
- break;
-/********** End reduce actions ************************************************/
- };
- assert( fts5yyruleno<sizeof(fts5yyRuleInfo)/sizeof(fts5yyRuleInfo[0]) );
- fts5yygoto = fts5yyRuleInfo[fts5yyruleno].lhs;
- fts5yysize = fts5yyRuleInfo[fts5yyruleno].nrhs;
- fts5yyact = fts5yy_find_reduce_action(fts5yymsp[-fts5yysize].stateno,(fts5YYCODETYPE)fts5yygoto);
- if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){
- if( fts5yyact>fts5YY_MAX_SHIFT ) fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE;
- fts5yypParser->fts5yyidx -= fts5yysize - 1;
- fts5yymsp -= fts5yysize-1;
- fts5yymsp->stateno = (fts5YYACTIONTYPE)fts5yyact;
- fts5yymsp->major = (fts5YYCODETYPE)fts5yygoto;
- fts5yyTraceShift(fts5yypParser, fts5yyact);
- }else{
- assert( fts5yyact == fts5YY_ACCEPT_ACTION );
- fts5yypParser->fts5yyidx -= fts5yysize;
- fts5yy_accept(fts5yypParser);
- }
-}
-
-/*
-** The following code executes when the parse fails
-*/
-#ifndef fts5YYNOERRORRECOVERY
-static void fts5yy_parse_failed(
- fts5yyParser *fts5yypParser /* The parser */
-){
- sqlite3Fts5ParserARG_FETCH;
-#ifndef NDEBUG
- if( fts5yyTraceFILE ){
- fprintf(fts5yyTraceFILE,"%sFail!\n",fts5yyTracePrompt);
- }
-#endif
- while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser);
- /* Here code is inserted which will be executed whenever the
- ** parser fails */
-/************ Begin %parse_failure code ***************************************/
-/************ End %parse_failure code *****************************************/
- sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
-}
-#endif /* fts5YYNOERRORRECOVERY */
-
-/*
-** The following code executes when a syntax error first occurs.
-*/
-static void fts5yy_syntax_error(
- fts5yyParser *fts5yypParser, /* The parser */
- int fts5yymajor, /* The major type of the error token */
- sqlite3Fts5ParserFTS5TOKENTYPE fts5yyminor /* The minor type of the error token */
-){
- sqlite3Fts5ParserARG_FETCH;
-#define FTS5TOKEN fts5yyminor
-/************ Begin %syntax_error code ****************************************/
-
- UNUSED_PARAM(fts5yymajor); /* Silence a compiler warning */
- sqlite3Fts5ParseError(
- pParse, "fts5: syntax error near \"%.*s\"",FTS5TOKEN.n,FTS5TOKEN.p
- );
-/************ End %syntax_error code ******************************************/
- sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
-}
-
-/*
-** The following is executed when the parser accepts
-*/
-static void fts5yy_accept(
- fts5yyParser *fts5yypParser /* The parser */
-){
- sqlite3Fts5ParserARG_FETCH;
-#ifndef NDEBUG
- if( fts5yyTraceFILE ){
- fprintf(fts5yyTraceFILE,"%sAccept!\n",fts5yyTracePrompt);
- }
-#endif
- while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser);
- /* Here code is inserted which will be executed whenever the
- ** parser accepts */
-/*********** Begin %parse_accept code *****************************************/
-/*********** End %parse_accept code *******************************************/
- sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
-}
-
-/* The main parser program.
-** The first argument is a pointer to a structure obtained from
-** "sqlite3Fts5ParserAlloc" which describes the current state of the parser.
-** The second argument is the major token number. The third is
-** the minor token. The fourth optional argument is whatever the
-** user wants (and specified in the grammar) and is available for
-** use by the action routines.
-**
-** Inputs:
-** <ul>
-** <li> A pointer to the parser (an opaque structure.)
-** <li> The major token number.
-** <li> The minor token number.
-** <li> An option argument of a grammar-specified type.
-** </ul>
-**
-** Outputs:
-** None.
-*/
-static void sqlite3Fts5Parser(
- void *fts5yyp, /* The parser */
- int fts5yymajor, /* The major token code number */
- sqlite3Fts5ParserFTS5TOKENTYPE fts5yyminor /* The value for the token */
- sqlite3Fts5ParserARG_PDECL /* Optional %extra_argument parameter */
-){
- fts5YYMINORTYPE fts5yyminorunion;
- unsigned int fts5yyact; /* The parser action. */
-#if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY)
- int fts5yyendofinput; /* True if we are at the end of input */
-#endif
-#ifdef fts5YYERRORSYMBOL
- int fts5yyerrorhit = 0; /* True if fts5yymajor has invoked an error */
-#endif
- fts5yyParser *fts5yypParser; /* The parser */
-
- /* (re)initialize the parser, if necessary */
- fts5yypParser = (fts5yyParser*)fts5yyp;
- if( fts5yypParser->fts5yyidx<0 ){
-#if fts5YYSTACKDEPTH<=0
- if( fts5yypParser->fts5yystksz <=0 ){
- fts5yyStackOverflow(fts5yypParser);
- return;
- }
-#endif
- fts5yypParser->fts5yyidx = 0;
-#ifndef fts5YYNOERRORRECOVERY
- fts5yypParser->fts5yyerrcnt = -1;
-#endif
- fts5yypParser->fts5yystack[0].stateno = 0;
- fts5yypParser->fts5yystack[0].major = 0;
-#ifndef NDEBUG
- if( fts5yyTraceFILE ){
- fprintf(fts5yyTraceFILE,"%sInitialize. Empty stack. State 0\n",
- fts5yyTracePrompt);
- }
-#endif
- }
-#if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY)
- fts5yyendofinput = (fts5yymajor==0);
-#endif
- sqlite3Fts5ParserARG_STORE;
-
-#ifndef NDEBUG
- if( fts5yyTraceFILE ){
- fprintf(fts5yyTraceFILE,"%sInput '%s'\n",fts5yyTracePrompt,fts5yyTokenName[fts5yymajor]);
- }
-#endif
-
- do{
- fts5yyact = fts5yy_find_shift_action(fts5yypParser,(fts5YYCODETYPE)fts5yymajor);
- if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){
- if( fts5yyact > fts5YY_MAX_SHIFT ) fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE;
- fts5yy_shift(fts5yypParser,fts5yyact,fts5yymajor,fts5yyminor);
-#ifndef fts5YYNOERRORRECOVERY
- fts5yypParser->fts5yyerrcnt--;
-#endif
- fts5yymajor = fts5YYNOCODE;
- }else if( fts5yyact <= fts5YY_MAX_REDUCE ){
- fts5yy_reduce(fts5yypParser,fts5yyact-fts5YY_MIN_REDUCE);
- }else{
- assert( fts5yyact == fts5YY_ERROR_ACTION );
- fts5yyminorunion.fts5yy0 = fts5yyminor;
-#ifdef fts5YYERRORSYMBOL
- int fts5yymx;
-#endif
-#ifndef NDEBUG
- if( fts5yyTraceFILE ){
- fprintf(fts5yyTraceFILE,"%sSyntax Error!\n",fts5yyTracePrompt);
- }
-#endif
-#ifdef fts5YYERRORSYMBOL
- /* A syntax error has occurred.
- ** The response to an error depends upon whether or not the
- ** grammar defines an error token "ERROR".
- **
- ** This is what we do if the grammar does define ERROR:
- **
- ** * Call the %syntax_error function.
- **
- ** * Begin popping the stack until we enter a state where
- ** it is legal to shift the error symbol, then shift
- ** the error symbol.
- **
- ** * Set the error count to three.
- **
- ** * Begin accepting and shifting new tokens. No new error
- ** processing will occur until three tokens have been
- ** shifted successfully.
- **
- */
- if( fts5yypParser->fts5yyerrcnt<0 ){
- fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminor);
- }
- fts5yymx = fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].major;
- if( fts5yymx==fts5YYERRORSYMBOL || fts5yyerrorhit ){
-#ifndef NDEBUG
- if( fts5yyTraceFILE ){
- fprintf(fts5yyTraceFILE,"%sDiscard input token %s\n",
- fts5yyTracePrompt,fts5yyTokenName[fts5yymajor]);
- }
-#endif
- fts5yy_destructor(fts5yypParser, (fts5YYCODETYPE)fts5yymajor, &fts5yyminorunion);
- fts5yymajor = fts5YYNOCODE;
- }else{
- while(
- fts5yypParser->fts5yyidx >= 0 &&
- fts5yymx != fts5YYERRORSYMBOL &&
- (fts5yyact = fts5yy_find_reduce_action(
- fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].stateno,
- fts5YYERRORSYMBOL)) >= fts5YY_MIN_REDUCE
- ){
- fts5yy_pop_parser_stack(fts5yypParser);
- }
- if( fts5yypParser->fts5yyidx < 0 || fts5yymajor==0 ){
- fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
- fts5yy_parse_failed(fts5yypParser);
- fts5yymajor = fts5YYNOCODE;
- }else if( fts5yymx!=fts5YYERRORSYMBOL ){
- fts5yy_shift(fts5yypParser,fts5yyact,fts5YYERRORSYMBOL,fts5yyminor);
- }
- }
- fts5yypParser->fts5yyerrcnt = 3;
- fts5yyerrorhit = 1;
-#elif defined(fts5YYNOERRORRECOVERY)
- /* If the fts5YYNOERRORRECOVERY macro is defined, then do not attempt to
- ** do any kind of error recovery. Instead, simply invoke the syntax
- ** error routine and continue going as if nothing had happened.
- **
- ** Applications can set this macro (for example inside %include) if
- ** they intend to abandon the parse upon the first syntax error seen.
- */
- fts5yy_syntax_error(fts5yypParser,fts5yymajor, fts5yyminor);
- fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
- fts5yymajor = fts5YYNOCODE;
-
-#else /* fts5YYERRORSYMBOL is not defined */
- /* This is what we do if the grammar does not define ERROR:
- **
- ** * Report an error message, and throw away the input token.
- **
- ** * If the input token is $, then fail the parse.
- **
- ** As before, subsequent error messages are suppressed until
- ** three input tokens have been successfully shifted.
- */
- if( fts5yypParser->fts5yyerrcnt<=0 ){
- fts5yy_syntax_error(fts5yypParser,fts5yymajor, fts5yyminor);
- }
- fts5yypParser->fts5yyerrcnt = 3;
- fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
- if( fts5yyendofinput ){
- fts5yy_parse_failed(fts5yypParser);
- }
- fts5yymajor = fts5YYNOCODE;
-#endif
- }
- }while( fts5yymajor!=fts5YYNOCODE && fts5yypParser->fts5yyidx>=0 );
-#ifndef NDEBUG
- if( fts5yyTraceFILE ){
- int i;
- fprintf(fts5yyTraceFILE,"%sReturn. Stack=",fts5yyTracePrompt);
- for(i=1; i<=fts5yypParser->fts5yyidx; i++)
- fprintf(fts5yyTraceFILE,"%c%s", i==1 ? '[' : ' ',
- fts5yyTokenName[fts5yypParser->fts5yystack[i].major]);
- fprintf(fts5yyTraceFILE,"]\n");
- }
-#endif
- return;
-}
-
-/*
-** 2014 May 31
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-*/
-
-
-/* #include "fts5Int.h" */
-#include <math.h> /* amalgamator: keep */
-
-/*
-** Object used to iterate through all "coalesced phrase instances" in
-** a single column of the current row. If the phrase instances in the
-** column being considered do not overlap, this object simply iterates
-** through them. Or, if they do overlap (share one or more tokens in
-** common), each set of overlapping instances is treated as a single
-** match. See documentation for the highlight() auxiliary function for
-** details.
-**
-** Usage is:
-**
-** for(rc = fts5CInstIterNext(pApi, pFts, iCol, &iter);
-** (rc==SQLITE_OK && 0==fts5CInstIterEof(&iter);
-** rc = fts5CInstIterNext(&iter)
-** ){
-** printf("instance starts at %d, ends at %d\n", iter.iStart, iter.iEnd);
-** }
-**
-*/
-typedef struct CInstIter CInstIter;
-struct CInstIter {
- const Fts5ExtensionApi *pApi; /* API offered by current FTS version */
- Fts5Context *pFts; /* First arg to pass to pApi functions */
- int iCol; /* Column to search */
- int iInst; /* Next phrase instance index */
- int nInst; /* Total number of phrase instances */
-
- /* Output variables */
- int iStart; /* First token in coalesced phrase instance */
- int iEnd; /* Last token in coalesced phrase instance */
-};
-
-/*
-** Advance the iterator to the next coalesced phrase instance. Return
-** an SQLite error code if an error occurs, or SQLITE_OK otherwise.
-*/
-static int fts5CInstIterNext(CInstIter *pIter){
- int rc = SQLITE_OK;
- pIter->iStart = -1;
- pIter->iEnd = -1;
-
- while( rc==SQLITE_OK && pIter->iInst<pIter->nInst ){
- int ip; int ic; int io;
- rc = pIter->pApi->xInst(pIter->pFts, pIter->iInst, &ip, &ic, &io);
- if( rc==SQLITE_OK ){
- if( ic==pIter->iCol ){
- int iEnd = io - 1 + pIter->pApi->xPhraseSize(pIter->pFts, ip);
- if( pIter->iStart<0 ){
- pIter->iStart = io;
- pIter->iEnd = iEnd;
- }else if( io<=pIter->iEnd ){
- if( iEnd>pIter->iEnd ) pIter->iEnd = iEnd;
- }else{
- break;
- }
- }
- pIter->iInst++;
- }
- }
-
- return rc;
-}
-
-/*
-** Initialize the iterator object indicated by the final parameter to
-** iterate through coalesced phrase instances in column iCol.
-*/
-static int fts5CInstIterInit(
- const Fts5ExtensionApi *pApi,
- Fts5Context *pFts,
- int iCol,
- CInstIter *pIter
-){
- int rc;
-
- memset(pIter, 0, sizeof(CInstIter));
- pIter->pApi = pApi;
- pIter->pFts = pFts;
- pIter->iCol = iCol;
- rc = pApi->xInstCount(pFts, &pIter->nInst);
-
- if( rc==SQLITE_OK ){
- rc = fts5CInstIterNext(pIter);
- }
-
- return rc;
-}
-
-
-
-/*************************************************************************
-** Start of highlight() implementation.
-*/
-typedef struct HighlightContext HighlightContext;
-struct HighlightContext {
- CInstIter iter; /* Coalesced Instance Iterator */
- int iPos; /* Current token offset in zIn[] */
- int iRangeStart; /* First token to include */
- int iRangeEnd; /* If non-zero, last token to include */
- const char *zOpen; /* Opening highlight */
- const char *zClose; /* Closing highlight */
- const char *zIn; /* Input text */
- int nIn; /* Size of input text in bytes */
- int iOff; /* Current offset within zIn[] */
- char *zOut; /* Output value */
-};
-
-/*
-** Append text to the HighlightContext output string - p->zOut. Argument
-** z points to a buffer containing n bytes of text to append. If n is
-** negative, everything up until the first '\0' is appended to the output.
-**
-** If *pRc is set to any value other than SQLITE_OK when this function is
-** called, it is a no-op. If an error (i.e. an OOM condition) is encountered,
-** *pRc is set to an error code before returning.
-*/
-static void fts5HighlightAppend(
- int *pRc,
- HighlightContext *p,
- const char *z, int n
-){
- if( *pRc==SQLITE_OK ){
- if( n<0 ) n = (int)strlen(z);
- p->zOut = sqlite3_mprintf("%z%.*s", p->zOut, n, z);
- if( p->zOut==0 ) *pRc = SQLITE_NOMEM;
- }
-}
-
-/*
-** Tokenizer callback used by implementation of highlight() function.
-*/
-static int fts5HighlightCb(
- void *pContext, /* Pointer to HighlightContext object */
- int tflags, /* Mask of FTS5_TOKEN_* flags */
- const char *pToken, /* Buffer containing token */
- int nToken, /* Size of token in bytes */
- int iStartOff, /* Start offset of token */
- int iEndOff /* End offset of token */
-){
- HighlightContext *p = (HighlightContext*)pContext;
- int rc = SQLITE_OK;
- int iPos;
-
- UNUSED_PARAM2(pToken, nToken);
-
- if( tflags & FTS5_TOKEN_COLOCATED ) return SQLITE_OK;
- iPos = p->iPos++;
-
- if( p->iRangeEnd>0 ){
- if( iPos<p->iRangeStart || iPos>p->iRangeEnd ) return SQLITE_OK;
- if( p->iRangeStart && iPos==p->iRangeStart ) p->iOff = iStartOff;
- }
-
- if( iPos==p->iter.iStart ){
- fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iStartOff - p->iOff);
- fts5HighlightAppend(&rc, p, p->zOpen, -1);
- p->iOff = iStartOff;
- }
-
- if( iPos==p->iter.iEnd ){
- if( p->iRangeEnd && p->iter.iStart<p->iRangeStart ){
- fts5HighlightAppend(&rc, p, p->zOpen, -1);
- }
- fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
- fts5HighlightAppend(&rc, p, p->zClose, -1);
- p->iOff = iEndOff;
- if( rc==SQLITE_OK ){
- rc = fts5CInstIterNext(&p->iter);
- }
- }
-
- if( p->iRangeEnd>0 && iPos==p->iRangeEnd ){
- fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
- p->iOff = iEndOff;
- if( iPos<p->iter.iEnd ){
- fts5HighlightAppend(&rc, p, p->zClose, -1);
- }
- }
-
- return rc;
-}
-
-/*
-** Implementation of highlight() function.
-*/
-static void fts5HighlightFunction(
- const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
- Fts5Context *pFts, /* First arg to pass to pApi functions */
- sqlite3_context *pCtx, /* Context for returning result/error */
- int nVal, /* Number of values in apVal[] array */
- sqlite3_value **apVal /* Array of trailing arguments */
-){
- HighlightContext ctx;
- int rc;
- int iCol;
-
- if( nVal!=3 ){
- const char *zErr = "wrong number of arguments to function highlight()";
- sqlite3_result_error(pCtx, zErr, -1);
- return;
- }
-
- iCol = sqlite3_value_int(apVal[0]);
- memset(&ctx, 0, sizeof(HighlightContext));
- ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]);
- ctx.zClose = (const char*)sqlite3_value_text(apVal[2]);
- rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn);
-
- if( ctx.zIn ){
- if( rc==SQLITE_OK ){
- rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter);
- }
-
- if( rc==SQLITE_OK ){
- rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
- }
- fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
-
- if( rc==SQLITE_OK ){
- sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT);
- }
- sqlite3_free(ctx.zOut);
- }
- if( rc!=SQLITE_OK ){
- sqlite3_result_error_code(pCtx, rc);
- }
-}
-/*
-** End of highlight() implementation.
-**************************************************************************/
-
-/*
-** Implementation of snippet() function.
-*/
-static void fts5SnippetFunction(
- const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
- Fts5Context *pFts, /* First arg to pass to pApi functions */
- sqlite3_context *pCtx, /* Context for returning result/error */
- int nVal, /* Number of values in apVal[] array */
- sqlite3_value **apVal /* Array of trailing arguments */
-){
- HighlightContext ctx;
- int rc = SQLITE_OK; /* Return code */
- int iCol; /* 1st argument to snippet() */
- const char *zEllips; /* 4th argument to snippet() */
- int nToken; /* 5th argument to snippet() */
- int nInst = 0; /* Number of instance matches this row */
- int i; /* Used to iterate through instances */
- int nPhrase; /* Number of phrases in query */
- unsigned char *aSeen; /* Array of "seen instance" flags */
- int iBestCol; /* Column containing best snippet */
- int iBestStart = 0; /* First token of best snippet */
- int iBestLast; /* Last token of best snippet */
- int nBestScore = 0; /* Score of best snippet */
- int nColSize = 0; /* Total size of iBestCol in tokens */
-
- if( nVal!=5 ){
- const char *zErr = "wrong number of arguments to function snippet()";
- sqlite3_result_error(pCtx, zErr, -1);
- return;
- }
-
- memset(&ctx, 0, sizeof(HighlightContext));
- iCol = sqlite3_value_int(apVal[0]);
- ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]);
- ctx.zClose = (const char*)sqlite3_value_text(apVal[2]);
- zEllips = (const char*)sqlite3_value_text(apVal[3]);
- nToken = sqlite3_value_int(apVal[4]);
- iBestLast = nToken-1;
-
- iBestCol = (iCol>=0 ? iCol : 0);
- nPhrase = pApi->xPhraseCount(pFts);
- aSeen = sqlite3_malloc(nPhrase);
- if( aSeen==0 ){
- rc = SQLITE_NOMEM;
- }
-
- if( rc==SQLITE_OK ){
- rc = pApi->xInstCount(pFts, &nInst);
- }
- for(i=0; rc==SQLITE_OK && i<nInst; i++){
- int ip, iSnippetCol, iStart;
- memset(aSeen, 0, nPhrase);
- rc = pApi->xInst(pFts, i, &ip, &iSnippetCol, &iStart);
- if( rc==SQLITE_OK && (iCol<0 || iSnippetCol==iCol) ){
- int nScore = 1000;
- int iLast = iStart - 1 + pApi->xPhraseSize(pFts, ip);
- int j;
- aSeen[ip] = 1;
-
- for(j=i+1; rc==SQLITE_OK && j<nInst; j++){
- int ic; int io; int iFinal;
- rc = pApi->xInst(pFts, j, &ip, &ic, &io);
- iFinal = io + pApi->xPhraseSize(pFts, ip) - 1;
- if( rc==SQLITE_OK && ic==iSnippetCol && iLast<iStart+nToken ){
- nScore += aSeen[ip] ? 1000 : 1;
- aSeen[ip] = 1;
- if( iFinal>iLast ) iLast = iFinal;
- }
- }
-
- if( rc==SQLITE_OK && nScore>nBestScore ){
- iBestCol = iSnippetCol;
- iBestStart = iStart;
- iBestLast = iLast;
- nBestScore = nScore;
- }
- }
- }
-
- if( rc==SQLITE_OK ){
- rc = pApi->xColumnSize(pFts, iBestCol, &nColSize);
- }
- if( rc==SQLITE_OK ){
- rc = pApi->xColumnText(pFts, iBestCol, &ctx.zIn, &ctx.nIn);
- }
- if( ctx.zIn ){
- if( rc==SQLITE_OK ){
- rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter);
- }
-
- if( (iBestStart+nToken-1)>iBestLast ){
- iBestStart -= (iBestStart+nToken-1-iBestLast) / 2;
- }
- if( iBestStart+nToken>nColSize ){
- iBestStart = nColSize - nToken;
- }
- if( iBestStart<0 ) iBestStart = 0;
-
- ctx.iRangeStart = iBestStart;
- ctx.iRangeEnd = iBestStart + nToken - 1;
-
- if( iBestStart>0 ){
- fts5HighlightAppend(&rc, &ctx, zEllips, -1);
- }
- if( rc==SQLITE_OK ){
- rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
- }
- if( ctx.iRangeEnd>=(nColSize-1) ){
- fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
- }else{
- fts5HighlightAppend(&rc, &ctx, zEllips, -1);
- }
-
- if( rc==SQLITE_OK ){
- sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT);
- }else{
- sqlite3_result_error_code(pCtx, rc);
- }
- sqlite3_free(ctx.zOut);
- }
- sqlite3_free(aSeen);
-}
-
-/************************************************************************/
-
-/*
-** The first time the bm25() function is called for a query, an instance
-** of the following structure is allocated and populated.
-*/
-typedef struct Fts5Bm25Data Fts5Bm25Data;
-struct Fts5Bm25Data {
- int nPhrase; /* Number of phrases in query */
- double avgdl; /* Average number of tokens in each row */
- double *aIDF; /* IDF for each phrase */
- double *aFreq; /* Array used to calculate phrase freq. */
-};
-
-/*
-** Callback used by fts5Bm25GetData() to count the number of rows in the
-** table matched by each individual phrase within the query.
-*/
-static int fts5CountCb(
- const Fts5ExtensionApi *pApi,
- Fts5Context *pFts,
- void *pUserData /* Pointer to sqlite3_int64 variable */
-){
- sqlite3_int64 *pn = (sqlite3_int64*)pUserData;
- UNUSED_PARAM2(pApi, pFts);
- (*pn)++;
- return SQLITE_OK;
-}
-
-/*
-** Set *ppData to point to the Fts5Bm25Data object for the current query.
-** If the object has not already been allocated, allocate and populate it
-** now.
-*/
-static int fts5Bm25GetData(
- const Fts5ExtensionApi *pApi,
- Fts5Context *pFts,
- Fts5Bm25Data **ppData /* OUT: bm25-data object for this query */
-){
- int rc = SQLITE_OK; /* Return code */
- Fts5Bm25Data *p; /* Object to return */
-
- p = pApi->xGetAuxdata(pFts, 0);
- if( p==0 ){
- int nPhrase; /* Number of phrases in query */
- sqlite3_int64 nRow = 0; /* Number of rows in table */
- sqlite3_int64 nToken = 0; /* Number of tokens in table */
- int nByte; /* Bytes of space to allocate */
- int i;
-
- /* Allocate the Fts5Bm25Data object */
- nPhrase = pApi->xPhraseCount(pFts);
- nByte = sizeof(Fts5Bm25Data) + nPhrase*2*sizeof(double);
- p = (Fts5Bm25Data*)sqlite3_malloc(nByte);
- if( p==0 ){
- rc = SQLITE_NOMEM;
- }else{
- memset(p, 0, nByte);
- p->nPhrase = nPhrase;
- p->aIDF = (double*)&p[1];
- p->aFreq = &p->aIDF[nPhrase];
- }
-
- /* Calculate the average document length for this FTS5 table */
- if( rc==SQLITE_OK ) rc = pApi->xRowCount(pFts, &nRow);
- if( rc==SQLITE_OK ) rc = pApi->xColumnTotalSize(pFts, -1, &nToken);
- if( rc==SQLITE_OK ) p->avgdl = (double)nToken / (double)nRow;
-
- /* Calculate an IDF for each phrase in the query */
- for(i=0; rc==SQLITE_OK && i<nPhrase; i++){
- sqlite3_int64 nHit = 0;
- rc = pApi->xQueryPhrase(pFts, i, (void*)&nHit, fts5CountCb);
- if( rc==SQLITE_OK ){
- /* Calculate the IDF (Inverse Document Frequency) for phrase i.
- ** This is done using the standard BM25 formula as found on wikipedia:
- **
- ** IDF = log( (N - nHit + 0.5) / (nHit + 0.5) )
- **
- ** where "N" is the total number of documents in the set and nHit
- ** is the number that contain at least one instance of the phrase
- ** under consideration.
- **
- ** The problem with this is that if (N < 2*nHit), the IDF is
- ** negative. Which is undesirable. So the mimimum allowable IDF is
- ** (1e-6) - roughly the same as a term that appears in just over
- ** half of set of 5,000,000 documents. */
- double idf = log( (nRow - nHit + 0.5) / (nHit + 0.5) );
- if( idf<=0.0 ) idf = 1e-6;
- p->aIDF[i] = idf;
- }
- }
-
- if( rc!=SQLITE_OK ){
- sqlite3_free(p);
- }else{
- rc = pApi->xSetAuxdata(pFts, p, sqlite3_free);
- }
- if( rc!=SQLITE_OK ) p = 0;
- }
- *ppData = p;
- return rc;
-}
-
-/*
-** Implementation of bm25() function.
-*/
-static void fts5Bm25Function(
- const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
- Fts5Context *pFts, /* First arg to pass to pApi functions */
- sqlite3_context *pCtx, /* Context for returning result/error */
- int nVal, /* Number of values in apVal[] array */
- sqlite3_value **apVal /* Array of trailing arguments */
-){
- const double k1 = 1.2; /* Constant "k1" from BM25 formula */
- const double b = 0.75; /* Constant "b" from BM25 formula */
- int rc = SQLITE_OK; /* Error code */
- double score = 0.0; /* SQL function return value */
- Fts5Bm25Data *pData; /* Values allocated/calculated once only */
- int i; /* Iterator variable */
- int nInst = 0; /* Value returned by xInstCount() */
- double D = 0.0; /* Total number of tokens in row */
- double *aFreq = 0; /* Array of phrase freq. for current row */
-
- /* Calculate the phrase frequency (symbol "f(qi,D)" in the documentation)
- ** for each phrase in the query for the current row. */
- rc = fts5Bm25GetData(pApi, pFts, &pData);
- if( rc==SQLITE_OK ){
- aFreq = pData->aFreq;
- memset(aFreq, 0, sizeof(double) * pData->nPhrase);
- rc = pApi->xInstCount(pFts, &nInst);
- }
- for(i=0; rc==SQLITE_OK && i<nInst; i++){
- int ip; int ic; int io;
- rc = pApi->xInst(pFts, i, &ip, &ic, &io);
- if( rc==SQLITE_OK ){
- double w = (nVal > ic) ? sqlite3_value_double(apVal[ic]) : 1.0;
- aFreq[ip] += w;
- }
- }
-
- /* Figure out the total size of the current row in tokens. */
- if( rc==SQLITE_OK ){
- int nTok;
- rc = pApi->xColumnSize(pFts, -1, &nTok);
- D = (double)nTok;
- }
-
- /* Determine the BM25 score for the current row. */
- for(i=0; rc==SQLITE_OK && i<pData->nPhrase; i++){
- score += pData->aIDF[i] * (
- ( aFreq[i] * (k1 + 1.0) ) /
- ( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) )
- );
- }
-
- /* If no error has occurred, return the calculated score. Otherwise,
- ** throw an SQL exception. */
- if( rc==SQLITE_OK ){
- sqlite3_result_double(pCtx, -1.0 * score);
- }else{
- sqlite3_result_error_code(pCtx, rc);
- }
-}
-
-static int sqlite3Fts5AuxInit(fts5_api *pApi){
- struct Builtin {
- const char *zFunc; /* Function name (nul-terminated) */
- void *pUserData; /* User-data pointer */
- fts5_extension_function xFunc;/* Callback function */
- void (*xDestroy)(void*); /* Destructor function */
- } aBuiltin [] = {
- { "snippet", 0, fts5SnippetFunction, 0 },
- { "highlight", 0, fts5HighlightFunction, 0 },
- { "bm25", 0, fts5Bm25Function, 0 },
- };
- int rc = SQLITE_OK; /* Return code */
- int i; /* To iterate through builtin functions */
-
- for(i=0; rc==SQLITE_OK && i<ArraySize(aBuiltin); i++){
- rc = pApi->xCreateFunction(pApi,
- aBuiltin[i].zFunc,
- aBuiltin[i].pUserData,
- aBuiltin[i].xFunc,
- aBuiltin[i].xDestroy
- );
- }
-
- return rc;
-}
-
-
-
-/*
-** 2014 May 31
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-*/
-
-
-
-/* #include "fts5Int.h" */
-
-static int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){
- if( (u32)pBuf->nSpace<nByte ){
- u32 nNew = pBuf->nSpace ? pBuf->nSpace : 64;
- u8 *pNew;
- while( nNew<nByte ){
- nNew = nNew * 2;
- }
- pNew = sqlite3_realloc(pBuf->p, nNew);
- if( pNew==0 ){
- *pRc = SQLITE_NOMEM;
- return 1;
- }else{
- pBuf->nSpace = nNew;
- pBuf->p = pNew;
- }
- }
- return 0;
-}
-
-
-/*
-** Encode value iVal as an SQLite varint and append it to the buffer object
-** pBuf. If an OOM error occurs, set the error code in p.
-*/
-static void sqlite3Fts5BufferAppendVarint(int *pRc, Fts5Buffer *pBuf, i64 iVal){
- if( fts5BufferGrow(pRc, pBuf, 9) ) return;
- pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iVal);
-}
-
-static void sqlite3Fts5Put32(u8 *aBuf, int iVal){
- aBuf[0] = (iVal>>24) & 0x00FF;
- aBuf[1] = (iVal>>16) & 0x00FF;
- aBuf[2] = (iVal>> 8) & 0x00FF;
- aBuf[3] = (iVal>> 0) & 0x00FF;
-}
-
-static int sqlite3Fts5Get32(const u8 *aBuf){
- return (aBuf[0] << 24) + (aBuf[1] << 16) + (aBuf[2] << 8) + aBuf[3];
-}
-
-/*
-** Append buffer nData/pData to buffer pBuf. If an OOM error occurs, set
-** the error code in p. If an error has already occurred when this function
-** is called, it is a no-op.
-*/
-static void sqlite3Fts5BufferAppendBlob(
- int *pRc,
- Fts5Buffer *pBuf,
- u32 nData,
- const u8 *pData
-){
- assert_nc( *pRc || nData>=0 );
- if( fts5BufferGrow(pRc, pBuf, nData) ) return;
- memcpy(&pBuf->p[pBuf->n], pData, nData);
- pBuf->n += nData;
-}
-
-/*
-** Append the nul-terminated string zStr to the buffer pBuf. This function
-** ensures that the byte following the buffer data is set to 0x00, even
-** though this byte is not included in the pBuf->n count.
-*/
-static void sqlite3Fts5BufferAppendString(
- int *pRc,
- Fts5Buffer *pBuf,
- const char *zStr
-){
- int nStr = (int)strlen(zStr);
- sqlite3Fts5BufferAppendBlob(pRc, pBuf, nStr+1, (const u8*)zStr);
- pBuf->n--;
-}
-
-/*
-** Argument zFmt is a printf() style format string. This function performs
-** the printf() style processing, then appends the results to buffer pBuf.
-**
-** Like sqlite3Fts5BufferAppendString(), this function ensures that the byte
-** following the buffer data is set to 0x00, even though this byte is not
-** included in the pBuf->n count.
-*/
-static void sqlite3Fts5BufferAppendPrintf(
- int *pRc,
- Fts5Buffer *pBuf,
- char *zFmt, ...
-){
- if( *pRc==SQLITE_OK ){
- char *zTmp;
- va_list ap;
- va_start(ap, zFmt);
- zTmp = sqlite3_vmprintf(zFmt, ap);
- va_end(ap);
-
- if( zTmp==0 ){
- *pRc = SQLITE_NOMEM;
- }else{
- sqlite3Fts5BufferAppendString(pRc, pBuf, zTmp);
- sqlite3_free(zTmp);
- }
- }
-}
-
-static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...){
- char *zRet = 0;
- if( *pRc==SQLITE_OK ){
- va_list ap;
- va_start(ap, zFmt);
- zRet = sqlite3_vmprintf(zFmt, ap);
- va_end(ap);
- if( zRet==0 ){
- *pRc = SQLITE_NOMEM;
- }
- }
- return zRet;
-}
-
-
-/*
-** Free any buffer allocated by pBuf. Zero the structure before returning.
-*/
-static void sqlite3Fts5BufferFree(Fts5Buffer *pBuf){
- sqlite3_free(pBuf->p);
- memset(pBuf, 0, sizeof(Fts5Buffer));
-}
-
-/*
-** Zero the contents of the buffer object. But do not free the associated
-** memory allocation.
-*/
-static void sqlite3Fts5BufferZero(Fts5Buffer *pBuf){
- pBuf->n = 0;
-}
-
-/*
-** Set the buffer to contain nData/pData. If an OOM error occurs, leave an
-** the error code in p. If an error has already occurred when this function
-** is called, it is a no-op.
-*/
-static void sqlite3Fts5BufferSet(
- int *pRc,
- Fts5Buffer *pBuf,
- int nData,
- const u8 *pData
-){
- pBuf->n = 0;
- sqlite3Fts5BufferAppendBlob(pRc, pBuf, nData, pData);
-}
-
-static int sqlite3Fts5PoslistNext64(
- const u8 *a, int n, /* Buffer containing poslist */
- int *pi, /* IN/OUT: Offset within a[] */
- i64 *piOff /* IN/OUT: Current offset */
-){
- int i = *pi;
- if( i>=n ){
- /* EOF */
- *piOff = -1;
- return 1;
- }else{
- i64 iOff = *piOff;
- int iVal;
- fts5FastGetVarint32(a, i, iVal);
- if( iVal==1 ){
- fts5FastGetVarint32(a, i, iVal);
- iOff = ((i64)iVal) << 32;
- fts5FastGetVarint32(a, i, iVal);
- }
- *piOff = iOff + (iVal-2);
- *pi = i;
- return 0;
- }
-}
-
-
-/*
-** Advance the iterator object passed as the only argument. Return true
-** if the iterator reaches EOF, or false otherwise.
-*/
-static int sqlite3Fts5PoslistReaderNext(Fts5PoslistReader *pIter){
- if( sqlite3Fts5PoslistNext64(pIter->a, pIter->n, &pIter->i, &pIter->iPos) ){
- pIter->bEof = 1;
- }
- return pIter->bEof;
-}
-
-static int sqlite3Fts5PoslistReaderInit(
- const u8 *a, int n, /* Poslist buffer to iterate through */
- Fts5PoslistReader *pIter /* Iterator object to initialize */
-){
- memset(pIter, 0, sizeof(*pIter));
- pIter->a = a;
- pIter->n = n;
- sqlite3Fts5PoslistReaderNext(pIter);
- return pIter->bEof;
-}
-
-/*
-** Append position iPos to the position list being accumulated in buffer
-** pBuf, which must be already be large enough to hold the new data.
-** The previous position written to this list is *piPrev. *piPrev is set
-** to iPos before returning.
-*/
-static void sqlite3Fts5PoslistSafeAppend(
- Fts5Buffer *pBuf,
- i64 *piPrev,
- i64 iPos
-){
- static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32;
- if( (iPos & colmask) != (*piPrev & colmask) ){
- pBuf->p[pBuf->n++] = 1;
- pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32));
- *piPrev = (iPos & colmask);
- }
- pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-*piPrev)+2);
- *piPrev = iPos;
-}
-
-static int sqlite3Fts5PoslistWriterAppend(
- Fts5Buffer *pBuf,
- Fts5PoslistWriter *pWriter,
- i64 iPos
-){
- int rc = 0; /* Initialized only to suppress erroneous warning from Clang */
- if( fts5BufferGrow(&rc, pBuf, 5+5+5) ) return rc;
- sqlite3Fts5PoslistSafeAppend(pBuf, &pWriter->iPrev, iPos);
- return SQLITE_OK;
-}
-
-static void *sqlite3Fts5MallocZero(int *pRc, int nByte){
- void *pRet = 0;
- if( *pRc==SQLITE_OK ){
- pRet = sqlite3_malloc(nByte);
- if( pRet==0 && nByte>0 ){
- *pRc = SQLITE_NOMEM;
- }else{
- memset(pRet, 0, nByte);
- }
- }
- return pRet;
-}
-
-/*
-** Return a nul-terminated copy of the string indicated by pIn. If nIn
-** is non-negative, then it is the length of the string in bytes. Otherwise,
-** the length of the string is determined using strlen().
-**
-** It is the responsibility of the caller to eventually free the returned
-** buffer using sqlite3_free(). If an OOM error occurs, NULL is returned.
-*/
-static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){
- char *zRet = 0;
- if( *pRc==SQLITE_OK ){
- if( nIn<0 ){
- nIn = (int)strlen(pIn);
- }
- zRet = (char*)sqlite3_malloc(nIn+1);
- if( zRet ){
- memcpy(zRet, pIn, nIn);
- zRet[nIn] = '\0';
- }else{
- *pRc = SQLITE_NOMEM;
- }
- }
- return zRet;
-}
-
-
-/*
-** Return true if character 't' may be part of an FTS5 bareword, or false
-** otherwise. Characters that may be part of barewords:
-**
-** * All non-ASCII characters,
-** * The 52 upper and lower case ASCII characters, and
-** * The 10 integer ASCII characters.
-** * The underscore character "_" (0x5F).
-** * The unicode "subsitute" character (0x1A).
-*/
-static int sqlite3Fts5IsBareword(char t){
- u8 aBareword[128] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 .. 0x0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* 0x10 .. 0x1F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 .. 0x2F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0x30 .. 0x3F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 .. 0x4F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x50 .. 0x5F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 .. 0x6F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 /* 0x70 .. 0x7F */
- };
-
- return (t & 0x80) || aBareword[(int)t];
-}
-
-
-/*************************************************************************
-*/
-typedef struct Fts5TermsetEntry Fts5TermsetEntry;
-struct Fts5TermsetEntry {
- char *pTerm;
- int nTerm;
- int iIdx; /* Index (main or aPrefix[] entry) */
- Fts5TermsetEntry *pNext;
-};
-
-struct Fts5Termset {
- Fts5TermsetEntry *apHash[512];
-};
-
-static int sqlite3Fts5TermsetNew(Fts5Termset **pp){
- int rc = SQLITE_OK;
- *pp = sqlite3Fts5MallocZero(&rc, sizeof(Fts5Termset));
- return rc;
-}
-
-static int sqlite3Fts5TermsetAdd(
- Fts5Termset *p,
- int iIdx,
- const char *pTerm, int nTerm,
- int *pbPresent
-){
- int rc = SQLITE_OK;
- *pbPresent = 0;
- if( p ){
- int i;
- u32 hash = 13;
- Fts5TermsetEntry *pEntry;
-
- /* Calculate a hash value for this term. This is the same hash checksum
- ** used by the fts5_hash.c module. This is not important for correct
- ** operation of the module, but is necessary to ensure that some tests
- ** designed to produce hash table collisions really do work. */
- for(i=nTerm-1; i>=0; i--){
- hash = (hash << 3) ^ hash ^ pTerm[i];
- }
- hash = (hash << 3) ^ hash ^ iIdx;
- hash = hash % ArraySize(p->apHash);
-
- for(pEntry=p->apHash[hash]; pEntry; pEntry=pEntry->pNext){
- if( pEntry->iIdx==iIdx
- && pEntry->nTerm==nTerm
- && memcmp(pEntry->pTerm, pTerm, nTerm)==0
- ){
- *pbPresent = 1;
- break;
- }
- }
-
- if( pEntry==0 ){
- pEntry = sqlite3Fts5MallocZero(&rc, sizeof(Fts5TermsetEntry) + nTerm);
- if( pEntry ){
- pEntry->pTerm = (char*)&pEntry[1];
- pEntry->nTerm = nTerm;
- pEntry->iIdx = iIdx;
- memcpy(pEntry->pTerm, pTerm, nTerm);
- pEntry->pNext = p->apHash[hash];
- p->apHash[hash] = pEntry;
- }
- }
- }
-
- return rc;
-}
-
-static void sqlite3Fts5TermsetFree(Fts5Termset *p){
- if( p ){
- u32 i;
- for(i=0; i<ArraySize(p->apHash); i++){
- Fts5TermsetEntry *pEntry = p->apHash[i];
- while( pEntry ){
- Fts5TermsetEntry *pDel = pEntry;
- pEntry = pEntry->pNext;
- sqlite3_free(pDel);
- }
- }
- sqlite3_free(p);
- }
-}
-
-/*
-** 2014 Jun 09
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This is an SQLite module implementing full-text search.
-*/
-
-
-/* #include "fts5Int.h" */
-
-#define FTS5_DEFAULT_PAGE_SIZE 4050
-#define FTS5_DEFAULT_AUTOMERGE 4
-#define FTS5_DEFAULT_USERMERGE 4
-#define FTS5_DEFAULT_CRISISMERGE 16
-#define FTS5_DEFAULT_HASHSIZE (1024*1024)
-
-/* Maximum allowed page size */
-#define FTS5_MAX_PAGE_SIZE (128*1024)
-
-static int fts5_iswhitespace(char x){
- return (x==' ');
-}
-
-static int fts5_isopenquote(char x){
- return (x=='"' || x=='\'' || x=='[' || x=='`');
-}
-
-/*
-** Argument pIn points to a character that is part of a nul-terminated
-** string. Return a pointer to the first character following *pIn in
-** the string that is not a white-space character.
-*/
-static const char *fts5ConfigSkipWhitespace(const char *pIn){
- const char *p = pIn;
- if( p ){
- while( fts5_iswhitespace(*p) ){ p++; }
- }
- return p;
-}
-
-/*
-** Argument pIn points to a character that is part of a nul-terminated
-** string. Return a pointer to the first character following *pIn in
-** the string that is not a "bareword" character.
-*/
-static const char *fts5ConfigSkipBareword(const char *pIn){
- const char *p = pIn;
- while ( sqlite3Fts5IsBareword(*p) ) p++;
- if( p==pIn ) p = 0;
- return p;
-}
-
-static int fts5_isdigit(char a){
- return (a>='0' && a<='9');
-}
-
-
-
-static const char *fts5ConfigSkipLiteral(const char *pIn){
- const char *p = pIn;
- switch( *p ){
- case 'n': case 'N':
- if( sqlite3_strnicmp("null", p, 4)==0 ){
- p = &p[4];
- }else{
- p = 0;
- }
- break;
-
- case 'x': case 'X':
- p++;
- if( *p=='\'' ){
- p++;
- while( (*p>='a' && *p<='f')
- || (*p>='A' && *p<='F')
- || (*p>='0' && *p<='9')
- ){
- p++;
- }
- if( *p=='\'' && 0==((p-pIn)%2) ){
- p++;
- }else{
- p = 0;
- }
- }else{
- p = 0;
- }
- break;
-
- case '\'':
- p++;
- while( p ){
- if( *p=='\'' ){
- p++;
- if( *p!='\'' ) break;
- }
- p++;
- if( *p==0 ) p = 0;
- }
- break;
-
- default:
- /* maybe a number */
- if( *p=='+' || *p=='-' ) p++;
- while( fts5_isdigit(*p) ) p++;
-
- /* At this point, if the literal was an integer, the parse is
- ** finished. Or, if it is a floating point value, it may continue
- ** with either a decimal point or an 'E' character. */
- if( *p=='.' && fts5_isdigit(p[1]) ){
- p += 2;
- while( fts5_isdigit(*p) ) p++;
- }
- if( p==pIn ) p = 0;
-
- break;
- }
-
- return p;
-}
-
-/*
-** The first character of the string pointed to by argument z is guaranteed
-** to be an open-quote character (see function fts5_isopenquote()).
-**
-** This function searches for the corresponding close-quote character within
-** the string and, if found, dequotes the string in place and adds a new
-** nul-terminator byte.
-**
-** If the close-quote is found, the value returned is the byte offset of
-** the character immediately following it. Or, if the close-quote is not
-** found, -1 is returned. If -1 is returned, the buffer is left in an
-** undefined state.
-*/
-static int fts5Dequote(char *z){
- char q;
- int iIn = 1;
- int iOut = 0;
- q = z[0];
-
- /* Set stack variable q to the close-quote character */
- assert( q=='[' || q=='\'' || q=='"' || q=='`' );
- if( q=='[' ) q = ']';
-
- while( ALWAYS(z[iIn]) ){
- if( z[iIn]==q ){
- if( z[iIn+1]!=q ){
- /* Character iIn was the close quote. */
- iIn++;
- break;
- }else{
- /* Character iIn and iIn+1 form an escaped quote character. Skip
- ** the input cursor past both and copy a single quote character
- ** to the output buffer. */
- iIn += 2;
- z[iOut++] = q;
- }
- }else{
- z[iOut++] = z[iIn++];
- }
- }
-
- z[iOut] = '\0';
- return iIn;
-}
-
-/*
-** Convert an SQL-style quoted string into a normal string by removing
-** the quote characters. The conversion is done in-place. If the
-** input does not begin with a quote character, then this routine
-** is a no-op.
-**
-** Examples:
-**
-** "abc" becomes abc
-** 'xyz' becomes xyz
-** [pqr] becomes pqr
-** `mno` becomes mno
-*/
-static void sqlite3Fts5Dequote(char *z){
- char quote; /* Quote character (if any ) */
-
- assert( 0==fts5_iswhitespace(z[0]) );
- quote = z[0];
- if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){
- fts5Dequote(z);
- }
-}
-
-
-struct Fts5Enum {
- const char *zName;
- int eVal;
-};
-typedef struct Fts5Enum Fts5Enum;
-
-static int fts5ConfigSetEnum(
- const Fts5Enum *aEnum,
- const char *zEnum,
- int *peVal
-){
- int nEnum = (int)strlen(zEnum);
- int i;
- int iVal = -1;
-
- for(i=0; aEnum[i].zName; i++){
- if( sqlite3_strnicmp(aEnum[i].zName, zEnum, nEnum)==0 ){
- if( iVal>=0 ) return SQLITE_ERROR;
- iVal = aEnum[i].eVal;
- }
- }
-
- *peVal = iVal;
- return iVal<0 ? SQLITE_ERROR : SQLITE_OK;
-}
-
-/*
-** Parse a "special" CREATE VIRTUAL TABLE directive and update
-** configuration object pConfig as appropriate.
-**
-** If successful, object pConfig is updated and SQLITE_OK returned. If
-** an error occurs, an SQLite error code is returned and an error message
-** may be left in *pzErr. It is the responsibility of the caller to
-** eventually free any such error message using sqlite3_free().
-*/
-static int fts5ConfigParseSpecial(
- Fts5Global *pGlobal,
- Fts5Config *pConfig, /* Configuration object to update */
- const char *zCmd, /* Special command to parse */
- const char *zArg, /* Argument to parse */
- char **pzErr /* OUT: Error message */
-){
- int rc = SQLITE_OK;
- int nCmd = (int)strlen(zCmd);
- if( sqlite3_strnicmp("prefix", zCmd, nCmd)==0 ){
- const int nByte = sizeof(int) * FTS5_MAX_PREFIX_INDEXES;
- const char *p;
- int bFirst = 1;
- if( pConfig->aPrefix==0 ){
- pConfig->aPrefix = sqlite3Fts5MallocZero(&rc, nByte);
- if( rc ) return rc;
- }
-
- p = zArg;
- while( 1 ){
- int nPre = 0;
-
- while( p[0]==' ' ) p++;
- if( bFirst==0 && p[0]==',' ){
- p++;
- while( p[0]==' ' ) p++;
- }else if( p[0]=='\0' ){
- break;
- }
- if( p[0]<'0' || p[0]>'9' ){
- *pzErr = sqlite3_mprintf("malformed prefix=... directive");
- rc = SQLITE_ERROR;
- break;
- }
-
- if( pConfig->nPrefix==FTS5_MAX_PREFIX_INDEXES ){
- *pzErr = sqlite3_mprintf(
- "too many prefix indexes (max %d)", FTS5_MAX_PREFIX_INDEXES
- );
- rc = SQLITE_ERROR;
- break;
- }
-
- while( p[0]>='0' && p[0]<='9' && nPre<1000 ){
- nPre = nPre*10 + (p[0] - '0');
- p++;
- }
-
- if( nPre<=0 || nPre>=1000 ){
- *pzErr = sqlite3_mprintf("prefix length out of range (max 999)");
- rc = SQLITE_ERROR;
- break;
- }
-
- pConfig->aPrefix[pConfig->nPrefix] = nPre;
- pConfig->nPrefix++;
- bFirst = 0;
- }
- assert( pConfig->nPrefix<=FTS5_MAX_PREFIX_INDEXES );
- return rc;
- }
-
- if( sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){
- const char *p = (const char*)zArg;
- int nArg = (int)strlen(zArg) + 1;
- char **azArg = sqlite3Fts5MallocZero(&rc, sizeof(char*) * nArg);
- char *pDel = sqlite3Fts5MallocZero(&rc, nArg * 2);
- char *pSpace = pDel;
-
- if( azArg && pSpace ){
- if( pConfig->pTok ){
- *pzErr = sqlite3_mprintf("multiple tokenize=... directives");
- rc = SQLITE_ERROR;
- }else{
- for(nArg=0; p && *p; nArg++){
- const char *p2 = fts5ConfigSkipWhitespace(p);
- if( *p2=='\'' ){
- p = fts5ConfigSkipLiteral(p2);
- }else{
- p = fts5ConfigSkipBareword(p2);
- }
- if( p ){
- memcpy(pSpace, p2, p-p2);
- azArg[nArg] = pSpace;
- sqlite3Fts5Dequote(pSpace);
- pSpace += (p - p2) + 1;
- p = fts5ConfigSkipWhitespace(p);
- }
- }
- if( p==0 ){
- *pzErr = sqlite3_mprintf("parse error in tokenize directive");
- rc = SQLITE_ERROR;
- }else{
- rc = sqlite3Fts5GetTokenizer(pGlobal,
- (const char**)azArg, nArg, &pConfig->pTok, &pConfig->pTokApi,
- pzErr
- );
- }
- }
- }
-
- sqlite3_free(azArg);
- sqlite3_free(pDel);
- return rc;
- }
-
- if( sqlite3_strnicmp("content", zCmd, nCmd)==0 ){
- if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){
- *pzErr = sqlite3_mprintf("multiple content=... directives");
- rc = SQLITE_ERROR;
- }else{
- if( zArg[0] ){
- pConfig->eContent = FTS5_CONTENT_EXTERNAL;
- pConfig->zContent = sqlite3Fts5Mprintf(&rc, "%Q.%Q", pConfig->zDb,zArg);
- }else{
- pConfig->eContent = FTS5_CONTENT_NONE;
- }
- }
- return rc;
- }
-
- if( sqlite3_strnicmp("content_rowid", zCmd, nCmd)==0 ){
- if( pConfig->zContentRowid ){
- *pzErr = sqlite3_mprintf("multiple content_rowid=... directives");
- rc = SQLITE_ERROR;
- }else{
- pConfig->zContentRowid = sqlite3Fts5Strndup(&rc, zArg, -1);
- }
- return rc;
- }
-
- if( sqlite3_strnicmp("columnsize", zCmd, nCmd)==0 ){
- if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
- *pzErr = sqlite3_mprintf("malformed columnsize=... directive");
- rc = SQLITE_ERROR;
- }else{
- pConfig->bColumnsize = (zArg[0]=='1');
- }
- return rc;
- }
-
- if( sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){
- const Fts5Enum aDetail[] = {
- { "none", FTS5_DETAIL_NONE },
- { "full", FTS5_DETAIL_FULL },
- { "columns", FTS5_DETAIL_COLUMNS },
- { 0, 0 }
- };
-
- if( (rc = fts5ConfigSetEnum(aDetail, zArg, &pConfig->eDetail)) ){
- *pzErr = sqlite3_mprintf("malformed detail=... directive");
- }
- return rc;
- }
-
- *pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd);
- return SQLITE_ERROR;
-}
-
-/*
-** Allocate an instance of the default tokenizer ("simple") at
-** Fts5Config.pTokenizer. Return SQLITE_OK if successful, or an SQLite error
-** code if an error occurs.
-*/
-static int fts5ConfigDefaultTokenizer(Fts5Global *pGlobal, Fts5Config *pConfig){
- assert( pConfig->pTok==0 && pConfig->pTokApi==0 );
- return sqlite3Fts5GetTokenizer(
- pGlobal, 0, 0, &pConfig->pTok, &pConfig->pTokApi, 0
- );
-}
-
-/*
-** Gobble up the first bareword or quoted word from the input buffer zIn.
-** Return a pointer to the character immediately following the last in
-** the gobbled word if successful, or a NULL pointer otherwise (failed
-** to find close-quote character).
-**
-** Before returning, set pzOut to point to a new buffer containing a
-** nul-terminated, dequoted copy of the gobbled word. If the word was
-** quoted, *pbQuoted is also set to 1 before returning.
-**
-** If *pRc is other than SQLITE_OK when this function is called, it is
-** a no-op (NULL is returned). Otherwise, if an OOM occurs within this
-** function, *pRc is set to SQLITE_NOMEM before returning. *pRc is *not*
-** set if a parse error (failed to find close quote) occurs.
-*/
-static const char *fts5ConfigGobbleWord(
- int *pRc, /* IN/OUT: Error code */
- const char *zIn, /* Buffer to gobble string/bareword from */
- char **pzOut, /* OUT: malloc'd buffer containing str/bw */
- int *pbQuoted /* OUT: Set to true if dequoting required */
-){
- const char *zRet = 0;
-
- int nIn = (int)strlen(zIn);
- char *zOut = sqlite3_malloc(nIn+1);
-
- assert( *pRc==SQLITE_OK );
- *pbQuoted = 0;
- *pzOut = 0;
-
- if( zOut==0 ){
- *pRc = SQLITE_NOMEM;
- }else{
- memcpy(zOut, zIn, nIn+1);
- if( fts5_isopenquote(zOut[0]) ){
- int ii = fts5Dequote(zOut);
- zRet = &zIn[ii];
- *pbQuoted = 1;
- }else{
- zRet = fts5ConfigSkipBareword(zIn);
- if( zRet ){
- zOut[zRet-zIn] = '\0';
- }
- }
- }
-
- if( zRet==0 ){
- sqlite3_free(zOut);
- }else{
- *pzOut = zOut;
- }
-
- return zRet;
-}
-
-static int fts5ConfigParseColumn(
- Fts5Config *p,
- char *zCol,
- char *zArg,
- char **pzErr
-){
- int rc = SQLITE_OK;
- if( 0==sqlite3_stricmp(zCol, FTS5_RANK_NAME)
- || 0==sqlite3_stricmp(zCol, FTS5_ROWID_NAME)
- ){
- *pzErr = sqlite3_mprintf("reserved fts5 column name: %s", zCol);
- rc = SQLITE_ERROR;
- }else if( zArg ){
- if( 0==sqlite3_stricmp(zArg, "unindexed") ){
- p->abUnindexed[p->nCol] = 1;
- }else{
- *pzErr = sqlite3_mprintf("unrecognized column option: %s", zArg);
- rc = SQLITE_ERROR;
- }
- }
-
- p->azCol[p->nCol++] = zCol;
- return rc;
-}
-
-/*
-** Populate the Fts5Config.zContentExprlist string.
-*/
-static int fts5ConfigMakeExprlist(Fts5Config *p){
- int i;
- int rc = SQLITE_OK;
- Fts5Buffer buf = {0, 0, 0};
-
- sqlite3Fts5BufferAppendPrintf(&rc, &buf, "T.%Q", p->zContentRowid);
- if( p->eContent!=FTS5_CONTENT_NONE ){
- for(i=0; i<p->nCol; i++){
- if( p->eContent==FTS5_CONTENT_EXTERNAL ){
- sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.%Q", p->azCol[i]);
- }else{
- sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.c%d", i);
- }
- }
- }
-
- assert( p->zContentExprlist==0 );
- p->zContentExprlist = (char*)buf.p;
- return rc;
-}
-
-/*
-** Arguments nArg/azArg contain the string arguments passed to the xCreate
-** or xConnect method of the virtual table. This function attempts to
-** allocate an instance of Fts5Config containing the results of parsing
-** those arguments.
-**
-** If successful, SQLITE_OK is returned and *ppOut is set to point to the
-** new Fts5Config object. If an error occurs, an SQLite error code is
-** returned, *ppOut is set to NULL and an error message may be left in
-** *pzErr. It is the responsibility of the caller to eventually free any
-** such error message using sqlite3_free().
-*/
-static int sqlite3Fts5ConfigParse(
- Fts5Global *pGlobal,
- sqlite3 *db,
- int nArg, /* Number of arguments */
- const char **azArg, /* Array of nArg CREATE VIRTUAL TABLE args */
- Fts5Config **ppOut, /* OUT: Results of parse */
- char **pzErr /* OUT: Error message */
-){
- int rc = SQLITE_OK; /* Return code */
- Fts5Config *pRet; /* New object to return */
- int i;
- int nByte;
-
- *ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config));
- if( pRet==0 ) return SQLITE_NOMEM;
- memset(pRet, 0, sizeof(Fts5Config));
- pRet->db = db;
- pRet->iCookie = -1;
-
- nByte = nArg * (sizeof(char*) + sizeof(u8));
- pRet->azCol = (char**)sqlite3Fts5MallocZero(&rc, nByte);
- pRet->abUnindexed = (u8*)&pRet->azCol[nArg];
- pRet->zDb = sqlite3Fts5Strndup(&rc, azArg[1], -1);
- pRet->zName = sqlite3Fts5Strndup(&rc, azArg[2], -1);
- pRet->bColumnsize = 1;
- pRet->eDetail = FTS5_DETAIL_FULL;
-#ifdef SQLITE_DEBUG
- pRet->bPrefixIndex = 1;
-#endif
- if( rc==SQLITE_OK && sqlite3_stricmp(pRet->zName, FTS5_RANK_NAME)==0 ){
- *pzErr = sqlite3_mprintf("reserved fts5 table name: %s", pRet->zName);
- rc = SQLITE_ERROR;
- }
-
- for(i=3; rc==SQLITE_OK && i<nArg; i++){
- const char *zOrig = azArg[i];
- const char *z;
- char *zOne = 0;
- char *zTwo = 0;
- int bOption = 0;
- int bMustBeCol = 0;
-
- z = fts5ConfigGobbleWord(&rc, zOrig, &zOne, &bMustBeCol);
- z = fts5ConfigSkipWhitespace(z);
- if( z && *z=='=' ){
- bOption = 1;
- z++;
- if( bMustBeCol ) z = 0;
- }
- z = fts5ConfigSkipWhitespace(z);
- if( z && z[0] ){
- int bDummy;
- z = fts5ConfigGobbleWord(&rc, z, &zTwo, &bDummy);
- if( z && z[0] ) z = 0;
- }
-
- if( rc==SQLITE_OK ){
- if( z==0 ){
- *pzErr = sqlite3_mprintf("parse error in \"%s\"", zOrig);
- rc = SQLITE_ERROR;
- }else{
- if( bOption ){
- rc = fts5ConfigParseSpecial(pGlobal, pRet, zOne, zTwo?zTwo:"", pzErr);
- }else{
- rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr);
- zOne = 0;
- }
- }
- }
-
- sqlite3_free(zOne);
- sqlite3_free(zTwo);
- }
-
- /* If a tokenizer= option was successfully parsed, the tokenizer has
- ** already been allocated. Otherwise, allocate an instance of the default
- ** tokenizer (unicode61) now. */
- if( rc==SQLITE_OK && pRet->pTok==0 ){
- rc = fts5ConfigDefaultTokenizer(pGlobal, pRet);
- }
-
- /* If no zContent option was specified, fill in the default values. */
- if( rc==SQLITE_OK && pRet->zContent==0 ){
- const char *zTail = 0;
- assert( pRet->eContent==FTS5_CONTENT_NORMAL
- || pRet->eContent==FTS5_CONTENT_NONE
- );
- if( pRet->eContent==FTS5_CONTENT_NORMAL ){
- zTail = "content";
- }else if( pRet->bColumnsize ){
- zTail = "docsize";
- }
-
- if( zTail ){
- pRet->zContent = sqlite3Fts5Mprintf(
- &rc, "%Q.'%q_%s'", pRet->zDb, pRet->zName, zTail
- );
- }
- }
-
- if( rc==SQLITE_OK && pRet->zContentRowid==0 ){
- pRet->zContentRowid = sqlite3Fts5Strndup(&rc, "rowid", -1);
- }
-
- /* Formulate the zContentExprlist text */
- if( rc==SQLITE_OK ){
- rc = fts5ConfigMakeExprlist(pRet);
- }
-
- if( rc!=SQLITE_OK ){
- sqlite3Fts5ConfigFree(pRet);
- *ppOut = 0;
- }
- return rc;
-}
-
-/*
-** Free the configuration object passed as the only argument.
-*/
-static void sqlite3Fts5ConfigFree(Fts5Config *pConfig){
- if( pConfig ){
- int i;
- if( pConfig->pTok ){
- pConfig->pTokApi->xDelete(pConfig->pTok);
- }
- sqlite3_free(pConfig->zDb);
- sqlite3_free(pConfig->zName);
- for(i=0; i<pConfig->nCol; i++){
- sqlite3_free(pConfig->azCol[i]);
- }
- sqlite3_free(pConfig->azCol);
- sqlite3_free(pConfig->aPrefix);
- sqlite3_free(pConfig->zRank);
- sqlite3_free(pConfig->zRankArgs);
- sqlite3_free(pConfig->zContent);
- sqlite3_free(pConfig->zContentRowid);
- sqlite3_free(pConfig->zContentExprlist);
- sqlite3_free(pConfig);
- }
-}
-
-/*
-** Call sqlite3_declare_vtab() based on the contents of the configuration
-** object passed as the only argument. Return SQLITE_OK if successful, or
-** an SQLite error code if an error occurs.
-*/
-static int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig){
- int i;
- int rc = SQLITE_OK;
- char *zSql;
-
- zSql = sqlite3Fts5Mprintf(&rc, "CREATE TABLE x(");
- for(i=0; zSql && i<pConfig->nCol; i++){
- const char *zSep = (i==0?"":", ");
- zSql = sqlite3Fts5Mprintf(&rc, "%z%s%Q", zSql, zSep, pConfig->azCol[i]);
- }
- zSql = sqlite3Fts5Mprintf(&rc, "%z, %Q HIDDEN, %s HIDDEN)",
- zSql, pConfig->zName, FTS5_RANK_NAME
- );
-
- assert( zSql || rc==SQLITE_NOMEM );
- if( zSql ){
- rc = sqlite3_declare_vtab(pConfig->db, zSql);
- sqlite3_free(zSql);
- }
-
- return rc;
-}
-
-/*
-** Tokenize the text passed via the second and third arguments.
-**
-** The callback is invoked once for each token in the input text. The
-** arguments passed to it are, in order:
-**
-** void *pCtx // Copy of 4th argument to sqlite3Fts5Tokenize()
-** const char *pToken // Pointer to buffer containing token
-** int nToken // Size of token in bytes
-** int iStart // Byte offset of start of token within input text
-** int iEnd // Byte offset of end of token within input text
-** int iPos // Position of token in input (first token is 0)
-**
-** If the callback returns a non-zero value the tokenization is abandoned
-** and no further callbacks are issued.
-**
-** This function returns SQLITE_OK if successful or an SQLite error code
-** if an error occurs. If the tokenization was abandoned early because
-** the callback returned SQLITE_DONE, this is not an error and this function
-** still returns SQLITE_OK. Or, if the tokenization was abandoned early
-** because the callback returned another non-zero value, it is assumed
-** to be an SQLite error code and returned to the caller.
-*/
-static int sqlite3Fts5Tokenize(
- Fts5Config *pConfig, /* FTS5 Configuration object */
- int flags, /* FTS5_TOKENIZE_* flags */
- const char *pText, int nText, /* Text to tokenize */
- void *pCtx, /* Context passed to xToken() */
- int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
-){
- if( pText==0 ) return SQLITE_OK;
- return pConfig->pTokApi->xTokenize(
- pConfig->pTok, pCtx, flags, pText, nText, xToken
- );
-}
-
-/*
-** Argument pIn points to the first character in what is expected to be
-** a comma-separated list of SQL literals followed by a ')' character.
-** If it actually is this, return a pointer to the ')'. Otherwise, return
-** NULL to indicate a parse error.
-*/
-static const char *fts5ConfigSkipArgs(const char *pIn){
- const char *p = pIn;
-
- while( 1 ){
- p = fts5ConfigSkipWhitespace(p);
- p = fts5ConfigSkipLiteral(p);
- p = fts5ConfigSkipWhitespace(p);
- if( p==0 || *p==')' ) break;
- if( *p!=',' ){
- p = 0;
- break;
- }
- p++;
- }
-
- return p;
-}
-
-/*
-** Parameter zIn contains a rank() function specification. The format of
-** this is:
-**
-** + Bareword (function name)
-** + Open parenthesis - "("
-** + Zero or more SQL literals in a comma separated list
-** + Close parenthesis - ")"
-*/
-static int sqlite3Fts5ConfigParseRank(
- const char *zIn, /* Input string */
- char **pzRank, /* OUT: Rank function name */
- char **pzRankArgs /* OUT: Rank function arguments */
-){
- const char *p = zIn;
- const char *pRank;
- char *zRank = 0;
- char *zRankArgs = 0;
- int rc = SQLITE_OK;
-
- *pzRank = 0;
- *pzRankArgs = 0;
-
- if( p==0 ){
- rc = SQLITE_ERROR;
- }else{
- p = fts5ConfigSkipWhitespace(p);
- pRank = p;
- p = fts5ConfigSkipBareword(p);
-
- if( p ){
- zRank = sqlite3Fts5MallocZero(&rc, 1 + p - pRank);
- if( zRank ) memcpy(zRank, pRank, p-pRank);
- }else{
- rc = SQLITE_ERROR;
- }
-
- if( rc==SQLITE_OK ){
- p = fts5ConfigSkipWhitespace(p);
- if( *p!='(' ) rc = SQLITE_ERROR;
- p++;
- }
- if( rc==SQLITE_OK ){
- const char *pArgs;
- p = fts5ConfigSkipWhitespace(p);
- pArgs = p;
- if( *p!=')' ){
- p = fts5ConfigSkipArgs(p);
- if( p==0 ){
- rc = SQLITE_ERROR;
- }else{
- zRankArgs = sqlite3Fts5MallocZero(&rc, 1 + p - pArgs);
- if( zRankArgs ) memcpy(zRankArgs, pArgs, p-pArgs);
- }
- }
- }
- }
-
- if( rc!=SQLITE_OK ){
- sqlite3_free(zRank);
- assert( zRankArgs==0 );
- }else{
- *pzRank = zRank;
- *pzRankArgs = zRankArgs;
- }
- return rc;
-}
-
-static int sqlite3Fts5ConfigSetValue(
- Fts5Config *pConfig,
- const char *zKey,
- sqlite3_value *pVal,
- int *pbBadkey
-){
- int rc = SQLITE_OK;
-
- if( 0==sqlite3_stricmp(zKey, "pgsz") ){
- int pgsz = 0;
- if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
- pgsz = sqlite3_value_int(pVal);
- }
- if( pgsz<=0 || pgsz>FTS5_MAX_PAGE_SIZE ){
- *pbBadkey = 1;
- }else{
- pConfig->pgsz = pgsz;
- }
- }
-
- else if( 0==sqlite3_stricmp(zKey, "hashsize") ){
- int nHashSize = -1;
- if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
- nHashSize = sqlite3_value_int(pVal);
- }
- if( nHashSize<=0 ){
- *pbBadkey = 1;
- }else{
- pConfig->nHashSize = nHashSize;
- }
- }
-
- else if( 0==sqlite3_stricmp(zKey, "automerge") ){
- int nAutomerge = -1;
- if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
- nAutomerge = sqlite3_value_int(pVal);
- }
- if( nAutomerge<0 || nAutomerge>64 ){
- *pbBadkey = 1;
- }else{
- if( nAutomerge==1 ) nAutomerge = FTS5_DEFAULT_AUTOMERGE;
- pConfig->nAutomerge = nAutomerge;
- }
- }
-
- else if( 0==sqlite3_stricmp(zKey, "usermerge") ){
- int nUsermerge = -1;
- if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
- nUsermerge = sqlite3_value_int(pVal);
- }
- if( nUsermerge<2 || nUsermerge>16 ){
- *pbBadkey = 1;
- }else{
- pConfig->nUsermerge = nUsermerge;
- }
- }
-
- else if( 0==sqlite3_stricmp(zKey, "crisismerge") ){
- int nCrisisMerge = -1;
- if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
- nCrisisMerge = sqlite3_value_int(pVal);
- }
- if( nCrisisMerge<0 ){
- *pbBadkey = 1;
- }else{
- if( nCrisisMerge<=1 ) nCrisisMerge = FTS5_DEFAULT_CRISISMERGE;
- pConfig->nCrisisMerge = nCrisisMerge;
- }
- }
-
- else if( 0==sqlite3_stricmp(zKey, "rank") ){
- const char *zIn = (const char*)sqlite3_value_text(pVal);
- char *zRank;
- char *zRankArgs;
- rc = sqlite3Fts5ConfigParseRank(zIn, &zRank, &zRankArgs);
- if( rc==SQLITE_OK ){
- sqlite3_free(pConfig->zRank);
- sqlite3_free(pConfig->zRankArgs);
- pConfig->zRank = zRank;
- pConfig->zRankArgs = zRankArgs;
- }else if( rc==SQLITE_ERROR ){
- rc = SQLITE_OK;
- *pbBadkey = 1;
- }
- }else{
- *pbBadkey = 1;
- }
- return rc;
-}
-
-/*
-** Load the contents of the %_config table into memory.
-*/
-static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
- const char *zSelect = "SELECT k, v FROM %Q.'%q_config'";
- char *zSql;
- sqlite3_stmt *p = 0;
- int rc = SQLITE_OK;
- int iVersion = 0;
-
- /* Set default values */
- pConfig->pgsz = FTS5_DEFAULT_PAGE_SIZE;
- pConfig->nAutomerge = FTS5_DEFAULT_AUTOMERGE;
- pConfig->nUsermerge = FTS5_DEFAULT_USERMERGE;
- pConfig->nCrisisMerge = FTS5_DEFAULT_CRISISMERGE;
- pConfig->nHashSize = FTS5_DEFAULT_HASHSIZE;
-
- zSql = sqlite3Fts5Mprintf(&rc, zSelect, pConfig->zDb, pConfig->zName);
- if( zSql ){
- rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &p, 0);
- sqlite3_free(zSql);
- }
-
- assert( rc==SQLITE_OK || p==0 );
- if( rc==SQLITE_OK ){
- while( SQLITE_ROW==sqlite3_step(p) ){
- const char *zK = (const char*)sqlite3_column_text(p, 0);
- sqlite3_value *pVal = sqlite3_column_value(p, 1);
- if( 0==sqlite3_stricmp(zK, "version") ){
- iVersion = sqlite3_value_int(pVal);
- }else{
- int bDummy = 0;
- sqlite3Fts5ConfigSetValue(pConfig, zK, pVal, &bDummy);
- }
- }
- rc = sqlite3_finalize(p);
- }
-
- if( rc==SQLITE_OK && iVersion!=FTS5_CURRENT_VERSION ){
- rc = SQLITE_ERROR;
- if( pConfig->pzErrmsg ){
- assert( 0==*pConfig->pzErrmsg );
- *pConfig->pzErrmsg = sqlite3_mprintf(
- "invalid fts5 file format (found %d, expected %d) - run 'rebuild'",
- iVersion, FTS5_CURRENT_VERSION
- );
- }
- }
-
- if( rc==SQLITE_OK ){
- pConfig->iCookie = iCookie;
- }
- return rc;
-}
-
-/*
-** 2014 May 31
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-*/
-
-
-
-/* #include "fts5Int.h" */
-/* #include "fts5parse.h" */
-
-/*
-** All token types in the generated fts5parse.h file are greater than 0.
-*/
-#define FTS5_EOF 0
-
-#define FTS5_LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
-
-typedef struct Fts5ExprTerm Fts5ExprTerm;
-
-/*
-** Functions generated by lemon from fts5parse.y.
-*/
-static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(u64));
-static void sqlite3Fts5ParserFree(void*, void (*freeProc)(void*));
-static void sqlite3Fts5Parser(void*, int, Fts5Token, Fts5Parse*);
-#ifndef NDEBUG
-/* #include <stdio.h> */
-static void sqlite3Fts5ParserTrace(FILE*, char*);
-#endif
-
-
-struct Fts5Expr {
- Fts5Index *pIndex;
- Fts5Config *pConfig;
- Fts5ExprNode *pRoot;
- int bDesc; /* Iterate in descending rowid order */
- int nPhrase; /* Number of phrases in expression */
- Fts5ExprPhrase **apExprPhrase; /* Pointers to phrase objects */
-};
-
-/*
-** eType:
-** Expression node type. Always one of:
-**
-** FTS5_AND (nChild, apChild valid)
-** FTS5_OR (nChild, apChild valid)
-** FTS5_NOT (nChild, apChild valid)
-** FTS5_STRING (pNear valid)
-** FTS5_TERM (pNear valid)
-*/
-struct Fts5ExprNode {
- int eType; /* Node type */
- int bEof; /* True at EOF */
- int bNomatch; /* True if entry is not a match */
-
- /* Next method for this node. */
- int (*xNext)(Fts5Expr*, Fts5ExprNode*, int, i64);
-
- i64 iRowid; /* Current rowid */
- Fts5ExprNearset *pNear; /* For FTS5_STRING - cluster of phrases */
-
- /* Child nodes. For a NOT node, this array always contains 2 entries. For
- ** AND or OR nodes, it contains 2 or more entries. */
- int nChild; /* Number of child nodes */
- Fts5ExprNode *apChild[1]; /* Array of child nodes */
-};
-
-#define Fts5NodeIsString(p) ((p)->eType==FTS5_TERM || (p)->eType==FTS5_STRING)
-
-/*
-** Invoke the xNext method of an Fts5ExprNode object. This macro should be
-** used as if it has the same signature as the xNext() methods themselves.
-*/
-#define fts5ExprNodeNext(a,b,c,d) (b)->xNext((a), (b), (c), (d))
-
-/*
-** An instance of the following structure represents a single search term
-** or term prefix.
-*/
-struct Fts5ExprTerm {
- int bPrefix; /* True for a prefix term */
- char *zTerm; /* nul-terminated term */
- Fts5IndexIter *pIter; /* Iterator for this term */
- Fts5ExprTerm *pSynonym; /* Pointer to first in list of synonyms */
-};
-
-/*
-** A phrase. One or more terms that must appear in a contiguous sequence
-** within a document for it to match.
-*/
-struct Fts5ExprPhrase {
- Fts5ExprNode *pNode; /* FTS5_STRING node this phrase is part of */
- Fts5Buffer poslist; /* Current position list */
- int nTerm; /* Number of entries in aTerm[] */
- Fts5ExprTerm aTerm[1]; /* Terms that make up this phrase */
-};
-
-/*
-** One or more phrases that must appear within a certain token distance of
-** each other within each matching document.
-*/
-struct Fts5ExprNearset {
- int nNear; /* NEAR parameter */
- Fts5Colset *pColset; /* Columns to search (NULL -> all columns) */
- int nPhrase; /* Number of entries in aPhrase[] array */
- Fts5ExprPhrase *apPhrase[1]; /* Array of phrase pointers */
-};
-
-
-/*
-** Parse context.
-*/
-struct Fts5Parse {
- Fts5Config *pConfig;
- char *zErr;
- int rc;
- int nPhrase; /* Size of apPhrase array */
- Fts5ExprPhrase **apPhrase; /* Array of all phrases */
- Fts5ExprNode *pExpr; /* Result of a successful parse */
-};
-
-static void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...){
- va_list ap;
- va_start(ap, zFmt);
- if( pParse->rc==SQLITE_OK ){
- pParse->zErr = sqlite3_vmprintf(zFmt, ap);
- pParse->rc = SQLITE_ERROR;
- }
- va_end(ap);
-}
-
-static int fts5ExprIsspace(char t){
- return t==' ' || t=='\t' || t=='\n' || t=='\r';
-}
-
-/*
-** Read the first token from the nul-terminated string at *pz.
-*/
-static int fts5ExprGetToken(
- Fts5Parse *pParse,
- const char **pz, /* IN/OUT: Pointer into buffer */
- Fts5Token *pToken
-){
- const char *z = *pz;
- int tok;
-
- /* Skip past any whitespace */
- while( fts5ExprIsspace(*z) ) z++;
-
- pToken->p = z;
- pToken->n = 1;
- switch( *z ){
- case '(': tok = FTS5_LP; break;
- case ')': tok = FTS5_RP; break;
- case '{': tok = FTS5_LCP; break;
- case '}': tok = FTS5_RCP; break;
- case ':': tok = FTS5_COLON; break;
- case ',': tok = FTS5_COMMA; break;
- case '+': tok = FTS5_PLUS; break;
- case '*': tok = FTS5_STAR; break;
- case '\0': tok = FTS5_EOF; break;
-
- case '"': {
- const char *z2;
- tok = FTS5_STRING;
-
- for(z2=&z[1]; 1; z2++){
- if( z2[0]=='"' ){
- z2++;
- if( z2[0]!='"' ) break;
- }
- if( z2[0]=='\0' ){
- sqlite3Fts5ParseError(pParse, "unterminated string");
- return FTS5_EOF;
- }
- }
- pToken->n = (z2 - z);
- break;
- }
-
- default: {
- const char *z2;
- if( sqlite3Fts5IsBareword(z[0])==0 ){
- sqlite3Fts5ParseError(pParse, "fts5: syntax error near \"%.1s\"", z);
- return FTS5_EOF;
- }
- tok = FTS5_STRING;
- for(z2=&z[1]; sqlite3Fts5IsBareword(*z2); z2++);
- pToken->n = (z2 - z);
- if( pToken->n==2 && memcmp(pToken->p, "OR", 2)==0 ) tok = FTS5_OR;
- if( pToken->n==3 && memcmp(pToken->p, "NOT", 3)==0 ) tok = FTS5_NOT;
- if( pToken->n==3 && memcmp(pToken->p, "AND", 3)==0 ) tok = FTS5_AND;
- break;
- }
- }
-
- *pz = &pToken->p[pToken->n];
- return tok;
-}
-
-static void *fts5ParseAlloc(u64 t){ return sqlite3_malloc((int)t); }
-static void fts5ParseFree(void *p){ sqlite3_free(p); }
-
-static int sqlite3Fts5ExprNew(
- Fts5Config *pConfig, /* FTS5 Configuration */
- const char *zExpr, /* Expression text */
- Fts5Expr **ppNew,
- char **pzErr
-){
- Fts5Parse sParse;
- Fts5Token token;
- const char *z = zExpr;
- int t; /* Next token type */
- void *pEngine;
- Fts5Expr *pNew;
-
- *ppNew = 0;
- *pzErr = 0;
- memset(&sParse, 0, sizeof(sParse));
- pEngine = sqlite3Fts5ParserAlloc(fts5ParseAlloc);
- if( pEngine==0 ){ return SQLITE_NOMEM; }
- sParse.pConfig = pConfig;
-
- do {
- t = fts5ExprGetToken(&sParse, &z, &token);
- sqlite3Fts5Parser(pEngine, t, token, &sParse);
- }while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
- sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
-
- assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 );
- if( sParse.rc==SQLITE_OK ){
- *ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr));
- if( pNew==0 ){
- sParse.rc = SQLITE_NOMEM;
- sqlite3Fts5ParseNodeFree(sParse.pExpr);
- }else{
- if( !sParse.pExpr ){
- const int nByte = sizeof(Fts5ExprNode);
- pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&sParse.rc, nByte);
- if( pNew->pRoot ){
- pNew->pRoot->bEof = 1;
- }
- }else{
- pNew->pRoot = sParse.pExpr;
- }
- pNew->pIndex = 0;
- pNew->pConfig = pConfig;
- pNew->apExprPhrase = sParse.apPhrase;
- pNew->nPhrase = sParse.nPhrase;
- sParse.apPhrase = 0;
- }
- }else{
- sqlite3Fts5ParseNodeFree(sParse.pExpr);
- }
-
- sqlite3_free(sParse.apPhrase);
- *pzErr = sParse.zErr;
- return sParse.rc;
-}
-
-/*
-** Free the expression node object passed as the only argument.
-*/
-static void sqlite3Fts5ParseNodeFree(Fts5ExprNode *p){
- if( p ){
- int i;
- for(i=0; i<p->nChild; i++){
- sqlite3Fts5ParseNodeFree(p->apChild[i]);
- }
- sqlite3Fts5ParseNearsetFree(p->pNear);
- sqlite3_free(p);
- }
-}
-
-/*
-** Free the expression object passed as the only argument.
-*/
-static void sqlite3Fts5ExprFree(Fts5Expr *p){
- if( p ){
- sqlite3Fts5ParseNodeFree(p->pRoot);
- sqlite3_free(p->apExprPhrase);
- sqlite3_free(p);
- }
-}
-
-/*
-** Argument pTerm must be a synonym iterator. Return the current rowid
-** that it points to.
-*/
-static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){
- i64 iRet = 0;
- int bRetValid = 0;
- Fts5ExprTerm *p;
-
- assert( pTerm->pSynonym );
- assert( bDesc==0 || bDesc==1 );
- for(p=pTerm; p; p=p->pSynonym){
- if( 0==sqlite3Fts5IterEof(p->pIter) ){
- i64 iRowid = p->pIter->iRowid;
- if( bRetValid==0 || (bDesc!=(iRowid<iRet)) ){
- iRet = iRowid;
- bRetValid = 1;
- }
- }
- }
-
- if( pbEof && bRetValid==0 ) *pbEof = 1;
- return iRet;
-}
-
-/*
-** Argument pTerm must be a synonym iterator.
-*/
-static int fts5ExprSynonymList(
- Fts5ExprTerm *pTerm,
- i64 iRowid,
- Fts5Buffer *pBuf, /* Use this buffer for space if required */
- u8 **pa, int *pn
-){
- Fts5PoslistReader aStatic[4];
- Fts5PoslistReader *aIter = aStatic;
- int nIter = 0;
- int nAlloc = 4;
- int rc = SQLITE_OK;
- Fts5ExprTerm *p;
-
- assert( pTerm->pSynonym );
- for(p=pTerm; p; p=p->pSynonym){
- Fts5IndexIter *pIter = p->pIter;
- if( sqlite3Fts5IterEof(pIter)==0 && pIter->iRowid==iRowid ){
- if( pIter->nData==0 ) continue;
- if( nIter==nAlloc ){
- int nByte = sizeof(Fts5PoslistReader) * nAlloc * 2;
- Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc(nByte);
- if( aNew==0 ){
- rc = SQLITE_NOMEM;
- goto synonym_poslist_out;
- }
- memcpy(aNew, aIter, sizeof(Fts5PoslistReader) * nIter);
- nAlloc = nAlloc*2;
- if( aIter!=aStatic ) sqlite3_free(aIter);
- aIter = aNew;
- }
- sqlite3Fts5PoslistReaderInit(pIter->pData, pIter->nData, &aIter[nIter]);
- assert( aIter[nIter].bEof==0 );
- nIter++;
- }
- }
-
- if( nIter==1 ){
- *pa = (u8*)aIter[0].a;
- *pn = aIter[0].n;
- }else{
- Fts5PoslistWriter writer = {0};
- i64 iPrev = -1;
- fts5BufferZero(pBuf);
- while( 1 ){
- int i;
- i64 iMin = FTS5_LARGEST_INT64;
- for(i=0; i<nIter; i++){
- if( aIter[i].bEof==0 ){
- if( aIter[i].iPos==iPrev ){
- if( sqlite3Fts5PoslistReaderNext(&aIter[i]) ) continue;
- }
- if( aIter[i].iPos<iMin ){
- iMin = aIter[i].iPos;
- }
- }
- }
- if( iMin==FTS5_LARGEST_INT64 || rc!=SQLITE_OK ) break;
- rc = sqlite3Fts5PoslistWriterAppend(pBuf, &writer, iMin);
- iPrev = iMin;
- }
- if( rc==SQLITE_OK ){
- *pa = pBuf->p;
- *pn = pBuf->n;
- }
- }
-
- synonym_poslist_out:
- if( aIter!=aStatic ) sqlite3_free(aIter);
- return rc;
-}
-
-
-/*
-** All individual term iterators in pPhrase are guaranteed to be valid and
-** pointing to the same rowid when this function is called. This function
-** checks if the current rowid really is a match, and if so populates
-** the pPhrase->poslist buffer accordingly. Output parameter *pbMatch
-** is set to true if this is really a match, or false otherwise.
-**
-** SQLITE_OK is returned if an error occurs, or an SQLite error code
-** otherwise. It is not considered an error code if the current rowid is
-** not a match.
-*/
-static int fts5ExprPhraseIsMatch(
- Fts5ExprNode *pNode, /* Node pPhrase belongs to */
- Fts5ExprPhrase *pPhrase, /* Phrase object to initialize */
- int *pbMatch /* OUT: Set to true if really a match */
-){
- Fts5PoslistWriter writer = {0};
- Fts5PoslistReader aStatic[4];
- Fts5PoslistReader *aIter = aStatic;
- int i;
- int rc = SQLITE_OK;
-
- fts5BufferZero(&pPhrase->poslist);
-
- /* If the aStatic[] array is not large enough, allocate a large array
- ** using sqlite3_malloc(). This approach could be improved upon. */
- if( pPhrase->nTerm>ArraySize(aStatic) ){
- int nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm;
- aIter = (Fts5PoslistReader*)sqlite3_malloc(nByte);
- if( !aIter ) return SQLITE_NOMEM;
- }
- memset(aIter, 0, sizeof(Fts5PoslistReader) * pPhrase->nTerm);
-
- /* Initialize a term iterator for each term in the phrase */
- for(i=0; i<pPhrase->nTerm; i++){
- Fts5ExprTerm *pTerm = &pPhrase->aTerm[i];
- int n = 0;
- int bFlag = 0;
- u8 *a = 0;
- if( pTerm->pSynonym ){
- Fts5Buffer buf = {0, 0, 0};
- rc = fts5ExprSynonymList(pTerm, pNode->iRowid, &buf, &a, &n);
- if( rc ){
- sqlite3_free(a);
- goto ismatch_out;
- }
- if( a==buf.p ) bFlag = 1;
- }else{
- a = (u8*)pTerm->pIter->pData;
- n = pTerm->pIter->nData;
- }
- sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
- aIter[i].bFlag = (u8)bFlag;
- if( aIter[i].bEof ) goto ismatch_out;
- }
-
- while( 1 ){
- int bMatch;
- i64 iPos = aIter[0].iPos;
- do {
- bMatch = 1;
- for(i=0; i<pPhrase->nTerm; i++){
- Fts5PoslistReader *pPos = &aIter[i];
- i64 iAdj = iPos + i;
- if( pPos->iPos!=iAdj ){
- bMatch = 0;
- while( pPos->iPos<iAdj ){
- if( sqlite3Fts5PoslistReaderNext(pPos) ) goto ismatch_out;
- }
- if( pPos->iPos>iAdj ) iPos = pPos->iPos-i;
- }
- }
- }while( bMatch==0 );
-
- /* Append position iPos to the output */
- rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos);
- if( rc!=SQLITE_OK ) goto ismatch_out;
-
- for(i=0; i<pPhrase->nTerm; i++){
- if( sqlite3Fts5PoslistReaderNext(&aIter[i]) ) goto ismatch_out;
- }
- }
-
- ismatch_out:
- *pbMatch = (pPhrase->poslist.n>0);
- for(i=0; i<pPhrase->nTerm; i++){
- if( aIter[i].bFlag ) sqlite3_free((u8*)aIter[i].a);
- }
- if( aIter!=aStatic ) sqlite3_free(aIter);
- return rc;
-}
-
-typedef struct Fts5LookaheadReader Fts5LookaheadReader;
-struct Fts5LookaheadReader {
- const u8 *a; /* Buffer containing position list */
- int n; /* Size of buffer a[] in bytes */
- int i; /* Current offset in position list */
- i64 iPos; /* Current position */
- i64 iLookahead; /* Next position */
-};
-
-#define FTS5_LOOKAHEAD_EOF (((i64)1) << 62)
-
-static int fts5LookaheadReaderNext(Fts5LookaheadReader *p){
- p->iPos = p->iLookahead;
- if( sqlite3Fts5PoslistNext64(p->a, p->n, &p->i, &p->iLookahead) ){
- p->iLookahead = FTS5_LOOKAHEAD_EOF;
- }
- return (p->iPos==FTS5_LOOKAHEAD_EOF);
-}
-
-static int fts5LookaheadReaderInit(
- const u8 *a, int n, /* Buffer to read position list from */
- Fts5LookaheadReader *p /* Iterator object to initialize */
-){
- memset(p, 0, sizeof(Fts5LookaheadReader));
- p->a = a;
- p->n = n;
- fts5LookaheadReaderNext(p);
- return fts5LookaheadReaderNext(p);
-}
-
-typedef struct Fts5NearTrimmer Fts5NearTrimmer;
-struct Fts5NearTrimmer {
- Fts5LookaheadReader reader; /* Input iterator */
- Fts5PoslistWriter writer; /* Writer context */
- Fts5Buffer *pOut; /* Output poslist */
-};
-
-/*
-** The near-set object passed as the first argument contains more than
-** one phrase. All phrases currently point to the same row. The
-** Fts5ExprPhrase.poslist buffers are populated accordingly. This function
-** tests if the current row contains instances of each phrase sufficiently
-** close together to meet the NEAR constraint. Non-zero is returned if it
-** does, or zero otherwise.
-**
-** If in/out parameter (*pRc) is set to other than SQLITE_OK when this
-** function is called, it is a no-op. Or, if an error (e.g. SQLITE_NOMEM)
-** occurs within this function (*pRc) is set accordingly before returning.
-** The return value is undefined in both these cases.
-**
-** If no error occurs and non-zero (a match) is returned, the position-list
-** of each phrase object is edited to contain only those entries that
-** meet the constraint before returning.
-*/
-static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){
- Fts5NearTrimmer aStatic[4];
- Fts5NearTrimmer *a = aStatic;
- Fts5ExprPhrase **apPhrase = pNear->apPhrase;
-
- int i;
- int rc = *pRc;
- int bMatch;
-
- assert( pNear->nPhrase>1 );
-
- /* If the aStatic[] array is not large enough, allocate a large array
- ** using sqlite3_malloc(). This approach could be improved upon. */
- if( pNear->nPhrase>ArraySize(aStatic) ){
- int nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase;
- a = (Fts5NearTrimmer*)sqlite3Fts5MallocZero(&rc, nByte);
- }else{
- memset(aStatic, 0, sizeof(aStatic));
- }
- if( rc!=SQLITE_OK ){
- *pRc = rc;
- return 0;
- }
-
- /* Initialize a lookahead iterator for each phrase. After passing the
- ** buffer and buffer size to the lookaside-reader init function, zero
- ** the phrase poslist buffer. The new poslist for the phrase (containing
- ** the same entries as the original with some entries removed on account
- ** of the NEAR constraint) is written over the original even as it is
- ** being read. This is safe as the entries for the new poslist are a
- ** subset of the old, so it is not possible for data yet to be read to
- ** be overwritten. */
- for(i=0; i<pNear->nPhrase; i++){
- Fts5Buffer *pPoslist = &apPhrase[i]->poslist;
- fts5LookaheadReaderInit(pPoslist->p, pPoslist->n, &a[i].reader);
- pPoslist->n = 0;
- a[i].pOut = pPoslist;
- }
-
- while( 1 ){
- int iAdv;
- i64 iMin;
- i64 iMax;
-
- /* This block advances the phrase iterators until they point to a set of
- ** entries that together comprise a match. */
- iMax = a[0].reader.iPos;
- do {
- bMatch = 1;
- for(i=0; i<pNear->nPhrase; i++){
- Fts5LookaheadReader *pPos = &a[i].reader;
- iMin = iMax - pNear->apPhrase[i]->nTerm - pNear->nNear;
- if( pPos->iPos<iMin || pPos->iPos>iMax ){
- bMatch = 0;
- while( pPos->iPos<iMin ){
- if( fts5LookaheadReaderNext(pPos) ) goto ismatch_out;
- }
- if( pPos->iPos>iMax ) iMax = pPos->iPos;
- }
- }
- }while( bMatch==0 );
-
- /* Add an entry to each output position list */
- for(i=0; i<pNear->nPhrase; i++){
- i64 iPos = a[i].reader.iPos;
- Fts5PoslistWriter *pWriter = &a[i].writer;
- if( a[i].pOut->n==0 || iPos!=pWriter->iPrev ){
- sqlite3Fts5PoslistWriterAppend(a[i].pOut, pWriter, iPos);
- }
- }
-
- iAdv = 0;
- iMin = a[0].reader.iLookahead;
- for(i=0; i<pNear->nPhrase; i++){
- if( a[i].reader.iLookahead < iMin ){
- iMin = a[i].reader.iLookahead;
- iAdv = i;
- }
- }
- if( fts5LookaheadReaderNext(&a[iAdv].reader) ) goto ismatch_out;
- }
-
- ismatch_out: {
- int bRet = a[0].pOut->n>0;
- *pRc = rc;
- if( a!=aStatic ) sqlite3_free(a);
- return bRet;
- }
-}
-
-/*
-** Advance iterator pIter until it points to a value equal to or laster
-** than the initial value of *piLast. If this means the iterator points
-** to a value laster than *piLast, update *piLast to the new lastest value.
-**
-** If the iterator reaches EOF, set *pbEof to true before returning. If
-** an error occurs, set *pRc to an error code. If either *pbEof or *pRc
-** are set, return a non-zero value. Otherwise, return zero.
-*/
-static int fts5ExprAdvanceto(
- Fts5IndexIter *pIter, /* Iterator to advance */
- int bDesc, /* True if iterator is "rowid DESC" */
- i64 *piLast, /* IN/OUT: Lastest rowid seen so far */
- int *pRc, /* OUT: Error code */
- int *pbEof /* OUT: Set to true if EOF */
-){
- i64 iLast = *piLast;
- i64 iRowid;
-
- iRowid = pIter->iRowid;
- if( (bDesc==0 && iLast>iRowid) || (bDesc && iLast<iRowid) ){
- int rc = sqlite3Fts5IterNextFrom(pIter, iLast);
- if( rc || sqlite3Fts5IterEof(pIter) ){
- *pRc = rc;
- *pbEof = 1;
- return 1;
- }
- iRowid = pIter->iRowid;
- assert( (bDesc==0 && iRowid>=iLast) || (bDesc==1 && iRowid<=iLast) );
- }
- *piLast = iRowid;
-
- return 0;
-}
-
-static int fts5ExprSynonymAdvanceto(
- Fts5ExprTerm *pTerm, /* Term iterator to advance */
- int bDesc, /* True if iterator is "rowid DESC" */
- i64 *piLast, /* IN/OUT: Lastest rowid seen so far */
- int *pRc /* OUT: Error code */
-){
- int rc = SQLITE_OK;
- i64 iLast = *piLast;
- Fts5ExprTerm *p;
- int bEof = 0;
-
- for(p=pTerm; rc==SQLITE_OK && p; p=p->pSynonym){
- if( sqlite3Fts5IterEof(p->pIter)==0 ){
- i64 iRowid = p->pIter->iRowid;
- if( (bDesc==0 && iLast>iRowid) || (bDesc && iLast<iRowid) ){
- rc = sqlite3Fts5IterNextFrom(p->pIter, iLast);
- }
- }
- }
-
- if( rc!=SQLITE_OK ){
- *pRc = rc;
- bEof = 1;
- }else{
- *piLast = fts5ExprSynonymRowid(pTerm, bDesc, &bEof);
- }
- return bEof;
-}
-
-
-static int fts5ExprNearTest(
- int *pRc,
- Fts5Expr *pExpr, /* Expression that pNear is a part of */
- Fts5ExprNode *pNode /* The "NEAR" node (FTS5_STRING) */
-){
- Fts5ExprNearset *pNear = pNode->pNear;
- int rc = *pRc;
-
- if( pExpr->pConfig->eDetail!=FTS5_DETAIL_FULL ){
- Fts5ExprTerm *pTerm;
- Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
- pPhrase->poslist.n = 0;
- for(pTerm=&pPhrase->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){
- Fts5IndexIter *pIter = pTerm->pIter;
- if( sqlite3Fts5IterEof(pIter)==0 ){
- if( pIter->iRowid==pNode->iRowid && pIter->nData>0 ){
- pPhrase->poslist.n = 1;
- }
- }
- }
- return pPhrase->poslist.n;
- }else{
- int i;
-
- /* Check that each phrase in the nearset matches the current row.
- ** Populate the pPhrase->poslist buffers at the same time. If any
- ** phrase is not a match, break out of the loop early. */
- for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
- Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
- if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){
- int bMatch = 0;
- rc = fts5ExprPhraseIsMatch(pNode, pPhrase, &bMatch);
- if( bMatch==0 ) break;
- }else{
- Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter;
- fts5BufferSet(&rc, &pPhrase->poslist, pIter->nData, pIter->pData);
- }
- }
-
- *pRc = rc;
- if( i==pNear->nPhrase && (i==1 || fts5ExprNearIsMatch(pRc, pNear)) ){
- return 1;
- }
- return 0;
- }
-}
-
-
-/*
-** Initialize all term iterators in the pNear object. If any term is found
-** to match no documents at all, return immediately without initializing any
-** further iterators.
-*/
-static int fts5ExprNearInitAll(
- Fts5Expr *pExpr,
- Fts5ExprNode *pNode
-){
- Fts5ExprNearset *pNear = pNode->pNear;
- int i, j;
- int rc = SQLITE_OK;
-
- assert( pNode->bNomatch==0 );
- for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
- Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
- for(j=0; j<pPhrase->nTerm; j++){
- Fts5ExprTerm *pTerm = &pPhrase->aTerm[j];
- Fts5ExprTerm *p;
- int bEof = 1;
-
- for(p=pTerm; p && rc==SQLITE_OK; p=p->pSynonym){
- if( p->pIter ){
- sqlite3Fts5IterClose(p->pIter);
- p->pIter = 0;
- }
- rc = sqlite3Fts5IndexQuery(
- pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm),
- (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
- (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0),
- pNear->pColset,
- &p->pIter
- );
- assert( rc==SQLITE_OK || p->pIter==0 );
- if( p->pIter && 0==sqlite3Fts5IterEof(p->pIter) ){
- bEof = 0;
- }
- }
-
- if( bEof ){
- pNode->bEof = 1;
- return rc;
- }
- }
- }
-
- return rc;
-}
-
-/*
-** If pExpr is an ASC iterator, this function returns a value with the
-** same sign as:
-**
-** (iLhs - iRhs)
-**
-** Otherwise, if this is a DESC iterator, the opposite is returned:
-**
-** (iRhs - iLhs)
-*/
-static int fts5RowidCmp(
- Fts5Expr *pExpr,
- i64 iLhs,
- i64 iRhs
-){
- assert( pExpr->bDesc==0 || pExpr->bDesc==1 );
- if( pExpr->bDesc==0 ){
- if( iLhs<iRhs ) return -1;
- return (iLhs > iRhs);
- }else{
- if( iLhs>iRhs ) return -1;
- return (iLhs < iRhs);
- }
-}
-
-static void fts5ExprSetEof(Fts5ExprNode *pNode){
- int i;
- pNode->bEof = 1;
- pNode->bNomatch = 0;
- for(i=0; i<pNode->nChild; i++){
- fts5ExprSetEof(pNode->apChild[i]);
- }
-}
-
-static void fts5ExprNodeZeroPoslist(Fts5ExprNode *pNode){
- if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){
- Fts5ExprNearset *pNear = pNode->pNear;
- int i;
- for(i=0; i<pNear->nPhrase; i++){
- Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
- pPhrase->poslist.n = 0;
- }
- }else{
- int i;
- for(i=0; i<pNode->nChild; i++){
- fts5ExprNodeZeroPoslist(pNode->apChild[i]);
- }
- }
-}
-
-
-
-/*
-** Compare the values currently indicated by the two nodes as follows:
-**
-** res = (*p1) - (*p2)
-**
-** Nodes that point to values that come later in the iteration order are
-** considered to be larger. Nodes at EOF are the largest of all.
-**
-** This means that if the iteration order is ASC, then numerically larger
-** rowids are considered larger. Or if it is the default DESC, numerically
-** smaller rowids are larger.
-*/
-static int fts5NodeCompare(
- Fts5Expr *pExpr,
- Fts5ExprNode *p1,
- Fts5ExprNode *p2
-){
- if( p2->bEof ) return -1;
- if( p1->bEof ) return +1;
- return fts5RowidCmp(pExpr, p1->iRowid, p2->iRowid);
-}
-
-/*
-** All individual term iterators in pNear are guaranteed to be valid when
-** this function is called. This function checks if all term iterators
-** point to the same rowid, and if not, advances them until they do.
-** If an EOF is reached before this happens, *pbEof is set to true before
-** returning.
-**
-** SQLITE_OK is returned if an error occurs, or an SQLite error code
-** otherwise. It is not considered an error code if an iterator reaches
-** EOF.
-*/
-static int fts5ExprNodeTest_STRING(
- Fts5Expr *pExpr, /* Expression pPhrase belongs to */
- Fts5ExprNode *pNode
-){
- Fts5ExprNearset *pNear = pNode->pNear;
- Fts5ExprPhrase *pLeft = pNear->apPhrase[0];
- int rc = SQLITE_OK;
- i64 iLast; /* Lastest rowid any iterator points to */
- int i, j; /* Phrase and token index, respectively */
- int bMatch; /* True if all terms are at the same rowid */
- const int bDesc = pExpr->bDesc;
-
- /* Check that this node should not be FTS5_TERM */
- assert( pNear->nPhrase>1
- || pNear->apPhrase[0]->nTerm>1
- || pNear->apPhrase[0]->aTerm[0].pSynonym
- );
-
- /* Initialize iLast, the "lastest" rowid any iterator points to. If the
- ** iterator skips through rowids in the default ascending order, this means
- ** the maximum rowid. Or, if the iterator is "ORDER BY rowid DESC", then it
- ** means the minimum rowid. */
- if( pLeft->aTerm[0].pSynonym ){
- iLast = fts5ExprSynonymRowid(&pLeft->aTerm[0], bDesc, 0);
- }else{
- iLast = pLeft->aTerm[0].pIter->iRowid;
- }
-
- do {
- bMatch = 1;
- for(i=0; i<pNear->nPhrase; i++){
- Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
- for(j=0; j<pPhrase->nTerm; j++){
- Fts5ExprTerm *pTerm = &pPhrase->aTerm[j];
- if( pTerm->pSynonym ){
- i64 iRowid = fts5ExprSynonymRowid(pTerm, bDesc, 0);
- if( iRowid==iLast ) continue;
- bMatch = 0;
- if( fts5ExprSynonymAdvanceto(pTerm, bDesc, &iLast, &rc) ){
- pNode->bNomatch = 0;
- pNode->bEof = 1;
- return rc;
- }
- }else{
- Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter;
- if( pIter->iRowid==iLast ) continue;
- bMatch = 0;
- if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){
- return rc;
- }
- }
- }
- }
- }while( bMatch==0 );
-
- pNode->iRowid = iLast;
- pNode->bNomatch = ((0==fts5ExprNearTest(&rc, pExpr, pNode)) && rc==SQLITE_OK);
- assert( pNode->bEof==0 || pNode->bNomatch==0 );
-
- return rc;
-}
-
-/*
-** Advance the first term iterator in the first phrase of pNear. Set output
-** variable *pbEof to true if it reaches EOF or if an error occurs.
-**
-** Return SQLITE_OK if successful, or an SQLite error code if an error
-** occurs.
-*/
-static int fts5ExprNodeNext_STRING(
- Fts5Expr *pExpr, /* Expression pPhrase belongs to */
- Fts5ExprNode *pNode, /* FTS5_STRING or FTS5_TERM node */
- int bFromValid,
- i64 iFrom
-){
- Fts5ExprTerm *pTerm = &pNode->pNear->apPhrase[0]->aTerm[0];
- int rc = SQLITE_OK;
-
- pNode->bNomatch = 0;
- if( pTerm->pSynonym ){
- int bEof = 1;
- Fts5ExprTerm *p;
-
- /* Find the firstest rowid any synonym points to. */
- i64 iRowid = fts5ExprSynonymRowid(pTerm, pExpr->bDesc, 0);
-
- /* Advance each iterator that currently points to iRowid. Or, if iFrom
- ** is valid - each iterator that points to a rowid before iFrom. */
- for(p=pTerm; p; p=p->pSynonym){
- if( sqlite3Fts5IterEof(p->pIter)==0 ){
- i64 ii = p->pIter->iRowid;
- if( ii==iRowid
- || (bFromValid && ii!=iFrom && (ii>iFrom)==pExpr->bDesc)
- ){
- if( bFromValid ){
- rc = sqlite3Fts5IterNextFrom(p->pIter, iFrom);
- }else{
- rc = sqlite3Fts5IterNext(p->pIter);
- }
- if( rc!=SQLITE_OK ) break;
- if( sqlite3Fts5IterEof(p->pIter)==0 ){
- bEof = 0;
- }
- }else{
- bEof = 0;
- }
- }
- }
-
- /* Set the EOF flag if either all synonym iterators are at EOF or an
- ** error has occurred. */
- pNode->bEof = (rc || bEof);
- }else{
- Fts5IndexIter *pIter = pTerm->pIter;
-
- assert( Fts5NodeIsString(pNode) );
- if( bFromValid ){
- rc = sqlite3Fts5IterNextFrom(pIter, iFrom);
- }else{
- rc = sqlite3Fts5IterNext(pIter);
- }
-
- pNode->bEof = (rc || sqlite3Fts5IterEof(pIter));
- }
-
- if( pNode->bEof==0 ){
- assert( rc==SQLITE_OK );
- rc = fts5ExprNodeTest_STRING(pExpr, pNode);
- }
-
- return rc;
-}
-
-
-static int fts5ExprNodeTest_TERM(
- Fts5Expr *pExpr, /* Expression that pNear is a part of */
- Fts5ExprNode *pNode /* The "NEAR" node (FTS5_TERM) */
-){
- /* As this "NEAR" object is actually a single phrase that consists
- ** of a single term only, grab pointers into the poslist managed by the
- ** fts5_index.c iterator object. This is much faster than synthesizing
- ** a new poslist the way we have to for more complicated phrase or NEAR
- ** expressions. */
- Fts5ExprPhrase *pPhrase = pNode->pNear->apPhrase[0];
- Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter;
-
- assert( pNode->eType==FTS5_TERM );
- assert( pNode->pNear->nPhrase==1 && pPhrase->nTerm==1 );
- assert( pPhrase->aTerm[0].pSynonym==0 );
-
- pPhrase->poslist.n = pIter->nData;
- if( pExpr->pConfig->eDetail==FTS5_DETAIL_FULL ){
- pPhrase->poslist.p = (u8*)pIter->pData;
- }
- pNode->iRowid = pIter->iRowid;
- pNode->bNomatch = (pPhrase->poslist.n==0);
- return SQLITE_OK;
-}
-
-/*
-** xNext() method for a node of type FTS5_TERM.
-*/
-static int fts5ExprNodeNext_TERM(
- Fts5Expr *pExpr,
- Fts5ExprNode *pNode,
- int bFromValid,
- i64 iFrom
-){
- int rc;
- Fts5IndexIter *pIter = pNode->pNear->apPhrase[0]->aTerm[0].pIter;
-
- assert( pNode->bEof==0 );
- if( bFromValid ){
- rc = sqlite3Fts5IterNextFrom(pIter, iFrom);
- }else{
- rc = sqlite3Fts5IterNext(pIter);
- }
- if( rc==SQLITE_OK && sqlite3Fts5IterEof(pIter)==0 ){
- rc = fts5ExprNodeTest_TERM(pExpr, pNode);
- }else{
- pNode->bEof = 1;
- pNode->bNomatch = 0;
- }
- return rc;
-}
-
-static void fts5ExprNodeTest_OR(
- Fts5Expr *pExpr, /* Expression of which pNode is a part */
- Fts5ExprNode *pNode /* Expression node to test */
-){
- Fts5ExprNode *pNext = pNode->apChild[0];
- int i;
-
- for(i=1; i<pNode->nChild; i++){
- Fts5ExprNode *pChild = pNode->apChild[i];
- int cmp = fts5NodeCompare(pExpr, pNext, pChild);
- if( cmp>0 || (cmp==0 && pChild->bNomatch==0) ){
- pNext = pChild;
- }
- }
- pNode->iRowid = pNext->iRowid;
- pNode->bEof = pNext->bEof;
- pNode->bNomatch = pNext->bNomatch;
-}
-
-static int fts5ExprNodeNext_OR(
- Fts5Expr *pExpr,
- Fts5ExprNode *pNode,
- int bFromValid,
- i64 iFrom
-){
- int i;
- i64 iLast = pNode->iRowid;
-
- for(i=0; i<pNode->nChild; i++){
- Fts5ExprNode *p1 = pNode->apChild[i];
- assert( p1->bEof || fts5RowidCmp(pExpr, p1->iRowid, iLast)>=0 );
- if( p1->bEof==0 ){
- if( (p1->iRowid==iLast)
- || (bFromValid && fts5RowidCmp(pExpr, p1->iRowid, iFrom)<0)
- ){
- int rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom);
- if( rc!=SQLITE_OK ) return rc;
- }
- }
- }
-
- fts5ExprNodeTest_OR(pExpr, pNode);
- return SQLITE_OK;
-}
-
-/*
-** Argument pNode is an FTS5_AND node.
-*/
-static int fts5ExprNodeTest_AND(
- Fts5Expr *pExpr, /* Expression pPhrase belongs to */
- Fts5ExprNode *pAnd /* FTS5_AND node to advance */
-){
- int iChild;
- i64 iLast = pAnd->iRowid;
- int rc = SQLITE_OK;
- int bMatch;
-
- assert( pAnd->bEof==0 );
- do {
- pAnd->bNomatch = 0;
- bMatch = 1;
- for(iChild=0; iChild<pAnd->nChild; iChild++){
- Fts5ExprNode *pChild = pAnd->apChild[iChild];
- int cmp = fts5RowidCmp(pExpr, iLast, pChild->iRowid);
- if( cmp>0 ){
- /* Advance pChild until it points to iLast or laster */
- rc = fts5ExprNodeNext(pExpr, pChild, 1, iLast);
- if( rc!=SQLITE_OK ) return rc;
- }
-
- /* If the child node is now at EOF, so is the parent AND node. Otherwise,
- ** the child node is guaranteed to have advanced at least as far as
- ** rowid iLast. So if it is not at exactly iLast, pChild->iRowid is the
- ** new lastest rowid seen so far. */
- assert( pChild->bEof || fts5RowidCmp(pExpr, iLast, pChild->iRowid)<=0 );
- if( pChild->bEof ){
- fts5ExprSetEof(pAnd);
- bMatch = 1;
- break;
- }else if( iLast!=pChild->iRowid ){
- bMatch = 0;
- iLast = pChild->iRowid;
- }
-
- if( pChild->bNomatch ){
- pAnd->bNomatch = 1;
- }
- }
- }while( bMatch==0 );
-
- if( pAnd->bNomatch && pAnd!=pExpr->pRoot ){
- fts5ExprNodeZeroPoslist(pAnd);
- }
- pAnd->iRowid = iLast;
- return SQLITE_OK;
-}
-
-static int fts5ExprNodeNext_AND(
- Fts5Expr *pExpr,
- Fts5ExprNode *pNode,
- int bFromValid,
- i64 iFrom
-){
- int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom);
- if( rc==SQLITE_OK ){
- rc = fts5ExprNodeTest_AND(pExpr, pNode);
- }
- return rc;
-}
-
-static int fts5ExprNodeTest_NOT(
- Fts5Expr *pExpr, /* Expression pPhrase belongs to */
- Fts5ExprNode *pNode /* FTS5_NOT node to advance */
-){
- int rc = SQLITE_OK;
- Fts5ExprNode *p1 = pNode->apChild[0];
- Fts5ExprNode *p2 = pNode->apChild[1];
- assert( pNode->nChild==2 );
-
- while( rc==SQLITE_OK && p1->bEof==0 ){
- int cmp = fts5NodeCompare(pExpr, p1, p2);
- if( cmp>0 ){
- rc = fts5ExprNodeNext(pExpr, p2, 1, p1->iRowid);
- cmp = fts5NodeCompare(pExpr, p1, p2);
- }
- assert( rc!=SQLITE_OK || cmp<=0 );
- if( cmp || p2->bNomatch ) break;
- rc = fts5ExprNodeNext(pExpr, p1, 0, 0);
- }
- pNode->bEof = p1->bEof;
- pNode->bNomatch = p1->bNomatch;
- pNode->iRowid = p1->iRowid;
- if( p1->bEof ){
- fts5ExprNodeZeroPoslist(p2);
- }
- return rc;
-}
-
-static int fts5ExprNodeNext_NOT(
- Fts5Expr *pExpr,
- Fts5ExprNode *pNode,
- int bFromValid,
- i64 iFrom
-){
- int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom);
- if( rc==SQLITE_OK ){
- rc = fts5ExprNodeTest_NOT(pExpr, pNode);
- }
- return rc;
-}
-
-/*
-** If pNode currently points to a match, this function returns SQLITE_OK
-** without modifying it. Otherwise, pNode is advanced until it does point
-** to a match or EOF is reached.
-*/
-static int fts5ExprNodeTest(
- Fts5Expr *pExpr, /* Expression of which pNode is a part */
- Fts5ExprNode *pNode /* Expression node to test */
-){
- int rc = SQLITE_OK;
- if( pNode->bEof==0 ){
- switch( pNode->eType ){
-
- case FTS5_STRING: {
- rc = fts5ExprNodeTest_STRING(pExpr, pNode);
- break;
- }
-
- case FTS5_TERM: {
- rc = fts5ExprNodeTest_TERM(pExpr, pNode);
- break;
- }
-
- case FTS5_AND: {
- rc = fts5ExprNodeTest_AND(pExpr, pNode);
- break;
- }
-
- case FTS5_OR: {
- fts5ExprNodeTest_OR(pExpr, pNode);
- break;
- }
-
- default: assert( pNode->eType==FTS5_NOT ); {
- rc = fts5ExprNodeTest_NOT(pExpr, pNode);
- break;
- }
- }
- }
- return rc;
-}
-
-
-/*
-** Set node pNode, which is part of expression pExpr, to point to the first
-** match. If there are no matches, set the Node.bEof flag to indicate EOF.
-**
-** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise.
-** It is not an error if there are no matches.
-*/
-static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){
- int rc = SQLITE_OK;
- pNode->bEof = 0;
- pNode->bNomatch = 0;
-
- if( Fts5NodeIsString(pNode) ){
- /* Initialize all term iterators in the NEAR object. */
- rc = fts5ExprNearInitAll(pExpr, pNode);
- }else if( pNode->xNext==0 ){
- pNode->bEof = 1;
- }else{
- int i;
- int nEof = 0;
- for(i=0; i<pNode->nChild && rc==SQLITE_OK; i++){
- Fts5ExprNode *pChild = pNode->apChild[i];
- rc = fts5ExprNodeFirst(pExpr, pNode->apChild[i]);
- assert( pChild->bEof==0 || pChild->bEof==1 );
- nEof += pChild->bEof;
- }
- pNode->iRowid = pNode->apChild[0]->iRowid;
-
- switch( pNode->eType ){
- case FTS5_AND:
- if( nEof>0 ) fts5ExprSetEof(pNode);
- break;
-
- case FTS5_OR:
- if( pNode->nChild==nEof ) fts5ExprSetEof(pNode);
- break;
-
- default:
- assert( pNode->eType==FTS5_NOT );
- pNode->bEof = pNode->apChild[0]->bEof;
- break;
- }
- }
-
- if( rc==SQLITE_OK ){
- rc = fts5ExprNodeTest(pExpr, pNode);
- }
- return rc;
-}
-
-
-/*
-** Begin iterating through the set of documents in index pIdx matched by
-** the MATCH expression passed as the first argument. If the "bDesc"
-** parameter is passed a non-zero value, iteration is in descending rowid
-** order. Or, if it is zero, in ascending order.
-**
-** If iterating in ascending rowid order (bDesc==0), the first document
-** visited is that with the smallest rowid that is larger than or equal
-** to parameter iFirst. Or, if iterating in ascending order (bDesc==1),
-** then the first document visited must have a rowid smaller than or
-** equal to iFirst.
-**
-** Return SQLITE_OK if successful, or an SQLite error code otherwise. It
-** is not considered an error if the query does not match any documents.
-*/
-static int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bDesc){
- Fts5ExprNode *pRoot = p->pRoot;
- int rc; /* Return code */
-
- p->pIndex = pIdx;
- p->bDesc = bDesc;
- rc = fts5ExprNodeFirst(p, pRoot);
-
- /* If not at EOF but the current rowid occurs earlier than iFirst in
- ** the iteration order, move to document iFirst or later. */
- if( pRoot->bEof==0 && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 ){
- rc = fts5ExprNodeNext(p, pRoot, 1, iFirst);
- }
-
- /* If the iterator is not at a real match, skip forward until it is. */
- while( pRoot->bNomatch ){
- assert( pRoot->bEof==0 && rc==SQLITE_OK );
- rc = fts5ExprNodeNext(p, pRoot, 0, 0);
- }
- return rc;
-}
-
-/*
-** Move to the next document
-**
-** Return SQLITE_OK if successful, or an SQLite error code otherwise. It
-** is not considered an error if the query does not match any documents.
-*/
-static int sqlite3Fts5ExprNext(Fts5Expr *p, i64 iLast){
- int rc;
- Fts5ExprNode *pRoot = p->pRoot;
- assert( pRoot->bEof==0 && pRoot->bNomatch==0 );
- do {
- rc = fts5ExprNodeNext(p, pRoot, 0, 0);
- assert( pRoot->bNomatch==0 || (rc==SQLITE_OK && pRoot->bEof==0) );
- }while( pRoot->bNomatch );
- if( fts5RowidCmp(p, pRoot->iRowid, iLast)>0 ){
- pRoot->bEof = 1;
- }
- return rc;
-}
-
-static int sqlite3Fts5ExprEof(Fts5Expr *p){
- return p->pRoot->bEof;
-}
-
-static i64 sqlite3Fts5ExprRowid(Fts5Expr *p){
- return p->pRoot->iRowid;
-}
-
-static int fts5ParseStringFromToken(Fts5Token *pToken, char **pz){
- int rc = SQLITE_OK;
- *pz = sqlite3Fts5Strndup(&rc, pToken->p, pToken->n);
- return rc;
-}
-
-/*
-** Free the phrase object passed as the only argument.
-*/
-static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){
- if( pPhrase ){
- int i;
- for(i=0; i<pPhrase->nTerm; i++){
- Fts5ExprTerm *pSyn;
- Fts5ExprTerm *pNext;
- Fts5ExprTerm *pTerm = &pPhrase->aTerm[i];
- sqlite3_free(pTerm->zTerm);
- sqlite3Fts5IterClose(pTerm->pIter);
- for(pSyn=pTerm->pSynonym; pSyn; pSyn=pNext){
- pNext = pSyn->pSynonym;
- sqlite3Fts5IterClose(pSyn->pIter);
- fts5BufferFree((Fts5Buffer*)&pSyn[1]);
- sqlite3_free(pSyn);
- }
- }
- if( pPhrase->poslist.nSpace>0 ) fts5BufferFree(&pPhrase->poslist);
- sqlite3_free(pPhrase);
- }
-}
-
-/*
-** If argument pNear is NULL, then a new Fts5ExprNearset object is allocated
-** and populated with pPhrase. Or, if pNear is not NULL, phrase pPhrase is
-** appended to it and the results returned.
-**
-** If an OOM error occurs, both the pNear and pPhrase objects are freed and
-** NULL returned.
-*/
-static Fts5ExprNearset *sqlite3Fts5ParseNearset(
- Fts5Parse *pParse, /* Parse context */
- Fts5ExprNearset *pNear, /* Existing nearset, or NULL */
- Fts5ExprPhrase *pPhrase /* Recently parsed phrase */
-){
- const int SZALLOC = 8;
- Fts5ExprNearset *pRet = 0;
-
- if( pParse->rc==SQLITE_OK ){
- if( pPhrase==0 ){
- return pNear;
- }
- if( pNear==0 ){
- int nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*);
- pRet = sqlite3_malloc(nByte);
- if( pRet==0 ){
- pParse->rc = SQLITE_NOMEM;
- }else{
- memset(pRet, 0, nByte);
- }
- }else if( (pNear->nPhrase % SZALLOC)==0 ){
- int nNew = pNear->nPhrase + SZALLOC;
- int nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*);
-
- pRet = (Fts5ExprNearset*)sqlite3_realloc(pNear, nByte);
- if( pRet==0 ){
- pParse->rc = SQLITE_NOMEM;
- }
- }else{
- pRet = pNear;
- }
- }
-
- if( pRet==0 ){
- assert( pParse->rc!=SQLITE_OK );
- sqlite3Fts5ParseNearsetFree(pNear);
- sqlite3Fts5ParsePhraseFree(pPhrase);
- }else{
- if( pRet->nPhrase>0 ){
- Fts5ExprPhrase *pLast = pRet->apPhrase[pRet->nPhrase-1];
- assert( pLast==pParse->apPhrase[pParse->nPhrase-2] );
- if( pPhrase->nTerm==0 ){
- fts5ExprPhraseFree(pPhrase);
- pRet->nPhrase--;
- pParse->nPhrase--;
- pPhrase = pLast;
- }else if( pLast->nTerm==0 ){
- fts5ExprPhraseFree(pLast);
- pParse->apPhrase[pParse->nPhrase-2] = pPhrase;
- pParse->nPhrase--;
- pRet->nPhrase--;
- }
- }
- pRet->apPhrase[pRet->nPhrase++] = pPhrase;
- }
- return pRet;
-}
-
-typedef struct TokenCtx TokenCtx;
-struct TokenCtx {
- Fts5ExprPhrase *pPhrase;
- int rc;
-};
-
-/*
-** Callback for tokenizing terms used by ParseTerm().
-*/
-static int fts5ParseTokenize(
- void *pContext, /* Pointer to Fts5InsertCtx object */
- int tflags, /* Mask of FTS5_TOKEN_* flags */
- const char *pToken, /* Buffer containing token */
- int nToken, /* Size of token in bytes */
- int iUnused1, /* Start offset of token */
- int iUnused2 /* End offset of token */
-){
- int rc = SQLITE_OK;
- const int SZALLOC = 8;
- TokenCtx *pCtx = (TokenCtx*)pContext;
- Fts5ExprPhrase *pPhrase = pCtx->pPhrase;
-
- UNUSED_PARAM2(iUnused1, iUnused2);
-
- /* If an error has already occurred, this is a no-op */
- if( pCtx->rc!=SQLITE_OK ) return pCtx->rc;
- if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
-
- if( pPhrase && pPhrase->nTerm>0 && (tflags & FTS5_TOKEN_COLOCATED) ){
- Fts5ExprTerm *pSyn;
- int nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1;
- pSyn = (Fts5ExprTerm*)sqlite3_malloc(nByte);
- if( pSyn==0 ){
- rc = SQLITE_NOMEM;
- }else{
- memset(pSyn, 0, nByte);
- pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
- memcpy(pSyn->zTerm, pToken, nToken);
- pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym;
- pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn;
- }
- }else{
- Fts5ExprTerm *pTerm;
- if( pPhrase==0 || (pPhrase->nTerm % SZALLOC)==0 ){
- Fts5ExprPhrase *pNew;
- int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0);
-
- pNew = (Fts5ExprPhrase*)sqlite3_realloc(pPhrase,
- sizeof(Fts5ExprPhrase) + sizeof(Fts5ExprTerm) * nNew
- );
- if( pNew==0 ){
- rc = SQLITE_NOMEM;
- }else{
- if( pPhrase==0 ) memset(pNew, 0, sizeof(Fts5ExprPhrase));
- pCtx->pPhrase = pPhrase = pNew;
- pNew->nTerm = nNew - SZALLOC;
- }
- }
-
- if( rc==SQLITE_OK ){
- pTerm = &pPhrase->aTerm[pPhrase->nTerm++];
- memset(pTerm, 0, sizeof(Fts5ExprTerm));
- pTerm->zTerm = sqlite3Fts5Strndup(&rc, pToken, nToken);
- }
- }
-
- pCtx->rc = rc;
- return rc;
-}
-
-
-/*
-** Free the phrase object passed as the only argument.
-*/
-static void sqlite3Fts5ParsePhraseFree(Fts5ExprPhrase *pPhrase){
- fts5ExprPhraseFree(pPhrase);
-}
-
-/*
-** Free the phrase object passed as the second argument.
-*/
-static void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset *pNear){
- if( pNear ){
- int i;
- for(i=0; i<pNear->nPhrase; i++){
- fts5ExprPhraseFree(pNear->apPhrase[i]);
- }
- sqlite3_free(pNear->pColset);
- sqlite3_free(pNear);
- }
-}
-
-static void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p){
- assert( pParse->pExpr==0 );
- pParse->pExpr = p;
-}
-
-/*
-** This function is called by the parser to process a string token. The
-** string may or may not be quoted. In any case it is tokenized and a
-** phrase object consisting of all tokens returned.
-*/
-static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
- Fts5Parse *pParse, /* Parse context */
- Fts5ExprPhrase *pAppend, /* Phrase to append to */
- Fts5Token *pToken, /* String to tokenize */
- int bPrefix /* True if there is a trailing "*" */
-){
- Fts5Config *pConfig = pParse->pConfig;
- TokenCtx sCtx; /* Context object passed to callback */
- int rc; /* Tokenize return code */
- char *z = 0;
-
- memset(&sCtx, 0, sizeof(TokenCtx));
- sCtx.pPhrase = pAppend;
-
- rc = fts5ParseStringFromToken(pToken, &z);
- if( rc==SQLITE_OK ){
- int flags = FTS5_TOKENIZE_QUERY | (bPrefix ? FTS5_TOKENIZE_QUERY : 0);
- int n;
- sqlite3Fts5Dequote(z);
- n = (int)strlen(z);
- rc = sqlite3Fts5Tokenize(pConfig, flags, z, n, &sCtx, fts5ParseTokenize);
- }
- sqlite3_free(z);
- if( rc || (rc = sCtx.rc) ){
- pParse->rc = rc;
- fts5ExprPhraseFree(sCtx.pPhrase);
- sCtx.pPhrase = 0;
- }else{
-
- if( pAppend==0 ){
- if( (pParse->nPhrase % 8)==0 ){
- int nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8);
- Fts5ExprPhrase **apNew;
- apNew = (Fts5ExprPhrase**)sqlite3_realloc(pParse->apPhrase, nByte);
- if( apNew==0 ){
- pParse->rc = SQLITE_NOMEM;
- fts5ExprPhraseFree(sCtx.pPhrase);
- return 0;
- }
- pParse->apPhrase = apNew;
- }
- pParse->nPhrase++;
- }
-
- if( sCtx.pPhrase==0 ){
- /* This happens when parsing a token or quoted phrase that contains
- ** no token characters at all. (e.g ... MATCH '""'). */
- sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, sizeof(Fts5ExprPhrase));
- }else if( sCtx.pPhrase->nTerm ){
- sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = bPrefix;
- }
- pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase;
- }
-
- return sCtx.pPhrase;
-}
-
-/*
-** Create a new FTS5 expression by cloning phrase iPhrase of the
-** expression passed as the second argument.
-*/
-static int sqlite3Fts5ExprClonePhrase(
- Fts5Expr *pExpr,
- int iPhrase,
- Fts5Expr **ppNew
-){
- int rc = SQLITE_OK; /* Return code */
- Fts5ExprPhrase *pOrig; /* The phrase extracted from pExpr */
- int i; /* Used to iterate through phrase terms */
- Fts5Expr *pNew = 0; /* Expression to return via *ppNew */
- TokenCtx sCtx = {0,0}; /* Context object for fts5ParseTokenize */
-
- pOrig = pExpr->apExprPhrase[iPhrase];
- pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
- if( rc==SQLITE_OK ){
- pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc,
- sizeof(Fts5ExprPhrase*));
- }
- if( rc==SQLITE_OK ){
- pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc,
- sizeof(Fts5ExprNode));
- }
- if( rc==SQLITE_OK ){
- pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc,
- sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*));
- }
- if( rc==SQLITE_OK ){
- Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset;
- if( pColsetOrig ){
- int nByte = sizeof(Fts5Colset) + pColsetOrig->nCol * sizeof(int);
- Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte);
- if( pColset ){
- memcpy(pColset, pColsetOrig, nByte);
- }
- pNew->pRoot->pNear->pColset = pColset;
- }
- }
-
- for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
- int tflags = 0;
- Fts5ExprTerm *p;
- for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
- const char *zTerm = p->zTerm;
- rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm),
- 0, 0);
- tflags = FTS5_TOKEN_COLOCATED;
- }
- if( rc==SQLITE_OK ){
- sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
- }
- }
-
- if( rc==SQLITE_OK ){
- /* All the allocations succeeded. Put the expression object together. */
- pNew->pIndex = pExpr->pIndex;
- pNew->pConfig = pExpr->pConfig;
- pNew->nPhrase = 1;
- pNew->apExprPhrase[0] = sCtx.pPhrase;
- pNew->pRoot->pNear->apPhrase[0] = sCtx.pPhrase;
- pNew->pRoot->pNear->nPhrase = 1;
- sCtx.pPhrase->pNode = pNew->pRoot;
-
- if( pOrig->nTerm==1 && pOrig->aTerm[0].pSynonym==0 ){
- pNew->pRoot->eType = FTS5_TERM;
- pNew->pRoot->xNext = fts5ExprNodeNext_TERM;
- }else{
- pNew->pRoot->eType = FTS5_STRING;
- pNew->pRoot->xNext = fts5ExprNodeNext_STRING;
- }
- }else{
- sqlite3Fts5ExprFree(pNew);
- fts5ExprPhraseFree(sCtx.pPhrase);
- pNew = 0;
- }
-
- *ppNew = pNew;
- return rc;
-}
-
-
-/*
-** Token pTok has appeared in a MATCH expression where the NEAR operator
-** is expected. If token pTok does not contain "NEAR", store an error
-** in the pParse object.
-*/
-static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token *pTok){
- if( pTok->n!=4 || memcmp("NEAR", pTok->p, 4) ){
- sqlite3Fts5ParseError(
- pParse, "fts5: syntax error near \"%.*s\"", pTok->n, pTok->p
- );
- }
-}
-
-static void sqlite3Fts5ParseSetDistance(
- Fts5Parse *pParse,
- Fts5ExprNearset *pNear,
- Fts5Token *p
-){
- if( pNear ){
- int nNear = 0;
- int i;
- if( p->n ){
- for(i=0; i<p->n; i++){
- char c = (char)p->p[i];
- if( c<'0' || c>'9' ){
- sqlite3Fts5ParseError(
- pParse, "expected integer, got \"%.*s\"", p->n, p->p
- );
- return;
- }
- nNear = nNear * 10 + (p->p[i] - '0');
- }
- }else{
- nNear = FTS5_DEFAULT_NEARDIST;
- }
- pNear->nNear = nNear;
- }
-}
-
-/*
-** The second argument passed to this function may be NULL, or it may be
-** an existing Fts5Colset object. This function returns a pointer to
-** a new colset object containing the contents of (p) with new value column
-** number iCol appended.
-**
-** If an OOM error occurs, store an error code in pParse and return NULL.
-** The old colset object (if any) is not freed in this case.
-*/
-static Fts5Colset *fts5ParseColset(
- Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */
- Fts5Colset *p, /* Existing colset object */
- int iCol /* New column to add to colset object */
-){
- int nCol = p ? p->nCol : 0; /* Num. columns already in colset object */
- Fts5Colset *pNew; /* New colset object to return */
-
- assert( pParse->rc==SQLITE_OK );
- assert( iCol>=0 && iCol<pParse->pConfig->nCol );
-
- pNew = sqlite3_realloc(p, sizeof(Fts5Colset) + sizeof(int)*nCol);
- if( pNew==0 ){
- pParse->rc = SQLITE_NOMEM;
- }else{
- int *aiCol = pNew->aiCol;
- int i, j;
- for(i=0; i<nCol; i++){
- if( aiCol[i]==iCol ) return pNew;
- if( aiCol[i]>iCol ) break;
- }
- for(j=nCol; j>i; j--){
- aiCol[j] = aiCol[j-1];
- }
- aiCol[i] = iCol;
- pNew->nCol = nCol+1;
-
-#ifndef NDEBUG
- /* Check that the array is in order and contains no duplicate entries. */
- for(i=1; i<pNew->nCol; i++) assert( pNew->aiCol[i]>pNew->aiCol[i-1] );
-#endif
- }
-
- return pNew;
-}
-
-static Fts5Colset *sqlite3Fts5ParseColset(
- Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */
- Fts5Colset *pColset, /* Existing colset object */
- Fts5Token *p
-){
- Fts5Colset *pRet = 0;
- int iCol;
- char *z; /* Dequoted copy of token p */
-
- z = sqlite3Fts5Strndup(&pParse->rc, p->p, p->n);
- if( pParse->rc==SQLITE_OK ){
- Fts5Config *pConfig = pParse->pConfig;
- sqlite3Fts5Dequote(z);
- for(iCol=0; iCol<pConfig->nCol; iCol++){
- if( 0==sqlite3_stricmp(pConfig->azCol[iCol], z) ) break;
- }
- if( iCol==pConfig->nCol ){
- sqlite3Fts5ParseError(pParse, "no such column: %s", z);
- }else{
- pRet = fts5ParseColset(pParse, pColset, iCol);
- }
- sqlite3_free(z);
- }
-
- if( pRet==0 ){
- assert( pParse->rc!=SQLITE_OK );
- sqlite3_free(pColset);
- }
-
- return pRet;
-}
-
-static void sqlite3Fts5ParseSetColset(
- Fts5Parse *pParse,
- Fts5ExprNearset *pNear,
- Fts5Colset *pColset
-){
- if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){
- pParse->rc = SQLITE_ERROR;
- pParse->zErr = sqlite3_mprintf(
- "fts5: column queries are not supported (detail=none)"
- );
- sqlite3_free(pColset);
- return;
- }
-
- if( pNear ){
- pNear->pColset = pColset;
- }else{
- sqlite3_free(pColset);
- }
-}
-
-static void fts5ExprAssignXNext(Fts5ExprNode *pNode){
- switch( pNode->eType ){
- case FTS5_STRING: {
- Fts5ExprNearset *pNear = pNode->pNear;
- if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1
- && pNear->apPhrase[0]->aTerm[0].pSynonym==0
- ){
- pNode->eType = FTS5_TERM;
- pNode->xNext = fts5ExprNodeNext_TERM;
- }else{
- pNode->xNext = fts5ExprNodeNext_STRING;
- }
- break;
- };
-
- case FTS5_OR: {
- pNode->xNext = fts5ExprNodeNext_OR;
- break;
- };
-
- case FTS5_AND: {
- pNode->xNext = fts5ExprNodeNext_AND;
- break;
- };
-
- default: assert( pNode->eType==FTS5_NOT ); {
- pNode->xNext = fts5ExprNodeNext_NOT;
- break;
- };
- }
-}
-
-static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
- if( p->eType!=FTS5_NOT && pSub->eType==p->eType ){
- int nByte = sizeof(Fts5ExprNode*) * pSub->nChild;
- memcpy(&p->apChild[p->nChild], pSub->apChild, nByte);
- p->nChild += pSub->nChild;
- sqlite3_free(pSub);
- }else{
- p->apChild[p->nChild++] = pSub;
- }
-}
-
-/*
-** Allocate and return a new expression object. If anything goes wrong (i.e.
-** OOM error), leave an error code in pParse and return NULL.
-*/
-static Fts5ExprNode *sqlite3Fts5ParseNode(
- Fts5Parse *pParse, /* Parse context */
- int eType, /* FTS5_STRING, AND, OR or NOT */
- Fts5ExprNode *pLeft, /* Left hand child expression */
- Fts5ExprNode *pRight, /* Right hand child expression */
- Fts5ExprNearset *pNear /* For STRING expressions, the near cluster */
-){
- Fts5ExprNode *pRet = 0;
-
- if( pParse->rc==SQLITE_OK ){
- int nChild = 0; /* Number of children of returned node */
- int nByte; /* Bytes of space to allocate for this node */
-
- assert( (eType!=FTS5_STRING && !pNear)
- || (eType==FTS5_STRING && !pLeft && !pRight)
- );
- if( eType==FTS5_STRING && pNear==0 ) return 0;
- if( eType!=FTS5_STRING && pLeft==0 ) return pRight;
- if( eType!=FTS5_STRING && pRight==0 ) return pLeft;
-
- if( eType==FTS5_NOT ){
- nChild = 2;
- }else if( eType==FTS5_AND || eType==FTS5_OR ){
- nChild = 2;
- if( pLeft->eType==eType ) nChild += pLeft->nChild-1;
- if( pRight->eType==eType ) nChild += pRight->nChild-1;
- }
-
- nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1);
- pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte);
-
- if( pRet ){
- pRet->eType = eType;
- pRet->pNear = pNear;
- fts5ExprAssignXNext(pRet);
- if( eType==FTS5_STRING ){
- int iPhrase;
- for(iPhrase=0; iPhrase<pNear->nPhrase; iPhrase++){
- pNear->apPhrase[iPhrase]->pNode = pRet;
- if( pNear->apPhrase[iPhrase]->nTerm==0 ){
- pRet->xNext = 0;
- pRet->eType = FTS5_EOF;
- }
- }
-
- if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL
- && (pNear->nPhrase!=1 || pNear->apPhrase[0]->nTerm>1)
- ){
- assert( pParse->rc==SQLITE_OK );
- pParse->rc = SQLITE_ERROR;
- assert( pParse->zErr==0 );
- pParse->zErr = sqlite3_mprintf(
- "fts5: %s queries are not supported (detail!=full)",
- pNear->nPhrase==1 ? "phrase": "NEAR"
- );
- sqlite3_free(pRet);
- pRet = 0;
- }
-
- }else{
- fts5ExprAddChildren(pRet, pLeft);
- fts5ExprAddChildren(pRet, pRight);
- }
- }
- }
-
- if( pRet==0 ){
- assert( pParse->rc!=SQLITE_OK );
- sqlite3Fts5ParseNodeFree(pLeft);
- sqlite3Fts5ParseNodeFree(pRight);
- sqlite3Fts5ParseNearsetFree(pNear);
- }
- return pRet;
-}
-
-static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
- Fts5Parse *pParse, /* Parse context */
- Fts5ExprNode *pLeft, /* Left hand child expression */
- Fts5ExprNode *pRight /* Right hand child expression */
-){
- Fts5ExprNode *pRet = 0;
- Fts5ExprNode *pPrev;
-
- if( pParse->rc ){
- sqlite3Fts5ParseNodeFree(pLeft);
- sqlite3Fts5ParseNodeFree(pRight);
- }else{
-
- assert( pLeft->eType==FTS5_STRING
- || pLeft->eType==FTS5_TERM
- || pLeft->eType==FTS5_EOF
- || pLeft->eType==FTS5_AND
- );
- assert( pRight->eType==FTS5_STRING
- || pRight->eType==FTS5_TERM
- || pRight->eType==FTS5_EOF
- );
-
- if( pLeft->eType==FTS5_AND ){
- pPrev = pLeft->apChild[pLeft->nChild-1];
- }else{
- pPrev = pLeft;
- }
- assert( pPrev->eType==FTS5_STRING
- || pPrev->eType==FTS5_TERM
- || pPrev->eType==FTS5_EOF
- );
-
- if( pRight->eType==FTS5_EOF ){
- assert( pParse->apPhrase[pParse->nPhrase-1]==pRight->pNear->apPhrase[0] );
- sqlite3Fts5ParseNodeFree(pRight);
- pRet = pLeft;
- pParse->nPhrase--;
- }
- else if( pPrev->eType==FTS5_EOF ){
- Fts5ExprPhrase **ap;
-
- if( pPrev==pLeft ){
- pRet = pRight;
- }else{
- pLeft->apChild[pLeft->nChild-1] = pRight;
- pRet = pLeft;
- }
-
- ap = &pParse->apPhrase[pParse->nPhrase-1-pRight->pNear->nPhrase];
- assert( ap[0]==pPrev->pNear->apPhrase[0] );
- memmove(ap, &ap[1], sizeof(Fts5ExprPhrase*)*pRight->pNear->nPhrase);
- pParse->nPhrase--;
-
- sqlite3Fts5ParseNodeFree(pPrev);
- }
- else{
- pRet = sqlite3Fts5ParseNode(pParse, FTS5_AND, pLeft, pRight, 0);
- }
- }
-
- return pRet;
-}
-
-static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
- int nByte = 0;
- Fts5ExprTerm *p;
- char *zQuoted;
-
- /* Determine the maximum amount of space required. */
- for(p=pTerm; p; p=p->pSynonym){
- nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2;
- }
- zQuoted = sqlite3_malloc(nByte);
-
- if( zQuoted ){
- int i = 0;
- for(p=pTerm; p; p=p->pSynonym){
- char *zIn = p->zTerm;
- zQuoted[i++] = '"';
- while( *zIn ){
- if( *zIn=='"' ) zQuoted[i++] = '"';
- zQuoted[i++] = *zIn++;
- }
- zQuoted[i++] = '"';
- if( p->pSynonym ) zQuoted[i++] = '|';
- }
- if( pTerm->bPrefix ){
- zQuoted[i++] = ' ';
- zQuoted[i++] = '*';
- }
- zQuoted[i++] = '\0';
- }
- return zQuoted;
-}
-
-static char *fts5PrintfAppend(char *zApp, const char *zFmt, ...){
- char *zNew;
- va_list ap;
- va_start(ap, zFmt);
- zNew = sqlite3_vmprintf(zFmt, ap);
- va_end(ap);
- if( zApp && zNew ){
- char *zNew2 = sqlite3_mprintf("%s%s", zApp, zNew);
- sqlite3_free(zNew);
- zNew = zNew2;
- }
- sqlite3_free(zApp);
- return zNew;
-}
-
-/*
-** Compose a tcl-readable representation of expression pExpr. Return a
-** pointer to a buffer containing that representation. It is the
-** responsibility of the caller to at some point free the buffer using
-** sqlite3_free().
-*/
-static char *fts5ExprPrintTcl(
- Fts5Config *pConfig,
- const char *zNearsetCmd,
- Fts5ExprNode *pExpr
-){
- char *zRet = 0;
- if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){
- Fts5ExprNearset *pNear = pExpr->pNear;
- int i;
- int iTerm;
-
- zRet = fts5PrintfAppend(zRet, "%s ", zNearsetCmd);
- if( zRet==0 ) return 0;
- if( pNear->pColset ){
- int *aiCol = pNear->pColset->aiCol;
- int nCol = pNear->pColset->nCol;
- if( nCol==1 ){
- zRet = fts5PrintfAppend(zRet, "-col %d ", aiCol[0]);
- }else{
- zRet = fts5PrintfAppend(zRet, "-col {%d", aiCol[0]);
- for(i=1; i<pNear->pColset->nCol; i++){
- zRet = fts5PrintfAppend(zRet, " %d", aiCol[i]);
- }
- zRet = fts5PrintfAppend(zRet, "} ");
- }
- if( zRet==0 ) return 0;
- }
-
- if( pNear->nPhrase>1 ){
- zRet = fts5PrintfAppend(zRet, "-near %d ", pNear->nNear);
- if( zRet==0 ) return 0;
- }
-
- zRet = fts5PrintfAppend(zRet, "--");
- if( zRet==0 ) return 0;
-
- for(i=0; i<pNear->nPhrase; i++){
- Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
-
- zRet = fts5PrintfAppend(zRet, " {");
- for(iTerm=0; zRet && iTerm<pPhrase->nTerm; iTerm++){
- char *zTerm = pPhrase->aTerm[iTerm].zTerm;
- zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm);
- if( pPhrase->aTerm[iTerm].bPrefix ){
- zRet = fts5PrintfAppend(zRet, "*");
- }
- }
-
- if( zRet ) zRet = fts5PrintfAppend(zRet, "}");
- if( zRet==0 ) return 0;
- }
-
- }else{
- char const *zOp = 0;
- int i;
- switch( pExpr->eType ){
- case FTS5_AND: zOp = "AND"; break;
- case FTS5_NOT: zOp = "NOT"; break;
- default:
- assert( pExpr->eType==FTS5_OR );
- zOp = "OR";
- break;
- }
-
- zRet = sqlite3_mprintf("%s", zOp);
- for(i=0; zRet && i<pExpr->nChild; i++){
- char *z = fts5ExprPrintTcl(pConfig, zNearsetCmd, pExpr->apChild[i]);
- if( !z ){
- sqlite3_free(zRet);
- zRet = 0;
- }else{
- zRet = fts5PrintfAppend(zRet, " [%z]", z);
- }
- }
- }
-
- return zRet;
-}
-
-static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){
- char *zRet = 0;
- if( pExpr->eType==0 ){
- return sqlite3_mprintf("\"\"");
- }else
- if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){
- Fts5ExprNearset *pNear = pExpr->pNear;
- int i;
- int iTerm;
-
- if( pNear->pColset ){
- int iCol = pNear->pColset->aiCol[0];
- zRet = fts5PrintfAppend(zRet, "%s : ", pConfig->azCol[iCol]);
- if( zRet==0 ) return 0;
- }
-
- if( pNear->nPhrase>1 ){
- zRet = fts5PrintfAppend(zRet, "NEAR(");
- if( zRet==0 ) return 0;
- }
-
- for(i=0; i<pNear->nPhrase; i++){
- Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
- if( i!=0 ){
- zRet = fts5PrintfAppend(zRet, " ");
- if( zRet==0 ) return 0;
- }
- for(iTerm=0; iTerm<pPhrase->nTerm; iTerm++){
- char *zTerm = fts5ExprTermPrint(&pPhrase->aTerm[iTerm]);
- if( zTerm ){
- zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" + ", zTerm);
- sqlite3_free(zTerm);
- }
- if( zTerm==0 || zRet==0 ){
- sqlite3_free(zRet);
- return 0;
- }
- }
- }
-
- if( pNear->nPhrase>1 ){
- zRet = fts5PrintfAppend(zRet, ", %d)", pNear->nNear);
- if( zRet==0 ) return 0;
- }
-
- }else{
- char const *zOp = 0;
- int i;
-
- switch( pExpr->eType ){
- case FTS5_AND: zOp = " AND "; break;
- case FTS5_NOT: zOp = " NOT "; break;
- default:
- assert( pExpr->eType==FTS5_OR );
- zOp = " OR ";
- break;
- }
-
- for(i=0; i<pExpr->nChild; i++){
- char *z = fts5ExprPrint(pConfig, pExpr->apChild[i]);
- if( z==0 ){
- sqlite3_free(zRet);
- zRet = 0;
- }else{
- int e = pExpr->apChild[i]->eType;
- int b = (e!=FTS5_STRING && e!=FTS5_TERM && e!=FTS5_EOF);
- zRet = fts5PrintfAppend(zRet, "%s%s%z%s",
- (i==0 ? "" : zOp),
- (b?"(":""), z, (b?")":"")
- );
- }
- if( zRet==0 ) break;
- }
- }
-
- return zRet;
-}
-
-/*
-** The implementation of user-defined scalar functions fts5_expr() (bTcl==0)
-** and fts5_expr_tcl() (bTcl!=0).
-*/
-static void fts5ExprFunction(
- sqlite3_context *pCtx, /* Function call context */
- int nArg, /* Number of args */
- sqlite3_value **apVal, /* Function arguments */
- int bTcl
-){
- Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx);
- sqlite3 *db = sqlite3_context_db_handle(pCtx);
- const char *zExpr = 0;
- char *zErr = 0;
- Fts5Expr *pExpr = 0;
- int rc;
- int i;
-
- const char **azConfig; /* Array of arguments for Fts5Config */
- const char *zNearsetCmd = "nearset";
- int nConfig; /* Size of azConfig[] */
- Fts5Config *pConfig = 0;
- int iArg = 1;
-
- if( nArg<1 ){
- zErr = sqlite3_mprintf("wrong number of arguments to function %s",
- bTcl ? "fts5_expr_tcl" : "fts5_expr"
- );
- sqlite3_result_error(pCtx, zErr, -1);
- sqlite3_free(zErr);
- return;
- }
-
- if( bTcl && nArg>1 ){
- zNearsetCmd = (const char*)sqlite3_value_text(apVal[1]);
- iArg = 2;
- }
-
- nConfig = 3 + (nArg-iArg);
- azConfig = (const char**)sqlite3_malloc(sizeof(char*) * nConfig);
- if( azConfig==0 ){
- sqlite3_result_error_nomem(pCtx);
- return;
- }
- azConfig[0] = 0;
- azConfig[1] = "main";
- azConfig[2] = "tbl";
- for(i=3; iArg<nArg; iArg++){
- azConfig[i++] = (const char*)sqlite3_value_text(apVal[iArg]);
- }
-
- zExpr = (const char*)sqlite3_value_text(apVal[0]);
-
- rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr);
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pExpr, &zErr);
- }
- if( rc==SQLITE_OK ){
- char *zText;
- if( pExpr->pRoot->xNext==0 ){
- zText = sqlite3_mprintf("");
- }else if( bTcl ){
- zText = fts5ExprPrintTcl(pConfig, zNearsetCmd, pExpr->pRoot);
- }else{
- zText = fts5ExprPrint(pConfig, pExpr->pRoot);
- }
- if( zText==0 ){
- rc = SQLITE_NOMEM;
- }else{
- sqlite3_result_text(pCtx, zText, -1, SQLITE_TRANSIENT);
- sqlite3_free(zText);
- }
- }
-
- if( rc!=SQLITE_OK ){
- if( zErr ){
- sqlite3_result_error(pCtx, zErr, -1);
- sqlite3_free(zErr);
- }else{
- sqlite3_result_error_code(pCtx, rc);
- }
- }
- sqlite3_free((void *)azConfig);
- sqlite3Fts5ConfigFree(pConfig);
- sqlite3Fts5ExprFree(pExpr);
-}
-
-static void fts5ExprFunctionHr(
- sqlite3_context *pCtx, /* Function call context */
- int nArg, /* Number of args */
- sqlite3_value **apVal /* Function arguments */
-){
- fts5ExprFunction(pCtx, nArg, apVal, 0);
-}
-static void fts5ExprFunctionTcl(
- sqlite3_context *pCtx, /* Function call context */
- int nArg, /* Number of args */
- sqlite3_value **apVal /* Function arguments */
-){
- fts5ExprFunction(pCtx, nArg, apVal, 1);
-}
-
-/*
-** The implementation of an SQLite user-defined-function that accepts a
-** single integer as an argument. If the integer is an alpha-numeric
-** unicode code point, 1 is returned. Otherwise 0.
-*/
-static void fts5ExprIsAlnum(
- sqlite3_context *pCtx, /* Function call context */
- int nArg, /* Number of args */
- sqlite3_value **apVal /* Function arguments */
-){
- int iCode;
- if( nArg!=1 ){
- sqlite3_result_error(pCtx,
- "wrong number of arguments to function fts5_isalnum", -1
- );
- return;
- }
- iCode = sqlite3_value_int(apVal[0]);
- sqlite3_result_int(pCtx, sqlite3Fts5UnicodeIsalnum(iCode));
-}
-
-static void fts5ExprFold(
- sqlite3_context *pCtx, /* Function call context */
- int nArg, /* Number of args */
- sqlite3_value **apVal /* Function arguments */
-){
- if( nArg!=1 && nArg!=2 ){
- sqlite3_result_error(pCtx,
- "wrong number of arguments to function fts5_fold", -1
- );
- }else{
- int iCode;
- int bRemoveDiacritics = 0;
- iCode = sqlite3_value_int(apVal[0]);
- if( nArg==2 ) bRemoveDiacritics = sqlite3_value_int(apVal[1]);
- sqlite3_result_int(pCtx, sqlite3Fts5UnicodeFold(iCode, bRemoveDiacritics));
- }
-}
-
-/*
-** This is called during initialization to register the fts5_expr() scalar
-** UDF with the SQLite handle passed as the only argument.
-*/
-static int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){
- struct Fts5ExprFunc {
- const char *z;
- void (*x)(sqlite3_context*,int,sqlite3_value**);
- } aFunc[] = {
- { "fts5_expr", fts5ExprFunctionHr },
- { "fts5_expr_tcl", fts5ExprFunctionTcl },
- { "fts5_isalnum", fts5ExprIsAlnum },
- { "fts5_fold", fts5ExprFold },
- };
- int i;
- int rc = SQLITE_OK;
- void *pCtx = (void*)pGlobal;
-
- for(i=0; rc==SQLITE_OK && i<ArraySize(aFunc); i++){
- struct Fts5ExprFunc *p = &aFunc[i];
- rc = sqlite3_create_function(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0);
- }
-
- /* Avoid a warning indicating that sqlite3Fts5ParserTrace() is unused */
-#ifndef NDEBUG
- (void)sqlite3Fts5ParserTrace;
-#endif
-
- return rc;
-}
-
-/*
-** Return the number of phrases in expression pExpr.
-*/
-static int sqlite3Fts5ExprPhraseCount(Fts5Expr *pExpr){
- return (pExpr ? pExpr->nPhrase : 0);
-}
-
-/*
-** Return the number of terms in the iPhrase'th phrase in pExpr.
-*/
-static int sqlite3Fts5ExprPhraseSize(Fts5Expr *pExpr, int iPhrase){
- if( iPhrase<0 || iPhrase>=pExpr->nPhrase ) return 0;
- return pExpr->apExprPhrase[iPhrase]->nTerm;
-}
-
-/*
-** This function is used to access the current position list for phrase
-** iPhrase.
-*/
-static int sqlite3Fts5ExprPoslist(Fts5Expr *pExpr, int iPhrase, const u8 **pa){
- int nRet;
- Fts5ExprPhrase *pPhrase = pExpr->apExprPhrase[iPhrase];
- Fts5ExprNode *pNode = pPhrase->pNode;
- if( pNode->bEof==0 && pNode->iRowid==pExpr->pRoot->iRowid ){
- *pa = pPhrase->poslist.p;
- nRet = pPhrase->poslist.n;
- }else{
- *pa = 0;
- nRet = 0;
- }
- return nRet;
-}
-
-struct Fts5PoslistPopulator {
- Fts5PoslistWriter writer;
- int bOk; /* True if ok to populate */
- int bMiss;
-};
-
-static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){
- Fts5PoslistPopulator *pRet;
- pRet = sqlite3_malloc(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
- if( pRet ){
- int i;
- memset(pRet, 0, sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
- for(i=0; i<pExpr->nPhrase; i++){
- Fts5Buffer *pBuf = &pExpr->apExprPhrase[i]->poslist;
- Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode;
- assert( pExpr->apExprPhrase[i]->nTerm==1 );
- if( bLive &&
- (pBuf->n==0 || pNode->iRowid!=pExpr->pRoot->iRowid || pNode->bEof)
- ){
- pRet[i].bMiss = 1;
- }else{
- pBuf->n = 0;
- }
- }
- }
- return pRet;
-}
-
-struct Fts5ExprCtx {
- Fts5Expr *pExpr;
- Fts5PoslistPopulator *aPopulator;
- i64 iOff;
-};
-typedef struct Fts5ExprCtx Fts5ExprCtx;
-
-/*
-** TODO: Make this more efficient!
-*/
-static int fts5ExprColsetTest(Fts5Colset *pColset, int iCol){
- int i;
- for(i=0; i<pColset->nCol; i++){
- if( pColset->aiCol[i]==iCol ) return 1;
- }
- return 0;
-}
-
-static int fts5ExprPopulatePoslistsCb(
- void *pCtx, /* Copy of 2nd argument to xTokenize() */
- int tflags, /* Mask of FTS5_TOKEN_* flags */
- const char *pToken, /* Pointer to buffer containing token */
- int nToken, /* Size of token in bytes */
- int iUnused1, /* Byte offset of token within input text */
- int iUnused2 /* Byte offset of end of token within input text */
-){
- Fts5ExprCtx *p = (Fts5ExprCtx*)pCtx;
- Fts5Expr *pExpr = p->pExpr;
- int i;
-
- UNUSED_PARAM2(iUnused1, iUnused2);
-
- if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
- if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++;
- for(i=0; i<pExpr->nPhrase; i++){
- Fts5ExprTerm *pTerm;
- if( p->aPopulator[i].bOk==0 ) continue;
- for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){
- int nTerm = (int)strlen(pTerm->zTerm);
- if( (nTerm==nToken || (nTerm<nToken && pTerm->bPrefix))
- && memcmp(pTerm->zTerm, pToken, nTerm)==0
- ){
- int rc = sqlite3Fts5PoslistWriterAppend(
- &pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff
- );
- if( rc ) return rc;
- break;
- }
- }
- }
- return SQLITE_OK;
-}
-
-static int sqlite3Fts5ExprPopulatePoslists(
- Fts5Config *pConfig,
- Fts5Expr *pExpr,
- Fts5PoslistPopulator *aPopulator,
- int iCol,
- const char *z, int n
-){
- int i;
- Fts5ExprCtx sCtx;
- sCtx.pExpr = pExpr;
- sCtx.aPopulator = aPopulator;
- sCtx.iOff = (((i64)iCol) << 32) - 1;
-
- for(i=0; i<pExpr->nPhrase; i++){
- Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode;
- Fts5Colset *pColset = pNode->pNear->pColset;
- if( (pColset && 0==fts5ExprColsetTest(pColset, iCol))
- || aPopulator[i].bMiss
- ){
- aPopulator[i].bOk = 0;
- }else{
- aPopulator[i].bOk = 1;
- }
- }
-
- return sqlite3Fts5Tokenize(pConfig,
- FTS5_TOKENIZE_DOCUMENT, z, n, (void*)&sCtx, fts5ExprPopulatePoslistsCb
- );
-}
-
-static void fts5ExprClearPoslists(Fts5ExprNode *pNode){
- if( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING ){
- pNode->pNear->apPhrase[0]->poslist.n = 0;
- }else{
- int i;
- for(i=0; i<pNode->nChild; i++){
- fts5ExprClearPoslists(pNode->apChild[i]);
- }
- }
-}
-
-static int fts5ExprCheckPoslists(Fts5ExprNode *pNode, i64 iRowid){
- pNode->iRowid = iRowid;
- pNode->bEof = 0;
- switch( pNode->eType ){
- case FTS5_TERM:
- case FTS5_STRING:
- return (pNode->pNear->apPhrase[0]->poslist.n>0);
-
- case FTS5_AND: {
- int i;
- for(i=0; i<pNode->nChild; i++){
- if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid)==0 ){
- fts5ExprClearPoslists(pNode);
- return 0;
- }
- }
- break;
- }
-
- case FTS5_OR: {
- int i;
- int bRet = 0;
- for(i=0; i<pNode->nChild; i++){
- if( fts5ExprCheckPoslists(pNode->apChild[i], iRowid) ){
- bRet = 1;
- }
- }
- return bRet;
- }
-
- default: {
- assert( pNode->eType==FTS5_NOT );
- if( 0==fts5ExprCheckPoslists(pNode->apChild[0], iRowid)
- || 0!=fts5ExprCheckPoslists(pNode->apChild[1], iRowid)
- ){
- fts5ExprClearPoslists(pNode);
- return 0;
- }
- break;
- }
- }
- return 1;
-}
-
-static void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){
- fts5ExprCheckPoslists(pExpr->pRoot, iRowid);
-}
-
-static void fts5ExprClearEof(Fts5ExprNode *pNode){
- int i;
- for(i=0; i<pNode->nChild; i++){
- fts5ExprClearEof(pNode->apChild[i]);
- }
- pNode->bEof = 0;
-}
-static void sqlite3Fts5ExprClearEof(Fts5Expr *pExpr){
- fts5ExprClearEof(pExpr->pRoot);
-}
-
-/*
-** This function is only called for detail=columns tables.
-*/
-static int sqlite3Fts5ExprPhraseCollist(
- Fts5Expr *pExpr,
- int iPhrase,
- const u8 **ppCollist,
- int *pnCollist
-){
- Fts5ExprPhrase *pPhrase = pExpr->apExprPhrase[iPhrase];
- Fts5ExprNode *pNode = pPhrase->pNode;
- int rc = SQLITE_OK;
-
- assert( iPhrase>=0 && iPhrase<pExpr->nPhrase );
- assert( pExpr->pConfig->eDetail==FTS5_DETAIL_COLUMNS );
-
- if( pNode->bEof==0
- && pNode->iRowid==pExpr->pRoot->iRowid
- && pPhrase->poslist.n>0
- ){
- Fts5ExprTerm *pTerm = &pPhrase->aTerm[0];
- if( pTerm->pSynonym ){
- Fts5Buffer *pBuf = (Fts5Buffer*)&pTerm->pSynonym[1];
- rc = fts5ExprSynonymList(
- pTerm, pNode->iRowid, pBuf, (u8**)ppCollist, pnCollist
- );
- }else{
- *ppCollist = pPhrase->aTerm[0].pIter->pData;
- *pnCollist = pPhrase->aTerm[0].pIter->nData;
- }
- }else{
- *ppCollist = 0;
- *pnCollist = 0;
- }
-
- return rc;
-}
-
-
-/*
-** 2014 August 11
-**
-** 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.
-**
-******************************************************************************
-**
-*/
-
-
-
-/* #include "fts5Int.h" */
-
-typedef struct Fts5HashEntry Fts5HashEntry;
-
-/*
-** This file contains the implementation of an in-memory hash table used
-** to accumuluate "term -> doclist" content before it is flused to a level-0
-** segment.
-*/
-
-
-struct Fts5Hash {
- int eDetail; /* Copy of Fts5Config.eDetail */
- int *pnByte; /* Pointer to bytes counter */
- int nEntry; /* Number of entries currently in hash */
- int nSlot; /* Size of aSlot[] array */
- Fts5HashEntry *pScan; /* Current ordered scan item */
- Fts5HashEntry **aSlot; /* Array of hash slots */
-};
-
-/*
-** Each entry in the hash table is represented by an object of the
-** following type. Each object, its key (zKey[]) and its current data
-** are stored in a single memory allocation. The position list data
-** immediately follows the key data in memory.
-**
-** The data that follows the key is in a similar, but not identical format
-** to the doclist data stored in the database. It is:
-**
-** * Rowid, as a varint
-** * Position list, without 0x00 terminator.
-** * Size of previous position list and rowid, as a 4 byte
-** big-endian integer.
-**
-** iRowidOff:
-** Offset of last rowid written to data area. Relative to first byte of
-** structure.
-**
-** nData:
-** Bytes of data written since iRowidOff.
-*/
-struct Fts5HashEntry {
- Fts5HashEntry *pHashNext; /* Next hash entry with same hash-key */
- Fts5HashEntry *pScanNext; /* Next entry in sorted order */
-
- int nAlloc; /* Total size of allocation */
- int iSzPoslist; /* Offset of space for 4-byte poslist size */
- int nData; /* Total bytes of data (incl. structure) */
- int nKey; /* Length of zKey[] in bytes */
- u8 bDel; /* Set delete-flag @ iSzPoslist */
- u8 bContent; /* Set content-flag (detail=none mode) */
- i16 iCol; /* Column of last value written */
- int iPos; /* Position of last value written */
- i64 iRowid; /* Rowid of last value written */
- char zKey[8]; /* Nul-terminated entry key */
-};
-
-/*
-** Size of Fts5HashEntry without the zKey[] array.
-*/
-#define FTS5_HASHENTRYSIZE (sizeof(Fts5HashEntry)-8)
-
-
-
-/*
-** Allocate a new hash table.
-*/
-static int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte){
- int rc = SQLITE_OK;
- Fts5Hash *pNew;
-
- *ppNew = pNew = (Fts5Hash*)sqlite3_malloc(sizeof(Fts5Hash));
- if( pNew==0 ){
- rc = SQLITE_NOMEM;
- }else{
- int nByte;
- memset(pNew, 0, sizeof(Fts5Hash));
- pNew->pnByte = pnByte;
- pNew->eDetail = pConfig->eDetail;
-
- pNew->nSlot = 1024;
- nByte = sizeof(Fts5HashEntry*) * pNew->nSlot;
- pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc(nByte);
- if( pNew->aSlot==0 ){
- sqlite3_free(pNew);
- *ppNew = 0;
- rc = SQLITE_NOMEM;
- }else{
- memset(pNew->aSlot, 0, nByte);
- }
- }
- return rc;
-}
-
-/*
-** Free a hash table object.
-*/
-static void sqlite3Fts5HashFree(Fts5Hash *pHash){
- if( pHash ){
- sqlite3Fts5HashClear(pHash);
- sqlite3_free(pHash->aSlot);
- sqlite3_free(pHash);
- }
-}
-
-/*
-** Empty (but do not delete) a hash table.
-*/
-static void sqlite3Fts5HashClear(Fts5Hash *pHash){
- int i;
- for(i=0; i<pHash->nSlot; i++){
- Fts5HashEntry *pNext;
- Fts5HashEntry *pSlot;
- for(pSlot=pHash->aSlot[i]; pSlot; pSlot=pNext){
- pNext = pSlot->pHashNext;
- sqlite3_free(pSlot);
- }
- }
- memset(pHash->aSlot, 0, pHash->nSlot * sizeof(Fts5HashEntry*));
- pHash->nEntry = 0;
-}
-
-static unsigned int fts5HashKey(int nSlot, const u8 *p, int n){
- int i;
- unsigned int h = 13;
- for(i=n-1; i>=0; i--){
- h = (h << 3) ^ h ^ p[i];
- }
- return (h % nSlot);
-}
-
-static unsigned int fts5HashKey2(int nSlot, u8 b, const u8 *p, int n){
- int i;
- unsigned int h = 13;
- for(i=n-1; i>=0; i--){
- h = (h << 3) ^ h ^ p[i];
- }
- h = (h << 3) ^ h ^ b;
- return (h % nSlot);
-}
-
-/*
-** Resize the hash table by doubling the number of slots.
-*/
-static int fts5HashResize(Fts5Hash *pHash){
- int nNew = pHash->nSlot*2;
- int i;
- Fts5HashEntry **apNew;
- Fts5HashEntry **apOld = pHash->aSlot;
-
- apNew = (Fts5HashEntry**)sqlite3_malloc(nNew*sizeof(Fts5HashEntry*));
- if( !apNew ) return SQLITE_NOMEM;
- memset(apNew, 0, nNew*sizeof(Fts5HashEntry*));
-
- for(i=0; i<pHash->nSlot; i++){
- while( apOld[i] ){
- int iHash;
- Fts5HashEntry *p = apOld[i];
- apOld[i] = p->pHashNext;
- iHash = fts5HashKey(nNew, (u8*)p->zKey, (int)strlen(p->zKey));
- p->pHashNext = apNew[iHash];
- apNew[iHash] = p;
- }
- }
-
- sqlite3_free(apOld);
- pHash->nSlot = nNew;
- pHash->aSlot = apNew;
- return SQLITE_OK;
-}
-
-static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){
- if( p->iSzPoslist ){
- u8 *pPtr = (u8*)p;
- if( pHash->eDetail==FTS5_DETAIL_NONE ){
- assert( p->nData==p->iSzPoslist );
- if( p->bDel ){
- pPtr[p->nData++] = 0x00;
- if( p->bContent ){
- pPtr[p->nData++] = 0x00;
- }
- }
- }else{
- int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */
- int nPos = nSz*2 + p->bDel; /* Value of nPos field */
-
- assert( p->bDel==0 || p->bDel==1 );
- if( nPos<=127 ){
- pPtr[p->iSzPoslist] = (u8)nPos;
- }else{
- int nByte = sqlite3Fts5GetVarintLen((u32)nPos);
- memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz);
- sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos);
- p->nData += (nByte-1);
- }
- }
-
- p->iSzPoslist = 0;
- p->bDel = 0;
- p->bContent = 0;
- }
-}
-
-/*
-** Add an entry to the in-memory hash table. The key is the concatenation
-** of bByte and (pToken/nToken). The value is (iRowid/iCol/iPos).
-**
-** (bByte || pToken) -> (iRowid,iCol,iPos)
-**
-** Or, if iCol is negative, then the value is a delete marker.
-*/
-static int sqlite3Fts5HashWrite(
- Fts5Hash *pHash,
- i64 iRowid, /* Rowid for this entry */
- int iCol, /* Column token appears in (-ve -> delete) */
- int iPos, /* Position of token within column */
- char bByte, /* First byte of token */
- const char *pToken, int nToken /* Token to add or remove to or from index */
-){
- unsigned int iHash;
- Fts5HashEntry *p;
- u8 *pPtr;
- int nIncr = 0; /* Amount to increment (*pHash->pnByte) by */
- int bNew; /* If non-delete entry should be written */
-
- bNew = (pHash->eDetail==FTS5_DETAIL_FULL);
-
- /* Attempt to locate an existing hash entry */
- iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken);
- for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
- if( p->zKey[0]==bByte
- && p->nKey==nToken
- && memcmp(&p->zKey[1], pToken, nToken)==0
- ){
- break;
- }
- }
-
- /* If an existing hash entry cannot be found, create a new one. */
- if( p==0 ){
- /* Figure out how much space to allocate */
- int nByte = FTS5_HASHENTRYSIZE + (nToken+1) + 1 + 64;
- if( nByte<128 ) nByte = 128;
-
- /* Grow the Fts5Hash.aSlot[] array if necessary. */
- if( (pHash->nEntry*2)>=pHash->nSlot ){
- int rc = fts5HashResize(pHash);
- if( rc!=SQLITE_OK ) return rc;
- iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken);
- }
-
- /* Allocate new Fts5HashEntry and add it to the hash table. */
- p = (Fts5HashEntry*)sqlite3_malloc(nByte);
- if( !p ) return SQLITE_NOMEM;
- memset(p, 0, FTS5_HASHENTRYSIZE);
- p->nAlloc = nByte;
- p->zKey[0] = bByte;
- memcpy(&p->zKey[1], pToken, nToken);
- assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) );
- p->nKey = nToken;
- p->zKey[nToken+1] = '\0';
- p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE;
- p->pHashNext = pHash->aSlot[iHash];
- pHash->aSlot[iHash] = p;
- pHash->nEntry++;
-
- /* Add the first rowid field to the hash-entry */
- p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid);
- p->iRowid = iRowid;
-
- p->iSzPoslist = p->nData;
- if( pHash->eDetail!=FTS5_DETAIL_NONE ){
- p->nData += 1;
- p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1);
- }
-
- nIncr += p->nData;
- }else{
-
- /* Appending to an existing hash-entry. Check that there is enough
- ** space to append the largest possible new entry. Worst case scenario
- ** is:
- **
- ** + 9 bytes for a new rowid,
- ** + 4 byte reserved for the "poslist size" varint.
- ** + 1 byte for a "new column" byte,
- ** + 3 bytes for a new column number (16-bit max) as a varint,
- ** + 5 bytes for the new position offset (32-bit max).
- */
- if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){
- int nNew = p->nAlloc * 2;
- Fts5HashEntry *pNew;
- Fts5HashEntry **pp;
- pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew);
- if( pNew==0 ) return SQLITE_NOMEM;
- pNew->nAlloc = nNew;
- for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext);
- *pp = pNew;
- p = pNew;
- }
- nIncr -= p->nData;
- }
- assert( (p->nAlloc - p->nData) >= (9 + 4 + 1 + 3 + 5) );
-
- pPtr = (u8*)p;
-
- /* If this is a new rowid, append the 4-byte size field for the previous
- ** entry, and the new rowid for this entry. */
- if( iRowid!=p->iRowid ){
- fts5HashAddPoslistSize(pHash, p);
- p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid);
- p->iRowid = iRowid;
- bNew = 1;
- p->iSzPoslist = p->nData;
- if( pHash->eDetail!=FTS5_DETAIL_NONE ){
- p->nData += 1;
- p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1);
- p->iPos = 0;
- }
- }
-
- if( iCol>=0 ){
- if( pHash->eDetail==FTS5_DETAIL_NONE ){
- p->bContent = 1;
- }else{
- /* Append a new column value, if necessary */
- assert( iCol>=p->iCol );
- if( iCol!=p->iCol ){
- if( pHash->eDetail==FTS5_DETAIL_FULL ){
- pPtr[p->nData++] = 0x01;
- p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol);
- p->iCol = (i16)iCol;
- p->iPos = 0;
- }else{
- bNew = 1;
- p->iCol = (i16)(iPos = iCol);
- }
- }
-
- /* Append the new position offset, if necessary */
- if( bNew ){
- p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2);
- p->iPos = iPos;
- }
- }
- }else{
- /* This is a delete. Set the delete flag. */
- p->bDel = 1;
- }
-
- nIncr += p->nData;
- *pHash->pnByte += nIncr;
- return SQLITE_OK;
-}
-
-
-/*
-** Arguments pLeft and pRight point to linked-lists of hash-entry objects,
-** each sorted in key order. This function merges the two lists into a
-** single list and returns a pointer to its first element.
-*/
-static Fts5HashEntry *fts5HashEntryMerge(
- Fts5HashEntry *pLeft,
- Fts5HashEntry *pRight
-){
- Fts5HashEntry *p1 = pLeft;
- Fts5HashEntry *p2 = pRight;
- Fts5HashEntry *pRet = 0;
- Fts5HashEntry **ppOut = &pRet;
-
- while( p1 || p2 ){
- if( p1==0 ){
- *ppOut = p2;
- p2 = 0;
- }else if( p2==0 ){
- *ppOut = p1;
- p1 = 0;
- }else{
- int i = 0;
- while( p1->zKey[i]==p2->zKey[i] ) i++;
-
- if( ((u8)p1->zKey[i])>((u8)p2->zKey[i]) ){
- /* p2 is smaller */
- *ppOut = p2;
- ppOut = &p2->pScanNext;
- p2 = p2->pScanNext;
- }else{
- /* p1 is smaller */
- *ppOut = p1;
- ppOut = &p1->pScanNext;
- p1 = p1->pScanNext;
- }
- *ppOut = 0;
- }
- }
-
- return pRet;
-}
-
-/*
-** Extract all tokens from hash table iHash and link them into a list
-** in sorted order. The hash table is cleared before returning. It is
-** the responsibility of the caller to free the elements of the returned
-** list.
-*/
-static int fts5HashEntrySort(
- Fts5Hash *pHash,
- const char *pTerm, int nTerm, /* Query prefix, if any */
- Fts5HashEntry **ppSorted
-){
- const int nMergeSlot = 32;
- Fts5HashEntry **ap;
- Fts5HashEntry *pList;
- int iSlot;
- int i;
-
- *ppSorted = 0;
- ap = sqlite3_malloc(sizeof(Fts5HashEntry*) * nMergeSlot);
- if( !ap ) return SQLITE_NOMEM;
- memset(ap, 0, sizeof(Fts5HashEntry*) * nMergeSlot);
-
- for(iSlot=0; iSlot<pHash->nSlot; iSlot++){
- Fts5HashEntry *pIter;
- for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){
- if( pTerm==0 || 0==memcmp(pIter->zKey, pTerm, nTerm) ){
- Fts5HashEntry *pEntry = pIter;
- pEntry->pScanNext = 0;
- for(i=0; ap[i]; i++){
- pEntry = fts5HashEntryMerge(pEntry, ap[i]);
- ap[i] = 0;
- }
- ap[i] = pEntry;
- }
- }
- }
-
- pList = 0;
- for(i=0; i<nMergeSlot; i++){
- pList = fts5HashEntryMerge(pList, ap[i]);
- }
-
- pHash->nEntry = 0;
- sqlite3_free(ap);
- *ppSorted = pList;
- return SQLITE_OK;
-}
-
-/*
-** Query the hash table for a doclist associated with term pTerm/nTerm.
-*/
-static int sqlite3Fts5HashQuery(
- Fts5Hash *pHash, /* Hash table to query */
- const char *pTerm, int nTerm, /* Query term */
- const u8 **ppDoclist, /* OUT: Pointer to doclist for pTerm */
- int *pnDoclist /* OUT: Size of doclist in bytes */
-){
- unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm);
- Fts5HashEntry *p;
-
- for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
- if( memcmp(p->zKey, pTerm, nTerm)==0 && p->zKey[nTerm]==0 ) break;
- }
-
- if( p ){
- fts5HashAddPoslistSize(pHash, p);
- *ppDoclist = (const u8*)&p->zKey[nTerm+1];
- *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1);
- }else{
- *ppDoclist = 0;
- *pnDoclist = 0;
- }
-
- return SQLITE_OK;
-}
-
-static int sqlite3Fts5HashScanInit(
- Fts5Hash *p, /* Hash table to query */
- const char *pTerm, int nTerm /* Query prefix */
-){
- return fts5HashEntrySort(p, pTerm, nTerm, &p->pScan);
-}
-
-static void sqlite3Fts5HashScanNext(Fts5Hash *p){
- assert( !sqlite3Fts5HashScanEof(p) );
- p->pScan = p->pScan->pScanNext;
-}
-
-static int sqlite3Fts5HashScanEof(Fts5Hash *p){
- return (p->pScan==0);
-}
-
-static void sqlite3Fts5HashScanEntry(
- Fts5Hash *pHash,
- const char **pzTerm, /* OUT: term (nul-terminated) */
- const u8 **ppDoclist, /* OUT: pointer to doclist */
- int *pnDoclist /* OUT: size of doclist in bytes */
-){
- Fts5HashEntry *p;
- if( (p = pHash->pScan) ){
- int nTerm = (int)strlen(p->zKey);
- fts5HashAddPoslistSize(pHash, p);
- *pzTerm = p->zKey;
- *ppDoclist = (const u8*)&p->zKey[nTerm+1];
- *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1);
- }else{
- *pzTerm = 0;
- *ppDoclist = 0;
- *pnDoclist = 0;
- }
-}
-
-
-/*
-** 2014 May 31
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** Low level access to the FTS index stored in the database file. The
-** routines in this file file implement all read and write access to the
-** %_data table. Other parts of the system access this functionality via
-** the interface defined in fts5Int.h.
-*/
-
-
-/* #include "fts5Int.h" */
-
-/*
-** Overview:
-**
-** The %_data table contains all the FTS indexes for an FTS5 virtual table.
-** As well as the main term index, there may be up to 31 prefix indexes.
-** The format is similar to FTS3/4, except that:
-**
-** * all segment b-tree leaf data is stored in fixed size page records
-** (e.g. 1000 bytes). A single doclist may span multiple pages. Care is
-** taken to ensure it is possible to iterate in either direction through
-** the entries in a doclist, or to seek to a specific entry within a
-** doclist, without loading it into memory.
-**
-** * large doclists that span many pages have associated "doclist index"
-** records that contain a copy of the first rowid on each page spanned by
-** the doclist. This is used to speed up seek operations, and merges of
-** large doclists with very small doclists.
-**
-** * extra fields in the "structure record" record the state of ongoing
-** incremental merge operations.
-**
-*/
-
-
-#define FTS5_OPT_WORK_UNIT 1000 /* Number of leaf pages per optimize step */
-#define FTS5_WORK_UNIT 64 /* Number of leaf pages in unit of work */
-
-#define FTS5_MIN_DLIDX_SIZE 4 /* Add dlidx if this many empty pages */
-
-#define FTS5_MAIN_PREFIX '0'
-
-#if FTS5_MAX_PREFIX_INDEXES > 31
-# error "FTS5_MAX_PREFIX_INDEXES is too large"
-#endif
-
-/*
-** Details:
-**
-** The %_data table managed by this module,
-**
-** CREATE TABLE %_data(id INTEGER PRIMARY KEY, block BLOB);
-**
-** , contains the following 5 types of records. See the comments surrounding
-** the FTS5_*_ROWID macros below for a description of how %_data rowids are
-** assigned to each fo them.
-**
-** 1. Structure Records:
-**
-** The set of segments that make up an index - the index structure - are
-** recorded in a single record within the %_data table. The record consists
-** of a single 32-bit configuration cookie value followed by a list of
-** SQLite varints. If the FTS table features more than one index (because
-** there are one or more prefix indexes), it is guaranteed that all share
-** the same cookie value.
-**
-** Immediately following the configuration cookie, the record begins with
-** three varints:
-**
-** + number of levels,
-** + total number of segments on all levels,
-** + value of write counter.
-**
-** Then, for each level from 0 to nMax:
-**
-** + number of input segments in ongoing merge.
-** + total number of segments in level.
-** + for each segment from oldest to newest:
-** + segment id (always > 0)
-** + first leaf page number (often 1, always greater than 0)
-** + final leaf page number
-**
-** 2. The Averages Record:
-**
-** A single record within the %_data table. The data is a list of varints.
-** The first value is the number of rows in the index. Then, for each column
-** from left to right, the total number of tokens in the column for all
-** rows of the table.
-**
-** 3. Segment leaves:
-**
-** TERM/DOCLIST FORMAT:
-**
-** Most of each segment leaf is taken up by term/doclist data. The
-** general format of term/doclist, starting with the first term
-** on the leaf page, is:
-**
-** varint : size of first term
-** blob: first term data
-** doclist: first doclist
-** zero-or-more {
-** varint: number of bytes in common with previous term
-** varint: number of bytes of new term data (nNew)
-** blob: nNew bytes of new term data
-** doclist: next doclist
-** }
-**
-** doclist format:
-**
-** varint: first rowid
-** poslist: first poslist
-** zero-or-more {
-** varint: rowid delta (always > 0)
-** poslist: next poslist
-** }
-**
-** poslist format:
-**
-** varint: size of poslist in bytes multiplied by 2, not including
-** this field. Plus 1 if this entry carries the "delete" flag.
-** collist: collist for column 0
-** zero-or-more {
-** 0x01 byte
-** varint: column number (I)
-** collist: collist for column I
-** }
-**
-** collist format:
-**
-** varint: first offset + 2
-** zero-or-more {
-** varint: offset delta + 2
-** }
-**
-** PAGE FORMAT
-**
-** Each leaf page begins with a 4-byte header containing 2 16-bit
-** unsigned integer fields in big-endian format. They are:
-**
-** * The byte offset of the first rowid on the page, if it exists
-** and occurs before the first term (otherwise 0).
-**
-** * The byte offset of the start of the page footer. If the page
-** footer is 0 bytes in size, then this field is the same as the
-** size of the leaf page in bytes.
-**
-** The page footer consists of a single varint for each term located
-** on the page. Each varint is the byte offset of the current term
-** within the page, delta-compressed against the previous value. In
-** other words, the first varint in the footer is the byte offset of
-** the first term, the second is the byte offset of the second less that
-** of the first, and so on.
-**
-** The term/doclist format described above is accurate if the entire
-** term/doclist data fits on a single leaf page. If this is not the case,
-** the format is changed in two ways:
-**
-** + if the first rowid on a page occurs before the first term, it
-** is stored as a literal value:
-**
-** varint: first rowid
-**
-** + the first term on each page is stored in the same way as the
-** very first term of the segment:
-**
-** varint : size of first term
-** blob: first term data
-**
-** 5. Segment doclist indexes:
-**
-** Doclist indexes are themselves b-trees, however they usually consist of
-** a single leaf record only. The format of each doclist index leaf page
-** is:
-**
-** * Flags byte. Bits are:
-** 0x01: Clear if leaf is also the root page, otherwise set.
-**
-** * Page number of fts index leaf page. As a varint.
-**
-** * First rowid on page indicated by previous field. As a varint.
-**
-** * A list of varints, one for each subsequent termless page. A
-** positive delta if the termless page contains at least one rowid,
-** or an 0x00 byte otherwise.
-**
-** Internal doclist index nodes are:
-**
-** * Flags byte. Bits are:
-** 0x01: Clear for root page, otherwise set.
-**
-** * Page number of first child page. As a varint.
-**
-** * Copy of first rowid on page indicated by previous field. As a varint.
-**
-** * A list of delta-encoded varints - the first rowid on each subsequent
-** child page.
-**
-*/
-
-/*
-** Rowids for the averages and structure records in the %_data table.
-*/
-#define FTS5_AVERAGES_ROWID 1 /* Rowid used for the averages record */
-#define FTS5_STRUCTURE_ROWID 10 /* The structure record */
-
-/*
-** Macros determining the rowids used by segment leaves and dlidx leaves
-** and nodes. All nodes and leaves are stored in the %_data table with large
-** positive rowids.
-**
-** Each segment has a unique non-zero 16-bit id.
-**
-** The rowid for each segment leaf is found by passing the segment id and
-** the leaf page number to the FTS5_SEGMENT_ROWID macro. Leaves are numbered
-** sequentially starting from 1.
-*/
-#define FTS5_DATA_ID_B 16 /* Max seg id number 65535 */
-#define FTS5_DATA_DLI_B 1 /* Doclist-index flag (1 bit) */
-#define FTS5_DATA_HEIGHT_B 5 /* Max dlidx tree height of 32 */
-#define FTS5_DATA_PAGE_B 31 /* Max page number of 2147483648 */
-
-#define fts5_dri(segid, dlidx, height, pgno) ( \
- ((i64)(segid) << (FTS5_DATA_PAGE_B+FTS5_DATA_HEIGHT_B+FTS5_DATA_DLI_B)) + \
- ((i64)(dlidx) << (FTS5_DATA_PAGE_B + FTS5_DATA_HEIGHT_B)) + \
- ((i64)(height) << (FTS5_DATA_PAGE_B)) + \
- ((i64)(pgno)) \
-)
-
-#define FTS5_SEGMENT_ROWID(segid, pgno) fts5_dri(segid, 0, 0, pgno)
-#define FTS5_DLIDX_ROWID(segid, height, pgno) fts5_dri(segid, 1, height, pgno)
-
-/*
-** Maximum segments permitted in a single index
-*/
-#define FTS5_MAX_SEGMENT 2000
-
-#ifdef SQLITE_DEBUG
-static int sqlite3Fts5Corrupt() { return SQLITE_CORRUPT_VTAB; }
-#endif
-
-
-/*
-** Each time a blob is read from the %_data table, it is padded with this
-** many zero bytes. This makes it easier to decode the various record formats
-** without overreading if the records are corrupt.
-*/
-#define FTS5_DATA_ZERO_PADDING 8
-#define FTS5_DATA_PADDING 20
-
-typedef struct Fts5Data Fts5Data;
-typedef struct Fts5DlidxIter Fts5DlidxIter;
-typedef struct Fts5DlidxLvl Fts5DlidxLvl;
-typedef struct Fts5DlidxWriter Fts5DlidxWriter;
-typedef struct Fts5Iter Fts5Iter;
-typedef struct Fts5PageWriter Fts5PageWriter;
-typedef struct Fts5SegIter Fts5SegIter;
-typedef struct Fts5DoclistIter Fts5DoclistIter;
-typedef struct Fts5SegWriter Fts5SegWriter;
-typedef struct Fts5Structure Fts5Structure;
-typedef struct Fts5StructureLevel Fts5StructureLevel;
-typedef struct Fts5StructureSegment Fts5StructureSegment;
-
-struct Fts5Data {
- u8 *p; /* Pointer to buffer containing record */
- int nn; /* Size of record in bytes */
- int szLeaf; /* Size of leaf without page-index */
-};
-
-/*
-** One object per %_data table.
-*/
-struct Fts5Index {
- Fts5Config *pConfig; /* Virtual table configuration */
- char *zDataTbl; /* Name of %_data table */
- int nWorkUnit; /* Leaf pages in a "unit" of work */
-
- /*
- ** Variables related to the accumulation of tokens and doclists within the
- ** in-memory hash tables before they are flushed to disk.
- */
- Fts5Hash *pHash; /* Hash table for in-memory data */
- int nPendingData; /* Current bytes of pending data */
- i64 iWriteRowid; /* Rowid for current doc being written */
- int bDelete; /* Current write is a delete */
-
- /* Error state. */
- int rc; /* Current error code */
-
- /* State used by the fts5DataXXX() functions. */
- sqlite3_blob *pReader; /* RO incr-blob open on %_data table */
- sqlite3_stmt *pWriter; /* "INSERT ... %_data VALUES(?,?)" */
- sqlite3_stmt *pDeleter; /* "DELETE FROM %_data ... id>=? AND id<=?" */
- sqlite3_stmt *pIdxWriter; /* "INSERT ... %_idx VALUES(?,?,?,?)" */
- sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=? */
- sqlite3_stmt *pIdxSelect;
- int nRead; /* Total number of blocks read */
-
- sqlite3_stmt *pDataVersion;
- i64 iStructVersion; /* data_version when pStruct read */
- Fts5Structure *pStruct; /* Current db structure (or NULL) */
-};
-
-struct Fts5DoclistIter {
- u8 *aEof; /* Pointer to 1 byte past end of doclist */
-
- /* Output variables. aPoslist==0 at EOF */
- i64 iRowid;
- u8 *aPoslist;
- int nPoslist;
- int nSize;
-};
-
-/*
-** The contents of the "structure" record for each index are represented
-** using an Fts5Structure record in memory. Which uses instances of the
-** other Fts5StructureXXX types as components.
-*/
-struct Fts5StructureSegment {
- int iSegid; /* Segment id */
- int pgnoFirst; /* First leaf page number in segment */
- int pgnoLast; /* Last leaf page number in segment */
-};
-struct Fts5StructureLevel {
- int nMerge; /* Number of segments in incr-merge */
- int nSeg; /* Total number of segments on level */
- Fts5StructureSegment *aSeg; /* Array of segments. aSeg[0] is oldest. */
-};
-struct Fts5Structure {
- int nRef; /* Object reference count */
- u64 nWriteCounter; /* Total leaves written to level 0 */
- int nSegment; /* Total segments in this structure */
- int nLevel; /* Number of levels in this index */
- Fts5StructureLevel aLevel[1]; /* Array of nLevel level objects */
-};
-
-/*
-** An object of type Fts5SegWriter is used to write to segments.
-*/
-struct Fts5PageWriter {
- int pgno; /* Page number for this page */
- int iPrevPgidx; /* Previous value written into pgidx */
- Fts5Buffer buf; /* Buffer containing leaf data */
- Fts5Buffer pgidx; /* Buffer containing page-index */
- Fts5Buffer term; /* Buffer containing previous term on page */
-};
-struct Fts5DlidxWriter {
- int pgno; /* Page number for this page */
- int bPrevValid; /* True if iPrev is valid */
- i64 iPrev; /* Previous rowid value written to page */
- Fts5Buffer buf; /* Buffer containing page data */
-};
-struct Fts5SegWriter {
- int iSegid; /* Segid to write to */
- Fts5PageWriter writer; /* PageWriter object */
- i64 iPrevRowid; /* Previous rowid written to current leaf */
- u8 bFirstRowidInDoclist; /* True if next rowid is first in doclist */
- u8 bFirstRowidInPage; /* True if next rowid is first in page */
- /* TODO1: Can use (writer.pgidx.n==0) instead of bFirstTermInPage */
- u8 bFirstTermInPage; /* True if next term will be first in leaf */
- int nLeafWritten; /* Number of leaf pages written */
- int nEmpty; /* Number of contiguous term-less nodes */
-
- int nDlidx; /* Allocated size of aDlidx[] array */
- Fts5DlidxWriter *aDlidx; /* Array of Fts5DlidxWriter objects */
-
- /* Values to insert into the %_idx table */
- Fts5Buffer btterm; /* Next term to insert into %_idx table */
- int iBtPage; /* Page number corresponding to btterm */
-};
-
-typedef struct Fts5CResult Fts5CResult;
-struct Fts5CResult {
- u16 iFirst; /* aSeg[] index of firstest iterator */
- u8 bTermEq; /* True if the terms are equal */
-};
-
-/*
-** Object for iterating through a single segment, visiting each term/rowid
-** pair in the segment.
-**
-** pSeg:
-** The segment to iterate through.
-**
-** iLeafPgno:
-** Current leaf page number within segment.
-**
-** iLeafOffset:
-** Byte offset within the current leaf that is the first byte of the
-** position list data (one byte passed the position-list size field).
-** rowid field of the current entry. Usually this is the size field of the
-** position list data. The exception is if the rowid for the current entry
-** is the last thing on the leaf page.
-**
-** pLeaf:
-** Buffer containing current leaf page data. Set to NULL at EOF.
-**
-** iTermLeafPgno, iTermLeafOffset:
-** Leaf page number containing the last term read from the segment. And
-** the offset immediately following the term data.
-**
-** flags:
-** Mask of FTS5_SEGITER_XXX values. Interpreted as follows:
-**
-** FTS5_SEGITER_ONETERM:
-** If set, set the iterator to point to EOF after the current doclist
-** has been exhausted. Do not proceed to the next term in the segment.
-**
-** FTS5_SEGITER_REVERSE:
-** This flag is only ever set if FTS5_SEGITER_ONETERM is also set. If
-** it is set, iterate through rowid in descending order instead of the
-** default ascending order.
-**
-** iRowidOffset/nRowidOffset/aRowidOffset:
-** These are used if the FTS5_SEGITER_REVERSE flag is set.
-**
-** For each rowid on the page corresponding to the current term, the
-** corresponding aRowidOffset[] entry is set to the byte offset of the
-** start of the "position-list-size" field within the page.
-**
-** iTermIdx:
-** Index of current term on iTermLeafPgno.
-*/
-struct Fts5SegIter {
- Fts5StructureSegment *pSeg; /* Segment to iterate through */
- int flags; /* Mask of configuration flags */
- int iLeafPgno; /* Current leaf page number */
- Fts5Data *pLeaf; /* Current leaf data */
- Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */
- int iLeafOffset; /* Byte offset within current leaf */
-
- /* Next method */
- void (*xNext)(Fts5Index*, Fts5SegIter*, int*);
-
- /* The page and offset from which the current term was read. The offset
- ** is the offset of the first rowid in the current doclist. */
- int iTermLeafPgno;
- int iTermLeafOffset;
-
- int iPgidxOff; /* Next offset in pgidx */
- int iEndofDoclist;
-
- /* The following are only used if the FTS5_SEGITER_REVERSE flag is set. */
- int iRowidOffset; /* Current entry in aRowidOffset[] */
- int nRowidOffset; /* Allocated size of aRowidOffset[] array */
- int *aRowidOffset; /* Array of offset to rowid fields */
-
- Fts5DlidxIter *pDlidx; /* If there is a doclist-index */
-
- /* Variables populated based on current entry. */
- Fts5Buffer term; /* Current term */
- i64 iRowid; /* Current rowid */
- int nPos; /* Number of bytes in current position list */
- u8 bDel; /* True if the delete flag is set */
-};
-
-/*
-** Argument is a pointer to an Fts5Data structure that contains a
-** leaf page.
-*/
-#define ASSERT_SZLEAF_OK(x) assert( \
- (x)->szLeaf==(x)->nn || (x)->szLeaf==fts5GetU16(&(x)->p[2]) \
-)
-
-#define FTS5_SEGITER_ONETERM 0x01
-#define FTS5_SEGITER_REVERSE 0x02
-
-/*
-** Argument is a pointer to an Fts5Data structure that contains a leaf
-** page. This macro evaluates to true if the leaf contains no terms, or
-** false if it contains at least one term.
-*/
-#define fts5LeafIsTermless(x) ((x)->szLeaf >= (x)->nn)
-
-#define fts5LeafTermOff(x, i) (fts5GetU16(&(x)->p[(x)->szLeaf + (i)*2]))
-
-#define fts5LeafFirstRowidOff(x) (fts5GetU16((x)->p))
-
-/*
-** Object for iterating through the merged results of one or more segments,
-** visiting each term/rowid pair in the merged data.
-**
-** nSeg is always a power of two greater than or equal to the number of
-** segments that this object is merging data from. Both the aSeg[] and
-** aFirst[] arrays are sized at nSeg entries. The aSeg[] array is padded
-** with zeroed objects - these are handled as if they were iterators opened
-** on empty segments.
-**
-** The results of comparing segments aSeg[N] and aSeg[N+1], where N is an
-** even number, is stored in aFirst[(nSeg+N)/2]. The "result" of the
-** comparison in this context is the index of the iterator that currently
-** points to the smaller term/rowid combination. Iterators at EOF are
-** considered to be greater than all other iterators.
-**
-** aFirst[1] contains the index in aSeg[] of the iterator that points to
-** the smallest key overall. aFirst[0] is unused.
-**
-** poslist:
-** Used by sqlite3Fts5IterPoslist() when the poslist needs to be buffered.
-** There is no way to tell if this is populated or not.
-*/
-struct Fts5Iter {
- Fts5IndexIter base; /* Base class containing output vars */
-
- Fts5Index *pIndex; /* Index that owns this iterator */
- Fts5Structure *pStruct; /* Database structure for this iterator */
- Fts5Buffer poslist; /* Buffer containing current poslist */
- Fts5Colset *pColset; /* Restrict matches to these columns */
-
- /* Invoked to set output variables. */
- void (*xSetOutputs)(Fts5Iter*, Fts5SegIter*);
-
- int nSeg; /* Size of aSeg[] array */
- int bRev; /* True to iterate in reverse order */
- u8 bSkipEmpty; /* True to skip deleted entries */
-
- i64 iSwitchRowid; /* Firstest rowid of other than aFirst[1] */
- Fts5CResult *aFirst; /* Current merge state (see above) */
- Fts5SegIter aSeg[1]; /* Array of segment iterators */
-};
-
-
-/*
-** An instance of the following type is used to iterate through the contents
-** of a doclist-index record.
-**
-** pData:
-** Record containing the doclist-index data.
-**
-** bEof:
-** Set to true once iterator has reached EOF.
-**
-** iOff:
-** Set to the current offset within record pData.
-*/
-struct Fts5DlidxLvl {
- Fts5Data *pData; /* Data for current page of this level */
- int iOff; /* Current offset into pData */
- int bEof; /* At EOF already */
- int iFirstOff; /* Used by reverse iterators */
-
- /* Output variables */
- int iLeafPgno; /* Page number of current leaf page */
- i64 iRowid; /* First rowid on leaf iLeafPgno */
-};
-struct Fts5DlidxIter {
- int nLvl;
- int iSegid;
- Fts5DlidxLvl aLvl[1];
-};
-
-static void fts5PutU16(u8 *aOut, u16 iVal){
- aOut[0] = (iVal>>8);
- aOut[1] = (iVal&0xFF);
-}
-
-static u16 fts5GetU16(const u8 *aIn){
- return ((u16)aIn[0] << 8) + aIn[1];
-}
-
-/*
-** Allocate and return a buffer at least nByte bytes in size.
-**
-** If an OOM error is encountered, return NULL and set the error code in
-** the Fts5Index handle passed as the first argument.
-*/
-static void *fts5IdxMalloc(Fts5Index *p, int nByte){
- return sqlite3Fts5MallocZero(&p->rc, nByte);
-}
-
-/*
-** Compare the contents of the pLeft buffer with the pRight/nRight blob.
-**
-** Return -ve if pLeft is smaller than pRight, 0 if they are equal or
-** +ve if pRight is smaller than pLeft. In other words:
-**
-** res = *pLeft - *pRight
-*/
-#ifdef SQLITE_DEBUG
-static int fts5BufferCompareBlob(
- Fts5Buffer *pLeft, /* Left hand side of comparison */
- const u8 *pRight, int nRight /* Right hand side of comparison */
-){
- int nCmp = MIN(pLeft->n, nRight);
- int res = memcmp(pLeft->p, pRight, nCmp);
- return (res==0 ? (pLeft->n - nRight) : res);
-}
-#endif
-
-/*
-** Compare the contents of the two buffers using memcmp(). If one buffer
-** is a prefix of the other, it is considered the lesser.
-**
-** Return -ve if pLeft is smaller than pRight, 0 if they are equal or
-** +ve if pRight is smaller than pLeft. In other words:
-**
-** res = *pLeft - *pRight
-*/
-static int fts5BufferCompare(Fts5Buffer *pLeft, Fts5Buffer *pRight){
- int nCmp = MIN(pLeft->n, pRight->n);
- int res = memcmp(pLeft->p, pRight->p, nCmp);
- return (res==0 ? (pLeft->n - pRight->n) : res);
-}
-
-static int fts5LeafFirstTermOff(Fts5Data *pLeaf){
- int ret;
- fts5GetVarint32(&pLeaf->p[pLeaf->szLeaf], ret);
- return ret;
-}
-
-/*
-** Close the read-only blob handle, if it is open.
-*/
-static void fts5CloseReader(Fts5Index *p){
- if( p->pReader ){
- sqlite3_blob *pReader = p->pReader;
- p->pReader = 0;
- sqlite3_blob_close(pReader);
- }
-}
-
-
-/*
-** Retrieve a record from the %_data table.
-**
-** If an error occurs, NULL is returned and an error left in the
-** Fts5Index object.
-*/
-static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
- Fts5Data *pRet = 0;
- if( p->rc==SQLITE_OK ){
- int rc = SQLITE_OK;
-
- if( p->pReader ){
- /* This call may return SQLITE_ABORT if there has been a savepoint
- ** rollback since it was last used. In this case a new blob handle
- ** is required. */
- sqlite3_blob *pBlob = p->pReader;
- p->pReader = 0;
- rc = sqlite3_blob_reopen(pBlob, iRowid);
- assert( p->pReader==0 );
- p->pReader = pBlob;
- if( rc!=SQLITE_OK ){
- fts5CloseReader(p);
- }
- if( rc==SQLITE_ABORT ) rc = SQLITE_OK;
- }
-
- /* If the blob handle is not open at this point, open it and seek
- ** to the requested entry. */
- if( p->pReader==0 && rc==SQLITE_OK ){
- Fts5Config *pConfig = p->pConfig;
- rc = sqlite3_blob_open(pConfig->db,
- pConfig->zDb, p->zDataTbl, "block", iRowid, 0, &p->pReader
- );
- }
-
- /* If either of the sqlite3_blob_open() or sqlite3_blob_reopen() calls
- ** above returned SQLITE_ERROR, return SQLITE_CORRUPT_VTAB instead.
- ** All the reasons those functions might return SQLITE_ERROR - missing
- ** table, missing row, non-blob/text in block column - indicate
- ** backing store corruption. */
- if( rc==SQLITE_ERROR ) rc = FTS5_CORRUPT;
-
- if( rc==SQLITE_OK ){
- u8 *aOut = 0; /* Read blob data into this buffer */
- int nByte = sqlite3_blob_bytes(p->pReader);
- int nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING;
- pRet = (Fts5Data*)sqlite3_malloc(nAlloc);
- if( pRet ){
- pRet->nn = nByte;
- aOut = pRet->p = (u8*)&pRet[1];
- }else{
- rc = SQLITE_NOMEM;
- }
-
- if( rc==SQLITE_OK ){
- rc = sqlite3_blob_read(p->pReader, aOut, nByte, 0);
- }
- if( rc!=SQLITE_OK ){
- sqlite3_free(pRet);
- pRet = 0;
- }else{
- /* TODO1: Fix this */
- pRet->szLeaf = fts5GetU16(&pRet->p[2]);
- }
- }
- p->rc = rc;
- p->nRead++;
- }
-
- assert( (pRet==0)==(p->rc!=SQLITE_OK) );
- return pRet;
-}
-
-
-/*
-** Release a reference to data record returned by an earlier call to
-** fts5DataRead().
-*/
-static void fts5DataRelease(Fts5Data *pData){
- sqlite3_free(pData);
-}
-
-static int fts5IndexPrepareStmt(
- Fts5Index *p,
- sqlite3_stmt **ppStmt,
- char *zSql
-){
- if( p->rc==SQLITE_OK ){
- if( zSql ){
- p->rc = sqlite3_prepare_v2(p->pConfig->db, zSql, -1, ppStmt, 0);
- }else{
- p->rc = SQLITE_NOMEM;
- }
- }
- sqlite3_free(zSql);
- return p->rc;
-}
-
-
-/*
-** INSERT OR REPLACE a record into the %_data table.
-*/
-static void fts5DataWrite(Fts5Index *p, i64 iRowid, const u8 *pData, int nData){
- if( p->rc!=SQLITE_OK ) return;
-
- if( p->pWriter==0 ){
- Fts5Config *pConfig = p->pConfig;
- fts5IndexPrepareStmt(p, &p->pWriter, sqlite3_mprintf(
- "REPLACE INTO '%q'.'%q_data'(id, block) VALUES(?,?)",
- pConfig->zDb, pConfig->zName
- ));
- if( p->rc ) return;
- }
-
- sqlite3_bind_int64(p->pWriter, 1, iRowid);
- sqlite3_bind_blob(p->pWriter, 2, pData, nData, SQLITE_STATIC);
- sqlite3_step(p->pWriter);
- p->rc = sqlite3_reset(p->pWriter);
-}
-
-/*
-** Execute the following SQL:
-**
-** DELETE FROM %_data WHERE id BETWEEN $iFirst AND $iLast
-*/
-static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){
- if( p->rc!=SQLITE_OK ) return;
-
- if( p->pDeleter==0 ){
- int rc;
- Fts5Config *pConfig = p->pConfig;
- char *zSql = sqlite3_mprintf(
- "DELETE FROM '%q'.'%q_data' WHERE id>=? AND id<=?",
- pConfig->zDb, pConfig->zName
- );
- if( zSql==0 ){
- rc = SQLITE_NOMEM;
- }else{
- rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &p->pDeleter, 0);
- sqlite3_free(zSql);
- }
- if( rc!=SQLITE_OK ){
- p->rc = rc;
- return;
- }
- }
-
- sqlite3_bind_int64(p->pDeleter, 1, iFirst);
- sqlite3_bind_int64(p->pDeleter, 2, iLast);
- sqlite3_step(p->pDeleter);
- p->rc = sqlite3_reset(p->pDeleter);
-}
-
-/*
-** Remove all records associated with segment iSegid.
-*/
-static void fts5DataRemoveSegment(Fts5Index *p, int iSegid){
- i64 iFirst = FTS5_SEGMENT_ROWID(iSegid, 0);
- i64 iLast = FTS5_SEGMENT_ROWID(iSegid+1, 0)-1;
- fts5DataDelete(p, iFirst, iLast);
- if( p->pIdxDeleter==0 ){
- Fts5Config *pConfig = p->pConfig;
- fts5IndexPrepareStmt(p, &p->pIdxDeleter, sqlite3_mprintf(
- "DELETE FROM '%q'.'%q_idx' WHERE segid=?",
- pConfig->zDb, pConfig->zName
- ));
- }
- if( p->rc==SQLITE_OK ){
- sqlite3_bind_int(p->pIdxDeleter, 1, iSegid);
- sqlite3_step(p->pIdxDeleter);
- p->rc = sqlite3_reset(p->pIdxDeleter);
- }
-}
-
-/*
-** Release a reference to an Fts5Structure object returned by an earlier
-** call to fts5StructureRead() or fts5StructureDecode().
-*/
-static void fts5StructureRelease(Fts5Structure *pStruct){
- if( pStruct && 0>=(--pStruct->nRef) ){
- int i;
- assert( pStruct->nRef==0 );
- for(i=0; i<pStruct->nLevel; i++){
- sqlite3_free(pStruct->aLevel[i].aSeg);
- }
- sqlite3_free(pStruct);
- }
-}
-
-static void fts5StructureRef(Fts5Structure *pStruct){
- pStruct->nRef++;
-}
-
-/*
-** Deserialize and return the structure record currently stored in serialized
-** form within buffer pData/nData.
-**
-** The Fts5Structure.aLevel[] and each Fts5StructureLevel.aSeg[] array
-** are over-allocated by one slot. This allows the structure contents
-** to be more easily edited.
-**
-** If an error occurs, *ppOut is set to NULL and an SQLite error code
-** returned. Otherwise, *ppOut is set to point to the new object and
-** SQLITE_OK returned.
-*/
-static int fts5StructureDecode(
- const u8 *pData, /* Buffer containing serialized structure */
- int nData, /* Size of buffer pData in bytes */
- int *piCookie, /* Configuration cookie value */
- Fts5Structure **ppOut /* OUT: Deserialized object */
-){
- int rc = SQLITE_OK;
- int i = 0;
- int iLvl;
- int nLevel = 0;
- int nSegment = 0;
- int nByte; /* Bytes of space to allocate at pRet */
- Fts5Structure *pRet = 0; /* Structure object to return */
-
- /* Grab the cookie value */
- if( piCookie ) *piCookie = sqlite3Fts5Get32(pData);
- i = 4;
-
- /* Read the total number of levels and segments from the start of the
- ** structure record. */
- i += fts5GetVarint32(&pData[i], nLevel);
- i += fts5GetVarint32(&pData[i], nSegment);
- nByte = (
- sizeof(Fts5Structure) + /* Main structure */
- sizeof(Fts5StructureLevel) * (nLevel-1) /* aLevel[] array */
- );
- pRet = (Fts5Structure*)sqlite3Fts5MallocZero(&rc, nByte);
-
- if( pRet ){
- pRet->nRef = 1;
- pRet->nLevel = nLevel;
- pRet->nSegment = nSegment;
- i += sqlite3Fts5GetVarint(&pData[i], &pRet->nWriteCounter);
-
- for(iLvl=0; rc==SQLITE_OK && iLvl<nLevel; iLvl++){
- Fts5StructureLevel *pLvl = &pRet->aLevel[iLvl];
- int nTotal = 0;
- int iSeg;
-
- if( i>=nData ){
- rc = FTS5_CORRUPT;
- }else{
- i += fts5GetVarint32(&pData[i], pLvl->nMerge);
- i += fts5GetVarint32(&pData[i], nTotal);
- assert( nTotal>=pLvl->nMerge );
- pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc,
- nTotal * sizeof(Fts5StructureSegment)
- );
- }
-
- if( rc==SQLITE_OK ){
- pLvl->nSeg = nTotal;
- for(iSeg=0; iSeg<nTotal; iSeg++){
- if( i>=nData ){
- rc = FTS5_CORRUPT;
- break;
- }
- i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].iSegid);
- i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoFirst);
- i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoLast);
- }
- }
- }
- if( rc!=SQLITE_OK ){
- fts5StructureRelease(pRet);
- pRet = 0;
- }
- }
-
- *ppOut = pRet;
- return rc;
-}
-
-/*
-**
-*/
-static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
- if( *pRc==SQLITE_OK ){
- Fts5Structure *pStruct = *ppStruct;
- int nLevel = pStruct->nLevel;
- int nByte = (
- sizeof(Fts5Structure) + /* Main structure */
- sizeof(Fts5StructureLevel) * (nLevel+1) /* aLevel[] array */
- );
-
- pStruct = sqlite3_realloc(pStruct, nByte);
- if( pStruct ){
- memset(&pStruct->aLevel[nLevel], 0, sizeof(Fts5StructureLevel));
- pStruct->nLevel++;
- *ppStruct = pStruct;
- }else{
- *pRc = SQLITE_NOMEM;
- }
- }
-}
-
-/*
-** Extend level iLvl so that there is room for at least nExtra more
-** segments.
-*/
-static void fts5StructureExtendLevel(
- int *pRc,
- Fts5Structure *pStruct,
- int iLvl,
- int nExtra,
- int bInsert
-){
- if( *pRc==SQLITE_OK ){
- Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
- Fts5StructureSegment *aNew;
- int nByte;
-
- nByte = (pLvl->nSeg + nExtra) * sizeof(Fts5StructureSegment);
- aNew = sqlite3_realloc(pLvl->aSeg, nByte);
- if( aNew ){
- if( bInsert==0 ){
- memset(&aNew[pLvl->nSeg], 0, sizeof(Fts5StructureSegment) * nExtra);
- }else{
- int nMove = pLvl->nSeg * sizeof(Fts5StructureSegment);
- memmove(&aNew[nExtra], aNew, nMove);
- memset(aNew, 0, sizeof(Fts5StructureSegment) * nExtra);
- }
- pLvl->aSeg = aNew;
- }else{
- *pRc = SQLITE_NOMEM;
- }
- }
-}
-
-static Fts5Structure *fts5StructureReadUncached(Fts5Index *p){
- Fts5Structure *pRet = 0;
- Fts5Config *pConfig = p->pConfig;
- int iCookie; /* Configuration cookie */
- Fts5Data *pData;
-
- pData = fts5DataRead(p, FTS5_STRUCTURE_ROWID);
- if( p->rc==SQLITE_OK ){
- /* TODO: Do we need this if the leaf-index is appended? Probably... */
- memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING);
- p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet);
- if( p->rc==SQLITE_OK && pConfig->iCookie!=iCookie ){
- p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie);
- }
- fts5DataRelease(pData);
- if( p->rc!=SQLITE_OK ){
- fts5StructureRelease(pRet);
- pRet = 0;
- }
- }
-
- return pRet;
-}
-
-static i64 fts5IndexDataVersion(Fts5Index *p){
- i64 iVersion = 0;
-
- if( p->rc==SQLITE_OK ){
- if( p->pDataVersion==0 ){
- p->rc = fts5IndexPrepareStmt(p, &p->pDataVersion,
- sqlite3_mprintf("PRAGMA %Q.data_version", p->pConfig->zDb)
- );
- if( p->rc ) return 0;
- }
-
- if( SQLITE_ROW==sqlite3_step(p->pDataVersion) ){
- iVersion = sqlite3_column_int64(p->pDataVersion, 0);
- }
- p->rc = sqlite3_reset(p->pDataVersion);
- }
-
- return iVersion;
-}
-
-/*
-** Read, deserialize and return the structure record.
-**
-** The Fts5Structure.aLevel[] and each Fts5StructureLevel.aSeg[] array
-** are over-allocated as described for function fts5StructureDecode()
-** above.
-**
-** If an error occurs, NULL is returned and an error code left in the
-** Fts5Index handle. If an error has already occurred when this function
-** is called, it is a no-op.
-*/
-static Fts5Structure *fts5StructureRead(Fts5Index *p){
-
- if( p->pStruct==0 ){
- p->iStructVersion = fts5IndexDataVersion(p);
- if( p->rc==SQLITE_OK ){
- p->pStruct = fts5StructureReadUncached(p);
- }
- }
-
-#if 0
- else{
- Fts5Structure *pTest = fts5StructureReadUncached(p);
- if( pTest ){
- int i, j;
- assert_nc( p->pStruct->nSegment==pTest->nSegment );
- assert_nc( p->pStruct->nLevel==pTest->nLevel );
- for(i=0; i<pTest->nLevel; i++){
- assert_nc( p->pStruct->aLevel[i].nMerge==pTest->aLevel[i].nMerge );
- assert_nc( p->pStruct->aLevel[i].nSeg==pTest->aLevel[i].nSeg );
- for(j=0; j<pTest->aLevel[i].nSeg; j++){
- Fts5StructureSegment *p1 = &pTest->aLevel[i].aSeg[j];
- Fts5StructureSegment *p2 = &p->pStruct->aLevel[i].aSeg[j];
- assert_nc( p1->iSegid==p2->iSegid );
- assert_nc( p1->pgnoFirst==p2->pgnoFirst );
- assert_nc( p1->pgnoLast==p2->pgnoLast );
- }
- }
- fts5StructureRelease(pTest);
- }
- }
-#endif
-
- if( p->rc!=SQLITE_OK ) return 0;
- assert( p->iStructVersion!=0 );
- assert( p->pStruct!=0 );
- fts5StructureRef(p->pStruct);
- return p->pStruct;
-}
-
-static void fts5StructureInvalidate(Fts5Index *p){
- if( p->pStruct ){
- fts5StructureRelease(p->pStruct);
- p->pStruct = 0;
- }
-}
-
-/*
-** Return the total number of segments in index structure pStruct. This
-** function is only ever used as part of assert() conditions.
-*/
-#ifdef SQLITE_DEBUG
-static int fts5StructureCountSegments(Fts5Structure *pStruct){
- int nSegment = 0; /* Total number of segments */
- if( pStruct ){
- int iLvl; /* Used to iterate through levels */
- for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
- nSegment += pStruct->aLevel[iLvl].nSeg;
- }
- }
-
- return nSegment;
-}
-#endif
-
-#define fts5BufferSafeAppendBlob(pBuf, pBlob, nBlob) { \
- assert( (pBuf)->nSpace>=((pBuf)->n+nBlob) ); \
- memcpy(&(pBuf)->p[(pBuf)->n], pBlob, nBlob); \
- (pBuf)->n += nBlob; \
-}
-
-#define fts5BufferSafeAppendVarint(pBuf, iVal) { \
- (pBuf)->n += sqlite3Fts5PutVarint(&(pBuf)->p[(pBuf)->n], (iVal)); \
- assert( (pBuf)->nSpace>=(pBuf)->n ); \
-}
-
-
-/*
-** Serialize and store the "structure" record.
-**
-** If an error occurs, leave an error code in the Fts5Index object. If an
-** error has already occurred, this function is a no-op.
-*/
-static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){
- if( p->rc==SQLITE_OK ){
- Fts5Buffer buf; /* Buffer to serialize record into */
- int iLvl; /* Used to iterate through levels */
- int iCookie; /* Cookie value to store */
-
- assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) );
- memset(&buf, 0, sizeof(Fts5Buffer));
-
- /* Append the current configuration cookie */
- iCookie = p->pConfig->iCookie;
- if( iCookie<0 ) iCookie = 0;
-
- if( 0==sqlite3Fts5BufferSize(&p->rc, &buf, 4+9+9+9) ){
- sqlite3Fts5Put32(buf.p, iCookie);
- buf.n = 4;
- fts5BufferSafeAppendVarint(&buf, pStruct->nLevel);
- fts5BufferSafeAppendVarint(&buf, pStruct->nSegment);
- fts5BufferSafeAppendVarint(&buf, (i64)pStruct->nWriteCounter);
- }
-
- for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
- int iSeg; /* Used to iterate through segments */
- Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
- fts5BufferAppendVarint(&p->rc, &buf, pLvl->nMerge);
- fts5BufferAppendVarint(&p->rc, &buf, pLvl->nSeg);
- assert( pLvl->nMerge<=pLvl->nSeg );
-
- for(iSeg=0; iSeg<pLvl->nSeg; iSeg++){
- fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].iSegid);
- fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoFirst);
- fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoLast);
- }
- }
-
- fts5DataWrite(p, FTS5_STRUCTURE_ROWID, buf.p, buf.n);
- fts5BufferFree(&buf);
- }
-}
-
-#if 0
-static void fts5DebugStructure(int*,Fts5Buffer*,Fts5Structure*);
-static void fts5PrintStructure(const char *zCaption, Fts5Structure *pStruct){
- int rc = SQLITE_OK;
- Fts5Buffer buf;
- memset(&buf, 0, sizeof(buf));
- fts5DebugStructure(&rc, &buf, pStruct);
- fprintf(stdout, "%s: %s\n", zCaption, buf.p);
- fflush(stdout);
- fts5BufferFree(&buf);
-}
-#else
-# define fts5PrintStructure(x,y)
-#endif
-
-static int fts5SegmentSize(Fts5StructureSegment *pSeg){
- return 1 + pSeg->pgnoLast - pSeg->pgnoFirst;
-}
-
-/*
-** Return a copy of index structure pStruct. Except, promote as many
-** segments as possible to level iPromote. If an OOM occurs, NULL is
-** returned.
-*/
-static void fts5StructurePromoteTo(
- Fts5Index *p,
- int iPromote,
- int szPromote,
- Fts5Structure *pStruct
-){
- int il, is;
- Fts5StructureLevel *pOut = &pStruct->aLevel[iPromote];
-
- if( pOut->nMerge==0 ){
- for(il=iPromote+1; il<pStruct->nLevel; il++){
- Fts5StructureLevel *pLvl = &pStruct->aLevel[il];
- if( pLvl->nMerge ) return;
- for(is=pLvl->nSeg-1; is>=0; is--){
- int sz = fts5SegmentSize(&pLvl->aSeg[is]);
- if( sz>szPromote ) return;
- fts5StructureExtendLevel(&p->rc, pStruct, iPromote, 1, 1);
- if( p->rc ) return;
- memcpy(pOut->aSeg, &pLvl->aSeg[is], sizeof(Fts5StructureSegment));
- pOut->nSeg++;
- pLvl->nSeg--;
- }
- }
- }
-}
-
-/*
-** A new segment has just been written to level iLvl of index structure
-** pStruct. This function determines if any segments should be promoted
-** as a result. Segments are promoted in two scenarios:
-**
-** a) If the segment just written is smaller than one or more segments
-** within the previous populated level, it is promoted to the previous
-** populated level.
-**
-** b) If the segment just written is larger than the newest segment on
-** the next populated level, then that segment, and any other adjacent
-** segments that are also smaller than the one just written, are
-** promoted.
-**
-** If one or more segments are promoted, the structure object is updated
-** to reflect this.
-*/
-static void fts5StructurePromote(
- Fts5Index *p, /* FTS5 backend object */
- int iLvl, /* Index level just updated */
- Fts5Structure *pStruct /* Index structure */
-){
- if( p->rc==SQLITE_OK ){
- int iTst;
- int iPromote = -1;
- int szPromote = 0; /* Promote anything this size or smaller */
- Fts5StructureSegment *pSeg; /* Segment just written */
- int szSeg; /* Size of segment just written */
- int nSeg = pStruct->aLevel[iLvl].nSeg;
-
- if( nSeg==0 ) return;
- pSeg = &pStruct->aLevel[iLvl].aSeg[pStruct->aLevel[iLvl].nSeg-1];
- szSeg = (1 + pSeg->pgnoLast - pSeg->pgnoFirst);
-
- /* Check for condition (a) */
- for(iTst=iLvl-1; iTst>=0 && pStruct->aLevel[iTst].nSeg==0; iTst--);
- if( iTst>=0 ){
- int i;
- int szMax = 0;
- Fts5StructureLevel *pTst = &pStruct->aLevel[iTst];
- assert( pTst->nMerge==0 );
- for(i=0; i<pTst->nSeg; i++){
- int sz = pTst->aSeg[i].pgnoLast - pTst->aSeg[i].pgnoFirst + 1;
- if( sz>szMax ) szMax = sz;
- }
- if( szMax>=szSeg ){
- /* Condition (a) is true. Promote the newest segment on level
- ** iLvl to level iTst. */
- iPromote = iTst;
- szPromote = szMax;
- }
- }
-
- /* If condition (a) is not met, assume (b) is true. StructurePromoteTo()
- ** is a no-op if it is not. */
- if( iPromote<0 ){
- iPromote = iLvl;
- szPromote = szSeg;
- }
- fts5StructurePromoteTo(p, iPromote, szPromote, pStruct);
- }
-}
-
-
-/*
-** Advance the iterator passed as the only argument. If the end of the
-** doclist-index page is reached, return non-zero.
-*/
-static int fts5DlidxLvlNext(Fts5DlidxLvl *pLvl){
- Fts5Data *pData = pLvl->pData;
-
- if( pLvl->iOff==0 ){
- assert( pLvl->bEof==0 );
- pLvl->iOff = 1;
- pLvl->iOff += fts5GetVarint32(&pData->p[1], pLvl->iLeafPgno);
- pLvl->iOff += fts5GetVarint(&pData->p[pLvl->iOff], (u64*)&pLvl->iRowid);
- pLvl->iFirstOff = pLvl->iOff;
- }else{
- int iOff;
- for(iOff=pLvl->iOff; iOff<pData->nn; iOff++){
- if( pData->p[iOff] ) break;
- }
-
- if( iOff<pData->nn ){
- i64 iVal;
- pLvl->iLeafPgno += (iOff - pLvl->iOff) + 1;
- iOff += fts5GetVarint(&pData->p[iOff], (u64*)&iVal);
- pLvl->iRowid += iVal;
- pLvl->iOff = iOff;
- }else{
- pLvl->bEof = 1;
- }
- }
-
- return pLvl->bEof;
-}
-
-/*
-** Advance the iterator passed as the only argument.
-*/
-static int fts5DlidxIterNextR(Fts5Index *p, Fts5DlidxIter *pIter, int iLvl){
- Fts5DlidxLvl *pLvl = &pIter->aLvl[iLvl];
-
- assert( iLvl<pIter->nLvl );
- if( fts5DlidxLvlNext(pLvl) ){
- if( (iLvl+1) < pIter->nLvl ){
- fts5DlidxIterNextR(p, pIter, iLvl+1);
- if( pLvl[1].bEof==0 ){
- fts5DataRelease(pLvl->pData);
- memset(pLvl, 0, sizeof(Fts5DlidxLvl));
- pLvl->pData = fts5DataRead(p,
- FTS5_DLIDX_ROWID(pIter->iSegid, iLvl, pLvl[1].iLeafPgno)
- );
- if( pLvl->pData ) fts5DlidxLvlNext(pLvl);
- }
- }
- }
-
- return pIter->aLvl[0].bEof;
-}
-static int fts5DlidxIterNext(Fts5Index *p, Fts5DlidxIter *pIter){
- return fts5DlidxIterNextR(p, pIter, 0);
-}
-
-/*
-** The iterator passed as the first argument has the following fields set
-** as follows. This function sets up the rest of the iterator so that it
-** points to the first rowid in the doclist-index.
-**
-** pData:
-** pointer to doclist-index record,
-**
-** When this function is called pIter->iLeafPgno is the page number the
-** doclist is associated with (the one featuring the term).
-*/
-static int fts5DlidxIterFirst(Fts5DlidxIter *pIter){
- int i;
- for(i=0; i<pIter->nLvl; i++){
- fts5DlidxLvlNext(&pIter->aLvl[i]);
- }
- return pIter->aLvl[0].bEof;
-}
-
-
-static int fts5DlidxIterEof(Fts5Index *p, Fts5DlidxIter *pIter){
- return p->rc!=SQLITE_OK || pIter->aLvl[0].bEof;
-}
-
-static void fts5DlidxIterLast(Fts5Index *p, Fts5DlidxIter *pIter){
- int i;
-
- /* Advance each level to the last entry on the last page */
- for(i=pIter->nLvl-1; p->rc==SQLITE_OK && i>=0; i--){
- Fts5DlidxLvl *pLvl = &pIter->aLvl[i];
- while( fts5DlidxLvlNext(pLvl)==0 );
- pLvl->bEof = 0;
-
- if( i>0 ){
- Fts5DlidxLvl *pChild = &pLvl[-1];
- fts5DataRelease(pChild->pData);
- memset(pChild, 0, sizeof(Fts5DlidxLvl));
- pChild->pData = fts5DataRead(p,
- FTS5_DLIDX_ROWID(pIter->iSegid, i-1, pLvl->iLeafPgno)
- );
- }
- }
-}
-
-/*
-** Move the iterator passed as the only argument to the previous entry.
-*/
-static int fts5DlidxLvlPrev(Fts5DlidxLvl *pLvl){
- int iOff = pLvl->iOff;
-
- assert( pLvl->bEof==0 );
- if( iOff<=pLvl->iFirstOff ){
- pLvl->bEof = 1;
- }else{
- u8 *a = pLvl->pData->p;
- i64 iVal;
- int iLimit;
- int ii;
- int nZero = 0;
-
- /* Currently iOff points to the first byte of a varint. This block
- ** decrements iOff until it points to the first byte of the previous
- ** varint. Taking care not to read any memory locations that occur
- ** before the buffer in memory. */
- iLimit = (iOff>9 ? iOff-9 : 0);
- for(iOff--; iOff>iLimit; iOff--){
- if( (a[iOff-1] & 0x80)==0 ) break;
- }
-
- fts5GetVarint(&a[iOff], (u64*)&iVal);
- pLvl->iRowid -= iVal;
- pLvl->iLeafPgno--;
-
- /* Skip backwards past any 0x00 varints. */
- for(ii=iOff-1; ii>=pLvl->iFirstOff && a[ii]==0x00; ii--){
- nZero++;
- }
- if( ii>=pLvl->iFirstOff && (a[ii] & 0x80) ){
- /* The byte immediately before the last 0x00 byte has the 0x80 bit
- ** set. So the last 0x00 is only a varint 0 if there are 8 more 0x80
- ** bytes before a[ii]. */
- int bZero = 0; /* True if last 0x00 counts */
- if( (ii-8)>=pLvl->iFirstOff ){
- int j;
- for(j=1; j<=8 && (a[ii-j] & 0x80); j++);
- bZero = (j>8);
- }
- if( bZero==0 ) nZero--;
- }
- pLvl->iLeafPgno -= nZero;
- pLvl->iOff = iOff - nZero;
- }
-
- return pLvl->bEof;
-}
-
-static int fts5DlidxIterPrevR(Fts5Index *p, Fts5DlidxIter *pIter, int iLvl){
- Fts5DlidxLvl *pLvl = &pIter->aLvl[iLvl];
-
- assert( iLvl<pIter->nLvl );
- if( fts5DlidxLvlPrev(pLvl) ){
- if( (iLvl+1) < pIter->nLvl ){
- fts5DlidxIterPrevR(p, pIter, iLvl+1);
- if( pLvl[1].bEof==0 ){
- fts5DataRelease(pLvl->pData);
- memset(pLvl, 0, sizeof(Fts5DlidxLvl));
- pLvl->pData = fts5DataRead(p,
- FTS5_DLIDX_ROWID(pIter->iSegid, iLvl, pLvl[1].iLeafPgno)
- );
- if( pLvl->pData ){
- while( fts5DlidxLvlNext(pLvl)==0 );
- pLvl->bEof = 0;
- }
- }
- }
- }
-
- return pIter->aLvl[0].bEof;
-}
-static int fts5DlidxIterPrev(Fts5Index *p, Fts5DlidxIter *pIter){
- return fts5DlidxIterPrevR(p, pIter, 0);
-}
-
-/*
-** Free a doclist-index iterator object allocated by fts5DlidxIterInit().
-*/
-static void fts5DlidxIterFree(Fts5DlidxIter *pIter){
- if( pIter ){
- int i;
- for(i=0; i<pIter->nLvl; i++){
- fts5DataRelease(pIter->aLvl[i].pData);
- }
- sqlite3_free(pIter);
- }
-}
-
-static Fts5DlidxIter *fts5DlidxIterInit(
- Fts5Index *p, /* Fts5 Backend to iterate within */
- int bRev, /* True for ORDER BY ASC */
- int iSegid, /* Segment id */
- int iLeafPg /* Leaf page number to load dlidx for */
-){
- Fts5DlidxIter *pIter = 0;
- int i;
- int bDone = 0;
-
- for(i=0; p->rc==SQLITE_OK && bDone==0; i++){
- int nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl);
- Fts5DlidxIter *pNew;
-
- pNew = (Fts5DlidxIter*)sqlite3_realloc(pIter, nByte);
- if( pNew==0 ){
- p->rc = SQLITE_NOMEM;
- }else{
- i64 iRowid = FTS5_DLIDX_ROWID(iSegid, i, iLeafPg);
- Fts5DlidxLvl *pLvl = &pNew->aLvl[i];
- pIter = pNew;
- memset(pLvl, 0, sizeof(Fts5DlidxLvl));
- pLvl->pData = fts5DataRead(p, iRowid);
- if( pLvl->pData && (pLvl->pData->p[0] & 0x0001)==0 ){
- bDone = 1;
- }
- pIter->nLvl = i+1;
- }
- }
-
- if( p->rc==SQLITE_OK ){
- pIter->iSegid = iSegid;
- if( bRev==0 ){
- fts5DlidxIterFirst(pIter);
- }else{
- fts5DlidxIterLast(p, pIter);
- }
- }
-
- if( p->rc!=SQLITE_OK ){
- fts5DlidxIterFree(pIter);
- pIter = 0;
- }
-
- return pIter;
-}
-
-static i64 fts5DlidxIterRowid(Fts5DlidxIter *pIter){
- return pIter->aLvl[0].iRowid;
-}
-static int fts5DlidxIterPgno(Fts5DlidxIter *pIter){
- return pIter->aLvl[0].iLeafPgno;
-}
-
-/*
-** Load the next leaf page into the segment iterator.
-*/
-static void fts5SegIterNextPage(
- Fts5Index *p, /* FTS5 backend object */
- Fts5SegIter *pIter /* Iterator to advance to next page */
-){
- Fts5Data *pLeaf;
- Fts5StructureSegment *pSeg = pIter->pSeg;
- fts5DataRelease(pIter->pLeaf);
- pIter->iLeafPgno++;
- if( pIter->pNextLeaf ){
- pIter->pLeaf = pIter->pNextLeaf;
- pIter->pNextLeaf = 0;
- }else if( pIter->iLeafPgno<=pSeg->pgnoLast ){
- pIter->pLeaf = fts5DataRead(p,
- FTS5_SEGMENT_ROWID(pSeg->iSegid, pIter->iLeafPgno)
- );
- }else{
- pIter->pLeaf = 0;
- }
- pLeaf = pIter->pLeaf;
-
- if( pLeaf ){
- pIter->iPgidxOff = pLeaf->szLeaf;
- if( fts5LeafIsTermless(pLeaf) ){
- pIter->iEndofDoclist = pLeaf->nn+1;
- }else{
- pIter->iPgidxOff += fts5GetVarint32(&pLeaf->p[pIter->iPgidxOff],
- pIter->iEndofDoclist
- );
- }
- }
-}
-
-/*
-** Argument p points to a buffer containing a varint to be interpreted as a
-** position list size field. Read the varint and return the number of bytes
-** read. Before returning, set *pnSz to the number of bytes in the position
-** list, and *pbDel to true if the delete flag is set, or false otherwise.
-*/
-static int fts5GetPoslistSize(const u8 *p, int *pnSz, int *pbDel){
- int nSz;
- int n = 0;
- fts5FastGetVarint32(p, n, nSz);
- assert_nc( nSz>=0 );
- *pnSz = nSz/2;
- *pbDel = nSz & 0x0001;
- return n;
-}
-
-/*
-** Fts5SegIter.iLeafOffset currently points to the first byte of a
-** position-list size field. Read the value of the field and store it
-** in the following variables:
-**
-** Fts5SegIter.nPos
-** Fts5SegIter.bDel
-**
-** Leave Fts5SegIter.iLeafOffset pointing to the first byte of the
-** position list content (if any).
-*/
-static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){
- if( p->rc==SQLITE_OK ){
- int iOff = pIter->iLeafOffset; /* Offset to read at */
- ASSERT_SZLEAF_OK(pIter->pLeaf);
- if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
- int iEod = MIN(pIter->iEndofDoclist, pIter->pLeaf->szLeaf);
- pIter->bDel = 0;
- pIter->nPos = 1;
- if( iOff<iEod && pIter->pLeaf->p[iOff]==0 ){
- pIter->bDel = 1;
- iOff++;
- if( iOff<iEod && pIter->pLeaf->p[iOff]==0 ){
- pIter->nPos = 1;
- iOff++;
- }else{
- pIter->nPos = 0;
- }
- }
- }else{
- int nSz;
- fts5FastGetVarint32(pIter->pLeaf->p, iOff, nSz);
- pIter->bDel = (nSz & 0x0001);
- pIter->nPos = nSz>>1;
- assert_nc( pIter->nPos>=0 );
- }
- pIter->iLeafOffset = iOff;
- }
-}
-
-static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){
- u8 *a = pIter->pLeaf->p; /* Buffer to read data from */
- int iOff = pIter->iLeafOffset;
-
- ASSERT_SZLEAF_OK(pIter->pLeaf);
- if( iOff>=pIter->pLeaf->szLeaf ){
- fts5SegIterNextPage(p, pIter);
- if( pIter->pLeaf==0 ){
- if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT;
- return;
- }
- iOff = 4;
- a = pIter->pLeaf->p;
- }
- iOff += sqlite3Fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid);
- pIter->iLeafOffset = iOff;
-}
-
-/*
-** Fts5SegIter.iLeafOffset currently points to the first byte of the
-** "nSuffix" field of a term. Function parameter nKeep contains the value
-** of the "nPrefix" field (if there was one - it is passed 0 if this is
-** the first term in the segment).
-**
-** This function populates:
-**
-** Fts5SegIter.term
-** Fts5SegIter.rowid
-**
-** accordingly and leaves (Fts5SegIter.iLeafOffset) set to the content of
-** the first position list. The position list belonging to document
-** (Fts5SegIter.iRowid).
-*/
-static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){
- u8 *a = pIter->pLeaf->p; /* Buffer to read data from */
- int iOff = pIter->iLeafOffset; /* Offset to read at */
- int nNew; /* Bytes of new data */
-
- iOff += fts5GetVarint32(&a[iOff], nNew);
- if( iOff+nNew>pIter->pLeaf->nn ){
- p->rc = FTS5_CORRUPT;
- return;
- }
- pIter->term.n = nKeep;
- fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]);
- iOff += nNew;
- pIter->iTermLeafOffset = iOff;
- pIter->iTermLeafPgno = pIter->iLeafPgno;
- pIter->iLeafOffset = iOff;
-
- if( pIter->iPgidxOff>=pIter->pLeaf->nn ){
- pIter->iEndofDoclist = pIter->pLeaf->nn+1;
- }else{
- int nExtra;
- pIter->iPgidxOff += fts5GetVarint32(&a[pIter->iPgidxOff], nExtra);
- pIter->iEndofDoclist += nExtra;
- }
-
- fts5SegIterLoadRowid(p, pIter);
-}
-
-static void fts5SegIterNext(Fts5Index*, Fts5SegIter*, int*);
-static void fts5SegIterNext_Reverse(Fts5Index*, Fts5SegIter*, int*);
-static void fts5SegIterNext_None(Fts5Index*, Fts5SegIter*, int*);
-
-static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){
- if( pIter->flags & FTS5_SEGITER_REVERSE ){
- pIter->xNext = fts5SegIterNext_Reverse;
- }else if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
- pIter->xNext = fts5SegIterNext_None;
- }else{
- pIter->xNext = fts5SegIterNext;
- }
-}
-
-/*
-** Initialize the iterator object pIter to iterate through the entries in
-** segment pSeg. The iterator is left pointing to the first entry when
-** this function returns.
-**
-** If an error occurs, Fts5Index.rc is set to an appropriate error code. If
-** an error has already occurred when this function is called, it is a no-op.
-*/
-static void fts5SegIterInit(
- Fts5Index *p, /* FTS index object */
- Fts5StructureSegment *pSeg, /* Description of segment */
- Fts5SegIter *pIter /* Object to populate */
-){
- if( pSeg->pgnoFirst==0 ){
- /* This happens if the segment is being used as an input to an incremental
- ** merge and all data has already been "trimmed". See function
- ** fts5TrimSegments() for details. In this case leave the iterator empty.
- ** The caller will see the (pIter->pLeaf==0) and assume the iterator is
- ** at EOF already. */
- assert( pIter->pLeaf==0 );
- return;
- }
-
- if( p->rc==SQLITE_OK ){
- memset(pIter, 0, sizeof(*pIter));
- fts5SegIterSetNext(p, pIter);
- pIter->pSeg = pSeg;
- pIter->iLeafPgno = pSeg->pgnoFirst-1;
- fts5SegIterNextPage(p, pIter);
- }
-
- if( p->rc==SQLITE_OK ){
- pIter->iLeafOffset = 4;
- assert_nc( pIter->pLeaf->nn>4 );
- assert( fts5LeafFirstTermOff(pIter->pLeaf)==4 );
- pIter->iPgidxOff = pIter->pLeaf->szLeaf+1;
- fts5SegIterLoadTerm(p, pIter, 0);
- fts5SegIterLoadNPos(p, pIter);
- }
-}
-
-/*
-** This function is only ever called on iterators created by calls to
-** Fts5IndexQuery() with the FTS5INDEX_QUERY_DESC flag set.
-**
-** The iterator is in an unusual state when this function is called: the
-** Fts5SegIter.iLeafOffset variable is set to the offset of the start of
-** the position-list size field for the first relevant rowid on the page.
-** Fts5SegIter.rowid is set, but nPos and bDel are not.
-**
-** This function advances the iterator so that it points to the last
-** relevant rowid on the page and, if necessary, initializes the
-** aRowidOffset[] and iRowidOffset variables. At this point the iterator
-** is in its regular state - Fts5SegIter.iLeafOffset points to the first
-** byte of the position list content associated with said rowid.
-*/
-static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
- int eDetail = p->pConfig->eDetail;
- int n = pIter->pLeaf->szLeaf;
- int i = pIter->iLeafOffset;
- u8 *a = pIter->pLeaf->p;
- int iRowidOffset = 0;
-
- if( n>pIter->iEndofDoclist ){
- n = pIter->iEndofDoclist;
- }
-
- ASSERT_SZLEAF_OK(pIter->pLeaf);
- while( 1 ){
- i64 iDelta = 0;
-
- if( eDetail==FTS5_DETAIL_NONE ){
- /* todo */
- if( i<n && a[i]==0 ){
- i++;
- if( i<n && a[i]==0 ) i++;
- }
- }else{
- int nPos;
- int bDummy;
- i += fts5GetPoslistSize(&a[i], &nPos, &bDummy);
- i += nPos;
- }
- if( i>=n ) break;
- i += fts5GetVarint(&a[i], (u64*)&iDelta);
- pIter->iRowid += iDelta;
-
- /* If necessary, grow the pIter->aRowidOffset[] array. */
- if( iRowidOffset>=pIter->nRowidOffset ){
- int nNew = pIter->nRowidOffset + 8;
- int *aNew = (int*)sqlite3_realloc(pIter->aRowidOffset, nNew*sizeof(int));
- if( aNew==0 ){
- p->rc = SQLITE_NOMEM;
- break;
- }
- pIter->aRowidOffset = aNew;
- pIter->nRowidOffset = nNew;
- }
-
- pIter->aRowidOffset[iRowidOffset++] = pIter->iLeafOffset;
- pIter->iLeafOffset = i;
- }
- pIter->iRowidOffset = iRowidOffset;
- fts5SegIterLoadNPos(p, pIter);
-}
-
-/*
-**
-*/
-static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){
- assert( pIter->flags & FTS5_SEGITER_REVERSE );
- assert( pIter->flags & FTS5_SEGITER_ONETERM );
-
- fts5DataRelease(pIter->pLeaf);
- pIter->pLeaf = 0;
- while( p->rc==SQLITE_OK && pIter->iLeafPgno>pIter->iTermLeafPgno ){
- Fts5Data *pNew;
- pIter->iLeafPgno--;
- pNew = fts5DataRead(p, FTS5_SEGMENT_ROWID(
- pIter->pSeg->iSegid, pIter->iLeafPgno
- ));
- if( pNew ){
- /* iTermLeafOffset may be equal to szLeaf if the term is the last
- ** thing on the page - i.e. the first rowid is on the following page.
- ** In this case leave pIter->pLeaf==0, this iterator is at EOF. */
- if( pIter->iLeafPgno==pIter->iTermLeafPgno ){
- assert( pIter->pLeaf==0 );
- if( pIter->iTermLeafOffset<pNew->szLeaf ){
- pIter->pLeaf = pNew;
- pIter->iLeafOffset = pIter->iTermLeafOffset;
- }
- }else{
- int iRowidOff;
- iRowidOff = fts5LeafFirstRowidOff(pNew);
- if( iRowidOff ){
- pIter->pLeaf = pNew;
- pIter->iLeafOffset = iRowidOff;
- }
- }
-
- if( pIter->pLeaf ){
- u8 *a = &pIter->pLeaf->p[pIter->iLeafOffset];
- pIter->iLeafOffset += fts5GetVarint(a, (u64*)&pIter->iRowid);
- break;
- }else{
- fts5DataRelease(pNew);
- }
- }
- }
-
- if( pIter->pLeaf ){
- pIter->iEndofDoclist = pIter->pLeaf->nn+1;
- fts5SegIterReverseInitPage(p, pIter);
- }
-}
-
-/*
-** Return true if the iterator passed as the second argument currently
-** points to a delete marker. A delete marker is an entry with a 0 byte
-** position-list.
-*/
-static int fts5MultiIterIsEmpty(Fts5Index *p, Fts5Iter *pIter){
- Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
- return (p->rc==SQLITE_OK && pSeg->pLeaf && pSeg->nPos==0);
-}
-
-/*
-** Advance iterator pIter to the next entry.
-**
-** This version of fts5SegIterNext() is only used by reverse iterators.
-*/
-static void fts5SegIterNext_Reverse(
- Fts5Index *p, /* FTS5 backend object */
- Fts5SegIter *pIter, /* Iterator to advance */
- int *pbUnused /* Unused */
-){
- assert( pIter->flags & FTS5_SEGITER_REVERSE );
- assert( pIter->pNextLeaf==0 );
- UNUSED_PARAM(pbUnused);
-
- if( pIter->iRowidOffset>0 ){
- u8 *a = pIter->pLeaf->p;
- int iOff;
- i64 iDelta;
-
- pIter->iRowidOffset--;
- pIter->iLeafOffset = pIter->aRowidOffset[pIter->iRowidOffset];
- fts5SegIterLoadNPos(p, pIter);
- iOff = pIter->iLeafOffset;
- if( p->pConfig->eDetail!=FTS5_DETAIL_NONE ){
- iOff += pIter->nPos;
- }
- fts5GetVarint(&a[iOff], (u64*)&iDelta);
- pIter->iRowid -= iDelta;
- }else{
- fts5SegIterReverseNewPage(p, pIter);
- }
-}
-
-/*
-** Advance iterator pIter to the next entry.
-**
-** This version of fts5SegIterNext() is only used if detail=none and the
-** iterator is not a reverse direction iterator.
-*/
-static void fts5SegIterNext_None(
- Fts5Index *p, /* FTS5 backend object */
- Fts5SegIter *pIter, /* Iterator to advance */
- int *pbNewTerm /* OUT: Set for new term */
-){
- int iOff;
-
- assert( p->rc==SQLITE_OK );
- assert( (pIter->flags & FTS5_SEGITER_REVERSE)==0 );
- assert( p->pConfig->eDetail==FTS5_DETAIL_NONE );
-
- ASSERT_SZLEAF_OK(pIter->pLeaf);
- iOff = pIter->iLeafOffset;
-
- /* Next entry is on the next page */
- if( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){
- fts5SegIterNextPage(p, pIter);
- if( p->rc || pIter->pLeaf==0 ) return;
- pIter->iRowid = 0;
- iOff = 4;
- }
-
- if( iOff<pIter->iEndofDoclist ){
- /* Next entry is on the current page */
- i64 iDelta;
- iOff += sqlite3Fts5GetVarint(&pIter->pLeaf->p[iOff], (u64*)&iDelta);
- pIter->iLeafOffset = iOff;
- pIter->iRowid += iDelta;
- }else if( (pIter->flags & FTS5_SEGITER_ONETERM)==0 ){
- if( pIter->pSeg ){
- int nKeep = 0;
- if( iOff!=fts5LeafFirstTermOff(pIter->pLeaf) ){
- iOff += fts5GetVarint32(&pIter->pLeaf->p[iOff], nKeep);
- }
- pIter->iLeafOffset = iOff;
- fts5SegIterLoadTerm(p, pIter, nKeep);
- }else{
- const u8 *pList = 0;
- const char *zTerm = 0;
- int nList;
- sqlite3Fts5HashScanNext(p->pHash);
- sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
- if( pList==0 ) goto next_none_eof;
- pIter->pLeaf->p = (u8*)pList;
- pIter->pLeaf->nn = nList;
- pIter->pLeaf->szLeaf = nList;
- pIter->iEndofDoclist = nList;
- sqlite3Fts5BufferSet(&p->rc,&pIter->term, (int)strlen(zTerm), (u8*)zTerm);
- pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
- }
-
- if( pbNewTerm ) *pbNewTerm = 1;
- }else{
- goto next_none_eof;
- }
-
- fts5SegIterLoadNPos(p, pIter);
-
- return;
- next_none_eof:
- fts5DataRelease(pIter->pLeaf);
- pIter->pLeaf = 0;
-}
-
-
-/*
-** Advance iterator pIter to the next entry.
-**
-** If an error occurs, Fts5Index.rc is set to an appropriate error code. It
-** is not considered an error if the iterator reaches EOF. If an error has
-** already occurred when this function is called, it is a no-op.
-*/
-static void fts5SegIterNext(
- Fts5Index *p, /* FTS5 backend object */
- Fts5SegIter *pIter, /* Iterator to advance */
- int *pbNewTerm /* OUT: Set for new term */
-){
- Fts5Data *pLeaf = pIter->pLeaf;
- int iOff;
- int bNewTerm = 0;
- int nKeep = 0;
- u8 *a;
- int n;
-
- assert( pbNewTerm==0 || *pbNewTerm==0 );
- assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE );
-
- /* Search for the end of the position list within the current page. */
- a = pLeaf->p;
- n = pLeaf->szLeaf;
-
- ASSERT_SZLEAF_OK(pLeaf);
- iOff = pIter->iLeafOffset + pIter->nPos;
-
- if( iOff<n ){
- /* The next entry is on the current page. */
- assert_nc( iOff<=pIter->iEndofDoclist );
- if( iOff>=pIter->iEndofDoclist ){
- bNewTerm = 1;
- if( iOff!=fts5LeafFirstTermOff(pLeaf) ){
- iOff += fts5GetVarint32(&a[iOff], nKeep);
- }
- }else{
- u64 iDelta;
- iOff += sqlite3Fts5GetVarint(&a[iOff], &iDelta);
- pIter->iRowid += iDelta;
- assert_nc( iDelta>0 );
- }
- pIter->iLeafOffset = iOff;
-
- }else if( pIter->pSeg==0 ){
- const u8 *pList = 0;
- const char *zTerm = 0;
- int nList = 0;
- assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm );
- if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){
- sqlite3Fts5HashScanNext(p->pHash);
- sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
- }
- if( pList==0 ){
- fts5DataRelease(pIter->pLeaf);
- pIter->pLeaf = 0;
- }else{
- pIter->pLeaf->p = (u8*)pList;
- pIter->pLeaf->nn = nList;
- pIter->pLeaf->szLeaf = nList;
- pIter->iEndofDoclist = nList+1;
- sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm),
- (u8*)zTerm);
- pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
- *pbNewTerm = 1;
- }
- }else{
- iOff = 0;
- /* Next entry is not on the current page */
- while( iOff==0 ){
- fts5SegIterNextPage(p, pIter);
- pLeaf = pIter->pLeaf;
- if( pLeaf==0 ) break;
- ASSERT_SZLEAF_OK(pLeaf);
- if( (iOff = fts5LeafFirstRowidOff(pLeaf)) && iOff<pLeaf->szLeaf ){
- iOff += sqlite3Fts5GetVarint(&pLeaf->p[iOff], (u64*)&pIter->iRowid);
- pIter->iLeafOffset = iOff;
-
- if( pLeaf->nn>pLeaf->szLeaf ){
- pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
- &pLeaf->p[pLeaf->szLeaf], pIter->iEndofDoclist
- );
- }
-
- }
- else if( pLeaf->nn>pLeaf->szLeaf ){
- pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
- &pLeaf->p[pLeaf->szLeaf], iOff
- );
- pIter->iLeafOffset = iOff;
- pIter->iEndofDoclist = iOff;
- bNewTerm = 1;
- }
- assert_nc( iOff<pLeaf->szLeaf );
- if( iOff>pLeaf->szLeaf ){
- p->rc = FTS5_CORRUPT;
- return;
- }
- }
- }
-
- /* Check if the iterator is now at EOF. If so, return early. */
- if( pIter->pLeaf ){
- if( bNewTerm ){
- if( pIter->flags & FTS5_SEGITER_ONETERM ){
- fts5DataRelease(pIter->pLeaf);
- pIter->pLeaf = 0;
- }else{
- fts5SegIterLoadTerm(p, pIter, nKeep);
- fts5SegIterLoadNPos(p, pIter);
- if( pbNewTerm ) *pbNewTerm = 1;
- }
- }else{
- /* The following could be done by calling fts5SegIterLoadNPos(). But
- ** this block is particularly performance critical, so equivalent
- ** code is inlined.
- **
- ** Later: Switched back to fts5SegIterLoadNPos() because it supports
- ** detail=none mode. Not ideal.
- */
- int nSz;
- assert( p->rc==SQLITE_OK );
- fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz);
- pIter->bDel = (nSz & 0x0001);
- pIter->nPos = nSz>>1;
- assert_nc( pIter->nPos>=0 );
- }
- }
-}
-
-#define SWAPVAL(T, a, b) { T tmp; tmp=a; a=b; b=tmp; }
-
-#define fts5IndexSkipVarint(a, iOff) { \
- int iEnd = iOff+9; \
- while( (a[iOff++] & 0x80) && iOff<iEnd ); \
-}
-
-/*
-** Iterator pIter currently points to the first rowid in a doclist. This
-** function sets the iterator up so that iterates in reverse order through
-** the doclist.
-*/
-static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){
- Fts5DlidxIter *pDlidx = pIter->pDlidx;
- Fts5Data *pLast = 0;
- int pgnoLast = 0;
-
- if( pDlidx ){
- int iSegid = pIter->pSeg->iSegid;
- pgnoLast = fts5DlidxIterPgno(pDlidx);
- pLast = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast));
- }else{
- Fts5Data *pLeaf = pIter->pLeaf; /* Current leaf data */
-
- /* Currently, Fts5SegIter.iLeafOffset points to the first byte of
- ** position-list content for the current rowid. Back it up so that it
- ** points to the start of the position-list size field. */
- int iPoslist;
- if( pIter->iTermLeafPgno==pIter->iLeafPgno ){
- iPoslist = pIter->iTermLeafOffset;
- }else{
- iPoslist = 4;
- }
- fts5IndexSkipVarint(pLeaf->p, iPoslist);
- pIter->iLeafOffset = iPoslist;
-
- /* If this condition is true then the largest rowid for the current
- ** term may not be stored on the current page. So search forward to
- ** see where said rowid really is. */
- if( pIter->iEndofDoclist>=pLeaf->szLeaf ){
- int pgno;
- Fts5StructureSegment *pSeg = pIter->pSeg;
-
- /* The last rowid in the doclist may not be on the current page. Search
- ** forward to find the page containing the last rowid. */
- for(pgno=pIter->iLeafPgno+1; !p->rc && pgno<=pSeg->pgnoLast; pgno++){
- i64 iAbs = FTS5_SEGMENT_ROWID(pSeg->iSegid, pgno);
- Fts5Data *pNew = fts5DataRead(p, iAbs);
- if( pNew ){
- int iRowid, bTermless;
- iRowid = fts5LeafFirstRowidOff(pNew);
- bTermless = fts5LeafIsTermless(pNew);
- if( iRowid ){
- SWAPVAL(Fts5Data*, pNew, pLast);
- pgnoLast = pgno;
- }
- fts5DataRelease(pNew);
- if( bTermless==0 ) break;
- }
- }
- }
- }
-
- /* If pLast is NULL at this point, then the last rowid for this doclist
- ** lies on the page currently indicated by the iterator. In this case
- ** pIter->iLeafOffset is already set to point to the position-list size
- ** field associated with the first relevant rowid on the page.
- **
- ** Or, if pLast is non-NULL, then it is the page that contains the last
- ** rowid. In this case configure the iterator so that it points to the
- ** first rowid on this page.
- */
- if( pLast ){
- int iOff;
- fts5DataRelease(pIter->pLeaf);
- pIter->pLeaf = pLast;
- pIter->iLeafPgno = pgnoLast;
- iOff = fts5LeafFirstRowidOff(pLast);
- iOff += fts5GetVarint(&pLast->p[iOff], (u64*)&pIter->iRowid);
- pIter->iLeafOffset = iOff;
-
- if( fts5LeafIsTermless(pLast) ){
- pIter->iEndofDoclist = pLast->nn+1;
- }else{
- pIter->iEndofDoclist = fts5LeafFirstTermOff(pLast);
- }
-
- }
-
- fts5SegIterReverseInitPage(p, pIter);
-}
-
-/*
-** Iterator pIter currently points to the first rowid of a doclist.
-** There is a doclist-index associated with the final term on the current
-** page. If the current term is the last term on the page, load the
-** doclist-index from disk and initialize an iterator at (pIter->pDlidx).
-*/
-static void fts5SegIterLoadDlidx(Fts5Index *p, Fts5SegIter *pIter){
- int iSeg = pIter->pSeg->iSegid;
- int bRev = (pIter->flags & FTS5_SEGITER_REVERSE);
- Fts5Data *pLeaf = pIter->pLeaf; /* Current leaf data */
-
- assert( pIter->flags & FTS5_SEGITER_ONETERM );
- assert( pIter->pDlidx==0 );
-
- /* Check if the current doclist ends on this page. If it does, return
- ** early without loading the doclist-index (as it belongs to a different
- ** term. */
- if( pIter->iTermLeafPgno==pIter->iLeafPgno
- && pIter->iEndofDoclist<pLeaf->szLeaf
- ){
- return;
- }
-
- pIter->pDlidx = fts5DlidxIterInit(p, bRev, iSeg, pIter->iTermLeafPgno);
-}
-
-/*
-** The iterator object passed as the second argument currently contains
-** no valid values except for the Fts5SegIter.pLeaf member variable. This
-** function searches the leaf page for a term matching (pTerm/nTerm).
-**
-** If the specified term is found on the page, then the iterator is left
-** pointing to it. If argument bGe is zero and the term is not found,
-** the iterator is left pointing at EOF.
-**
-** If bGe is non-zero and the specified term is not found, then the
-** iterator is left pointing to the smallest term in the segment that
-** is larger than the specified term, even if this term is not on the
-** current page.
-*/
-static void fts5LeafSeek(
- Fts5Index *p, /* Leave any error code here */
- int bGe, /* True for a >= search */
- Fts5SegIter *pIter, /* Iterator to seek */
- const u8 *pTerm, int nTerm /* Term to search for */
-){
- int iOff;
- const u8 *a = pIter->pLeaf->p;
- int szLeaf = pIter->pLeaf->szLeaf;
- int n = pIter->pLeaf->nn;
-
- int nMatch = 0;
- int nKeep = 0;
- int nNew = 0;
- int iTermOff;
- int iPgidx; /* Current offset in pgidx */
- int bEndOfPage = 0;
-
- assert( p->rc==SQLITE_OK );
-
- iPgidx = szLeaf;
- iPgidx += fts5GetVarint32(&a[iPgidx], iTermOff);
- iOff = iTermOff;
- if( iOff>n ){
- p->rc = FTS5_CORRUPT;
- return;
- }
-
- while( 1 ){
-
- /* Figure out how many new bytes are in this term */
- fts5FastGetVarint32(a, iOff, nNew);
- if( nKeep<nMatch ){
- goto search_failed;
- }
-
- assert( nKeep>=nMatch );
- if( nKeep==nMatch ){
- int nCmp;
- int i;
- nCmp = MIN(nNew, nTerm-nMatch);
- for(i=0; i<nCmp; i++){
- if( a[iOff+i]!=pTerm[nMatch+i] ) break;
- }
- nMatch += i;
-
- if( nTerm==nMatch ){
- if( i==nNew ){
- goto search_success;
- }else{
- goto search_failed;
- }
- }else if( i<nNew && a[iOff+i]>pTerm[nMatch] ){
- goto search_failed;
- }
- }
-
- if( iPgidx>=n ){
- bEndOfPage = 1;
- break;
- }
-
- iPgidx += fts5GetVarint32(&a[iPgidx], nKeep);
- iTermOff += nKeep;
- iOff = iTermOff;
-
- /* Read the nKeep field of the next term. */
- fts5FastGetVarint32(a, iOff, nKeep);
- }
-
- search_failed:
- if( bGe==0 ){
- fts5DataRelease(pIter->pLeaf);
- pIter->pLeaf = 0;
- return;
- }else if( bEndOfPage ){
- do {
- fts5SegIterNextPage(p, pIter);
- if( pIter->pLeaf==0 ) return;
- a = pIter->pLeaf->p;
- if( fts5LeafIsTermless(pIter->pLeaf)==0 ){
- iPgidx = pIter->pLeaf->szLeaf;
- iPgidx += fts5GetVarint32(&pIter->pLeaf->p[iPgidx], iOff);
- if( iOff<4 || iOff>=pIter->pLeaf->szLeaf ){
- p->rc = FTS5_CORRUPT;
- }else{
- nKeep = 0;
- iTermOff = iOff;
- n = pIter->pLeaf->nn;
- iOff += fts5GetVarint32(&a[iOff], nNew);
- break;
- }
- }
- }while( 1 );
- }
-
- search_success:
-
- pIter->iLeafOffset = iOff + nNew;
- pIter->iTermLeafOffset = pIter->iLeafOffset;
- pIter->iTermLeafPgno = pIter->iLeafPgno;
-
- fts5BufferSet(&p->rc, &pIter->term, nKeep, pTerm);
- fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]);
-
- if( iPgidx>=n ){
- pIter->iEndofDoclist = pIter->pLeaf->nn+1;
- }else{
- int nExtra;
- iPgidx += fts5GetVarint32(&a[iPgidx], nExtra);
- pIter->iEndofDoclist = iTermOff + nExtra;
- }
- pIter->iPgidxOff = iPgidx;
-
- fts5SegIterLoadRowid(p, pIter);
- fts5SegIterLoadNPos(p, pIter);
-}
-
-static sqlite3_stmt *fts5IdxSelectStmt(Fts5Index *p){
- if( p->pIdxSelect==0 ){
- Fts5Config *pConfig = p->pConfig;
- fts5IndexPrepareStmt(p, &p->pIdxSelect, sqlite3_mprintf(
- "SELECT pgno FROM '%q'.'%q_idx' WHERE "
- "segid=? AND term<=? ORDER BY term DESC LIMIT 1",
- pConfig->zDb, pConfig->zName
- ));
- }
- return p->pIdxSelect;
-}
-
-/*
-** Initialize the object pIter to point to term pTerm/nTerm within segment
-** pSeg. If there is no such term in the index, the iterator is set to EOF.
-**
-** If an error occurs, Fts5Index.rc is set to an appropriate error code. If
-** an error has already occurred when this function is called, it is a no-op.
-*/
-static void fts5SegIterSeekInit(
- Fts5Index *p, /* FTS5 backend */
- const u8 *pTerm, int nTerm, /* Term to seek to */
- int flags, /* Mask of FTS5INDEX_XXX flags */
- Fts5StructureSegment *pSeg, /* Description of segment */
- Fts5SegIter *pIter /* Object to populate */
-){
- int iPg = 1;
- int bGe = (flags & FTS5INDEX_QUERY_SCAN);
- int bDlidx = 0; /* True if there is a doclist-index */
- sqlite3_stmt *pIdxSelect = 0;
-
- assert( bGe==0 || (flags & FTS5INDEX_QUERY_DESC)==0 );
- assert( pTerm && nTerm );
- memset(pIter, 0, sizeof(*pIter));
- pIter->pSeg = pSeg;
-
- /* This block sets stack variable iPg to the leaf page number that may
- ** contain term (pTerm/nTerm), if it is present in the segment. */
- pIdxSelect = fts5IdxSelectStmt(p);
- if( p->rc ) return;
- sqlite3_bind_int(pIdxSelect, 1, pSeg->iSegid);
- sqlite3_bind_blob(pIdxSelect, 2, pTerm, nTerm, SQLITE_STATIC);
- if( SQLITE_ROW==sqlite3_step(pIdxSelect) ){
- i64 val = sqlite3_column_int(pIdxSelect, 0);
- iPg = (int)(val>>1);
- bDlidx = (val & 0x0001);
- }
- p->rc = sqlite3_reset(pIdxSelect);
-
- if( iPg<pSeg->pgnoFirst ){
- iPg = pSeg->pgnoFirst;
- bDlidx = 0;
- }
-
- pIter->iLeafPgno = iPg - 1;
- fts5SegIterNextPage(p, pIter);
-
- if( pIter->pLeaf ){
- fts5LeafSeek(p, bGe, pIter, pTerm, nTerm);
- }
-
- if( p->rc==SQLITE_OK && bGe==0 ){
- pIter->flags |= FTS5_SEGITER_ONETERM;
- if( pIter->pLeaf ){
- if( flags & FTS5INDEX_QUERY_DESC ){
- pIter->flags |= FTS5_SEGITER_REVERSE;
- }
- if( bDlidx ){
- fts5SegIterLoadDlidx(p, pIter);
- }
- if( flags & FTS5INDEX_QUERY_DESC ){
- fts5SegIterReverse(p, pIter);
- }
- }
- }
-
- fts5SegIterSetNext(p, pIter);
-
- /* Either:
- **
- ** 1) an error has occurred, or
- ** 2) the iterator points to EOF, or
- ** 3) the iterator points to an entry with term (pTerm/nTerm), or
- ** 4) the FTS5INDEX_QUERY_SCAN flag was set and the iterator points
- ** to an entry with a term greater than or equal to (pTerm/nTerm).
- */
- assert( p->rc!=SQLITE_OK /* 1 */
- || pIter->pLeaf==0 /* 2 */
- || fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)==0 /* 3 */
- || (bGe && fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)>0) /* 4 */
- );
-}
-
-/*
-** Initialize the object pIter to point to term pTerm/nTerm within the
-** in-memory hash table. If there is no such term in the hash-table, the
-** iterator is set to EOF.
-**
-** If an error occurs, Fts5Index.rc is set to an appropriate error code. If
-** an error has already occurred when this function is called, it is a no-op.
-*/
-static void fts5SegIterHashInit(
- Fts5Index *p, /* FTS5 backend */
- const u8 *pTerm, int nTerm, /* Term to seek to */
- int flags, /* Mask of FTS5INDEX_XXX flags */
- Fts5SegIter *pIter /* Object to populate */
-){
- const u8 *pList = 0;
- int nList = 0;
- const u8 *z = 0;
- int n = 0;
-
- assert( p->pHash );
- assert( p->rc==SQLITE_OK );
-
- if( pTerm==0 || (flags & FTS5INDEX_QUERY_SCAN) ){
- p->rc = sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm);
- sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList);
- n = (z ? (int)strlen((const char*)z) : 0);
- }else{
- pIter->flags |= FTS5_SEGITER_ONETERM;
- sqlite3Fts5HashQuery(p->pHash, (const char*)pTerm, nTerm, &pList, &nList);
- z = pTerm;
- n = nTerm;
- }
-
- if( pList ){
- Fts5Data *pLeaf;
- sqlite3Fts5BufferSet(&p->rc, &pIter->term, n, z);
- pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data));
- if( pLeaf==0 ) return;
- pLeaf->p = (u8*)pList;
- pLeaf->nn = pLeaf->szLeaf = nList;
- pIter->pLeaf = pLeaf;
- pIter->iLeafOffset = fts5GetVarint(pLeaf->p, (u64*)&pIter->iRowid);
- pIter->iEndofDoclist = pLeaf->nn;
-
- if( flags & FTS5INDEX_QUERY_DESC ){
- pIter->flags |= FTS5_SEGITER_REVERSE;
- fts5SegIterReverseInitPage(p, pIter);
- }else{
- fts5SegIterLoadNPos(p, pIter);
- }
- }
-
- fts5SegIterSetNext(p, pIter);
-}
-
-/*
-** Zero the iterator passed as the only argument.
-*/
-static void fts5SegIterClear(Fts5SegIter *pIter){
- fts5BufferFree(&pIter->term);
- fts5DataRelease(pIter->pLeaf);
- fts5DataRelease(pIter->pNextLeaf);
- fts5DlidxIterFree(pIter->pDlidx);
- sqlite3_free(pIter->aRowidOffset);
- memset(pIter, 0, sizeof(Fts5SegIter));
-}
-
-#ifdef SQLITE_DEBUG
-
-/*
-** This function is used as part of the big assert() procedure implemented by
-** fts5AssertMultiIterSetup(). It ensures that the result currently stored
-** in *pRes is the correct result of comparing the current positions of the
-** two iterators.
-*/
-static void fts5AssertComparisonResult(
- Fts5Iter *pIter,
- Fts5SegIter *p1,
- Fts5SegIter *p2,
- Fts5CResult *pRes
-){
- int i1 = p1 - pIter->aSeg;
- int i2 = p2 - pIter->aSeg;
-
- if( p1->pLeaf || p2->pLeaf ){
- if( p1->pLeaf==0 ){
- assert( pRes->iFirst==i2 );
- }else if( p2->pLeaf==0 ){
- assert( pRes->iFirst==i1 );
- }else{
- int nMin = MIN(p1->term.n, p2->term.n);
- int res = memcmp(p1->term.p, p2->term.p, nMin);
- if( res==0 ) res = p1->term.n - p2->term.n;
-
- if( res==0 ){
- assert( pRes->bTermEq==1 );
- assert( p1->iRowid!=p2->iRowid );
- res = ((p1->iRowid > p2->iRowid)==pIter->bRev) ? -1 : 1;
- }else{
- assert( pRes->bTermEq==0 );
- }
-
- if( res<0 ){
- assert( pRes->iFirst==i1 );
- }else{
- assert( pRes->iFirst==i2 );
- }
- }
- }
-}
-
-/*
-** This function is a no-op unless SQLITE_DEBUG is defined when this module
-** is compiled. In that case, this function is essentially an assert()
-** statement used to verify that the contents of the pIter->aFirst[] array
-** are correct.
-*/
-static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5Iter *pIter){
- if( p->rc==SQLITE_OK ){
- Fts5SegIter *pFirst = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
- int i;
-
- assert( (pFirst->pLeaf==0)==pIter->base.bEof );
-
- /* Check that pIter->iSwitchRowid is set correctly. */
- for(i=0; i<pIter->nSeg; i++){
- Fts5SegIter *p1 = &pIter->aSeg[i];
- assert( p1==pFirst
- || p1->pLeaf==0
- || fts5BufferCompare(&pFirst->term, &p1->term)
- || p1->iRowid==pIter->iSwitchRowid
- || (p1->iRowid<pIter->iSwitchRowid)==pIter->bRev
- );
- }
-
- for(i=0; i<pIter->nSeg; i+=2){
- Fts5SegIter *p1 = &pIter->aSeg[i];
- Fts5SegIter *p2 = &pIter->aSeg[i+1];
- Fts5CResult *pRes = &pIter->aFirst[(pIter->nSeg + i) / 2];
- fts5AssertComparisonResult(pIter, p1, p2, pRes);
- }
-
- for(i=1; i<(pIter->nSeg / 2); i+=2){
- Fts5SegIter *p1 = &pIter->aSeg[ pIter->aFirst[i*2].iFirst ];
- Fts5SegIter *p2 = &pIter->aSeg[ pIter->aFirst[i*2+1].iFirst ];
- Fts5CResult *pRes = &pIter->aFirst[i];
- fts5AssertComparisonResult(pIter, p1, p2, pRes);
- }
- }
-}
-#else
-# define fts5AssertMultiIterSetup(x,y)
-#endif
-
-/*
-** Do the comparison necessary to populate pIter->aFirst[iOut].
-**
-** If the returned value is non-zero, then it is the index of an entry
-** in the pIter->aSeg[] array that is (a) not at EOF, and (b) pointing
-** to a key that is a duplicate of another, higher priority,
-** segment-iterator in the pSeg->aSeg[] array.
-*/
-static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){
- int i1; /* Index of left-hand Fts5SegIter */
- int i2; /* Index of right-hand Fts5SegIter */
- int iRes;
- Fts5SegIter *p1; /* Left-hand Fts5SegIter */
- Fts5SegIter *p2; /* Right-hand Fts5SegIter */
- Fts5CResult *pRes = &pIter->aFirst[iOut];
-
- assert( iOut<pIter->nSeg && iOut>0 );
- assert( pIter->bRev==0 || pIter->bRev==1 );
-
- if( iOut>=(pIter->nSeg/2) ){
- i1 = (iOut - pIter->nSeg/2) * 2;
- i2 = i1 + 1;
- }else{
- i1 = pIter->aFirst[iOut*2].iFirst;
- i2 = pIter->aFirst[iOut*2+1].iFirst;
- }
- p1 = &pIter->aSeg[i1];
- p2 = &pIter->aSeg[i2];
-
- pRes->bTermEq = 0;
- if( p1->pLeaf==0 ){ /* If p1 is at EOF */
- iRes = i2;
- }else if( p2->pLeaf==0 ){ /* If p2 is at EOF */
- iRes = i1;
- }else{
- int res = fts5BufferCompare(&p1->term, &p2->term);
- if( res==0 ){
- assert( i2>i1 );
- assert( i2!=0 );
- pRes->bTermEq = 1;
- if( p1->iRowid==p2->iRowid ){
- p1->bDel = p2->bDel;
- return i2;
- }
- res = ((p1->iRowid > p2->iRowid)==pIter->bRev) ? -1 : +1;
- }
- assert( res!=0 );
- if( res<0 ){
- iRes = i1;
- }else{
- iRes = i2;
- }
- }
-
- pRes->iFirst = (u16)iRes;
- return 0;
-}
-
-/*
-** Move the seg-iter so that it points to the first rowid on page iLeafPgno.
-** It is an error if leaf iLeafPgno does not exist or contains no rowids.
-*/
-static void fts5SegIterGotoPage(
- Fts5Index *p, /* FTS5 backend object */
- Fts5SegIter *pIter, /* Iterator to advance */
- int iLeafPgno
-){
- assert( iLeafPgno>pIter->iLeafPgno );
-
- if( iLeafPgno>pIter->pSeg->pgnoLast ){
- p->rc = FTS5_CORRUPT;
- }else{
- fts5DataRelease(pIter->pNextLeaf);
- pIter->pNextLeaf = 0;
- pIter->iLeafPgno = iLeafPgno-1;
- fts5SegIterNextPage(p, pIter);
- assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno );
-
- if( p->rc==SQLITE_OK ){
- int iOff;
- u8 *a = pIter->pLeaf->p;
- int n = pIter->pLeaf->szLeaf;
-
- iOff = fts5LeafFirstRowidOff(pIter->pLeaf);
- if( iOff<4 || iOff>=n ){
- p->rc = FTS5_CORRUPT;
- }else{
- iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid);
- pIter->iLeafOffset = iOff;
- fts5SegIterLoadNPos(p, pIter);
- }
- }
- }
-}
-
-/*
-** Advance the iterator passed as the second argument until it is at or
-** past rowid iFrom. Regardless of the value of iFrom, the iterator is
-** always advanced at least once.
-*/
-static void fts5SegIterNextFrom(
- Fts5Index *p, /* FTS5 backend object */
- Fts5SegIter *pIter, /* Iterator to advance */
- i64 iMatch /* Advance iterator at least this far */
-){
- int bRev = (pIter->flags & FTS5_SEGITER_REVERSE);
- Fts5DlidxIter *pDlidx = pIter->pDlidx;
- int iLeafPgno = pIter->iLeafPgno;
- int bMove = 1;
-
- assert( pIter->flags & FTS5_SEGITER_ONETERM );
- assert( pIter->pDlidx );
- assert( pIter->pLeaf );
-
- if( bRev==0 ){
- while( !fts5DlidxIterEof(p, pDlidx) && iMatch>fts5DlidxIterRowid(pDlidx) ){
- iLeafPgno = fts5DlidxIterPgno(pDlidx);
- fts5DlidxIterNext(p, pDlidx);
- }
- assert_nc( iLeafPgno>=pIter->iLeafPgno || p->rc );
- if( iLeafPgno>pIter->iLeafPgno ){
- fts5SegIterGotoPage(p, pIter, iLeafPgno);
- bMove = 0;
- }
- }else{
- assert( pIter->pNextLeaf==0 );
- assert( iMatch<pIter->iRowid );
- while( !fts5DlidxIterEof(p, pDlidx) && iMatch<fts5DlidxIterRowid(pDlidx) ){
- fts5DlidxIterPrev(p, pDlidx);
- }
- iLeafPgno = fts5DlidxIterPgno(pDlidx);
-
- assert( fts5DlidxIterEof(p, pDlidx) || iLeafPgno<=pIter->iLeafPgno );
-
- if( iLeafPgno<pIter->iLeafPgno ){
- pIter->iLeafPgno = iLeafPgno+1;
- fts5SegIterReverseNewPage(p, pIter);
- bMove = 0;
- }
- }
-
- do{
- if( bMove && p->rc==SQLITE_OK ) pIter->xNext(p, pIter, 0);
- if( pIter->pLeaf==0 ) break;
- if( bRev==0 && pIter->iRowid>=iMatch ) break;
- if( bRev!=0 && pIter->iRowid<=iMatch ) break;
- bMove = 1;
- }while( p->rc==SQLITE_OK );
-}
-
-
-/*
-** Free the iterator object passed as the second argument.
-*/
-static void fts5MultiIterFree(Fts5Iter *pIter){
- if( pIter ){
- int i;
- for(i=0; i<pIter->nSeg; i++){
- fts5SegIterClear(&pIter->aSeg[i]);
- }
- fts5StructureRelease(pIter->pStruct);
- fts5BufferFree(&pIter->poslist);
- sqlite3_free(pIter);
- }
-}
-
-static void fts5MultiIterAdvanced(
- Fts5Index *p, /* FTS5 backend to iterate within */
- Fts5Iter *pIter, /* Iterator to update aFirst[] array for */
- int iChanged, /* Index of sub-iterator just advanced */
- int iMinset /* Minimum entry in aFirst[] to set */
-){
- int i;
- for(i=(pIter->nSeg+iChanged)/2; i>=iMinset && p->rc==SQLITE_OK; i=i/2){
- int iEq;
- if( (iEq = fts5MultiIterDoCompare(pIter, i)) ){
- Fts5SegIter *pSeg = &pIter->aSeg[iEq];
- assert( p->rc==SQLITE_OK );
- pSeg->xNext(p, pSeg, 0);
- i = pIter->nSeg + iEq;
- }
- }
-}
-
-/*
-** Sub-iterator iChanged of iterator pIter has just been advanced. It still
-** points to the same term though - just a different rowid. This function
-** attempts to update the contents of the pIter->aFirst[] accordingly.
-** If it does so successfully, 0 is returned. Otherwise 1.
-**
-** If non-zero is returned, the caller should call fts5MultiIterAdvanced()
-** on the iterator instead. That function does the same as this one, except
-** that it deals with more complicated cases as well.
-*/
-static int fts5MultiIterAdvanceRowid(
- Fts5Iter *pIter, /* Iterator to update aFirst[] array for */
- int iChanged, /* Index of sub-iterator just advanced */
- Fts5SegIter **ppFirst
-){
- Fts5SegIter *pNew = &pIter->aSeg[iChanged];
-
- if( pNew->iRowid==pIter->iSwitchRowid
- || (pNew->iRowid<pIter->iSwitchRowid)==pIter->bRev
- ){
- int i;
- Fts5SegIter *pOther = &pIter->aSeg[iChanged ^ 0x0001];
- pIter->iSwitchRowid = pIter->bRev ? SMALLEST_INT64 : LARGEST_INT64;
- for(i=(pIter->nSeg+iChanged)/2; 1; i=i/2){
- Fts5CResult *pRes = &pIter->aFirst[i];
-
- assert( pNew->pLeaf );
- assert( pRes->bTermEq==0 || pOther->pLeaf );
-
- if( pRes->bTermEq ){
- if( pNew->iRowid==pOther->iRowid ){
- return 1;
- }else if( (pOther->iRowid>pNew->iRowid)==pIter->bRev ){
- pIter->iSwitchRowid = pOther->iRowid;
- pNew = pOther;
- }else if( (pOther->iRowid>pIter->iSwitchRowid)==pIter->bRev ){
- pIter->iSwitchRowid = pOther->iRowid;
- }
- }
- pRes->iFirst = (u16)(pNew - pIter->aSeg);
- if( i==1 ) break;
-
- pOther = &pIter->aSeg[ pIter->aFirst[i ^ 0x0001].iFirst ];
- }
- }
-
- *ppFirst = pNew;
- return 0;
-}
-
-/*
-** Set the pIter->bEof variable based on the state of the sub-iterators.
-*/
-static void fts5MultiIterSetEof(Fts5Iter *pIter){
- Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
- pIter->base.bEof = pSeg->pLeaf==0;
- pIter->iSwitchRowid = pSeg->iRowid;
-}
-
-/*
-** Move the iterator to the next entry.
-**
-** If an error occurs, an error code is left in Fts5Index.rc. It is not
-** considered an error if the iterator reaches EOF, or if it is already at
-** EOF when this function is called.
-*/
-static void fts5MultiIterNext(
- Fts5Index *p,
- Fts5Iter *pIter,
- int bFrom, /* True if argument iFrom is valid */
- i64 iFrom /* Advance at least as far as this */
-){
- int bUseFrom = bFrom;
- while( p->rc==SQLITE_OK ){
- int iFirst = pIter->aFirst[1].iFirst;
- int bNewTerm = 0;
- Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
- assert( p->rc==SQLITE_OK );
- if( bUseFrom && pSeg->pDlidx ){
- fts5SegIterNextFrom(p, pSeg, iFrom);
- }else{
- pSeg->xNext(p, pSeg, &bNewTerm);
- }
-
- if( pSeg->pLeaf==0 || bNewTerm
- || fts5MultiIterAdvanceRowid(pIter, iFirst, &pSeg)
- ){
- fts5MultiIterAdvanced(p, pIter, iFirst, 1);
- fts5MultiIterSetEof(pIter);
- pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
- if( pSeg->pLeaf==0 ) return;
- }
-
- fts5AssertMultiIterSetup(p, pIter);
- assert( pSeg==&pIter->aSeg[pIter->aFirst[1].iFirst] && pSeg->pLeaf );
- if( pIter->bSkipEmpty==0 || pSeg->nPos ){
- pIter->xSetOutputs(pIter, pSeg);
- return;
- }
- bUseFrom = 0;
- }
-}
-
-static void fts5MultiIterNext2(
- Fts5Index *p,
- Fts5Iter *pIter,
- int *pbNewTerm /* OUT: True if *might* be new term */
-){
- assert( pIter->bSkipEmpty );
- if( p->rc==SQLITE_OK ){
- do {
- int iFirst = pIter->aFirst[1].iFirst;
- Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
- int bNewTerm = 0;
-
- assert( p->rc==SQLITE_OK );
- pSeg->xNext(p, pSeg, &bNewTerm);
- if( pSeg->pLeaf==0 || bNewTerm
- || fts5MultiIterAdvanceRowid(pIter, iFirst, &pSeg)
- ){
- fts5MultiIterAdvanced(p, pIter, iFirst, 1);
- fts5MultiIterSetEof(pIter);
- *pbNewTerm = 1;
- }else{
- *pbNewTerm = 0;
- }
- fts5AssertMultiIterSetup(p, pIter);
-
- }while( fts5MultiIterIsEmpty(p, pIter) );
- }
-}
-
-static void fts5IterSetOutputs_Noop(Fts5Iter *pUnused1, Fts5SegIter *pUnused2){
- UNUSED_PARAM2(pUnused1, pUnused2);
-}
-
-static Fts5Iter *fts5MultiIterAlloc(
- Fts5Index *p, /* FTS5 backend to iterate within */
- int nSeg
-){
- Fts5Iter *pNew;
- int nSlot; /* Power of two >= nSeg */
-
- for(nSlot=2; nSlot<nSeg; nSlot=nSlot*2);
- pNew = fts5IdxMalloc(p,
- sizeof(Fts5Iter) + /* pNew */
- sizeof(Fts5SegIter) * (nSlot-1) + /* pNew->aSeg[] */
- sizeof(Fts5CResult) * nSlot /* pNew->aFirst[] */
- );
- if( pNew ){
- pNew->nSeg = nSlot;
- pNew->aFirst = (Fts5CResult*)&pNew->aSeg[nSlot];
- pNew->pIndex = p;
- pNew->xSetOutputs = fts5IterSetOutputs_Noop;
- }
- return pNew;
-}
-
-static void fts5PoslistCallback(
- Fts5Index *pUnused,
- void *pContext,
- const u8 *pChunk, int nChunk
-){
- UNUSED_PARAM(pUnused);
- assert_nc( nChunk>=0 );
- if( nChunk>0 ){
- fts5BufferSafeAppendBlob((Fts5Buffer*)pContext, pChunk, nChunk);
- }
-}
-
-typedef struct PoslistCallbackCtx PoslistCallbackCtx;
-struct PoslistCallbackCtx {
- Fts5Buffer *pBuf; /* Append to this buffer */
- Fts5Colset *pColset; /* Restrict matches to this column */
- int eState; /* See above */
-};
-
-typedef struct PoslistOffsetsCtx PoslistOffsetsCtx;
-struct PoslistOffsetsCtx {
- Fts5Buffer *pBuf; /* Append to this buffer */
- Fts5Colset *pColset; /* Restrict matches to this column */
- int iRead;
- int iWrite;
-};
-
-/*
-** TODO: Make this more efficient!
-*/
-static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){
- int i;
- for(i=0; i<pColset->nCol; i++){
- if( pColset->aiCol[i]==iCol ) return 1;
- }
- return 0;
-}
-
-static void fts5PoslistOffsetsCallback(
- Fts5Index *pUnused,
- void *pContext,
- const u8 *pChunk, int nChunk
-){
- PoslistOffsetsCtx *pCtx = (PoslistOffsetsCtx*)pContext;
- UNUSED_PARAM(pUnused);
- assert_nc( nChunk>=0 );
- if( nChunk>0 ){
- int i = 0;
- while( i<nChunk ){
- int iVal;
- i += fts5GetVarint32(&pChunk[i], iVal);
- iVal += pCtx->iRead - 2;
- pCtx->iRead = iVal;
- if( fts5IndexColsetTest(pCtx->pColset, iVal) ){
- fts5BufferSafeAppendVarint(pCtx->pBuf, iVal + 2 - pCtx->iWrite);
- pCtx->iWrite = iVal;
- }
- }
- }
-}
-
-static void fts5PoslistFilterCallback(
- Fts5Index *pUnused,
- void *pContext,
- const u8 *pChunk, int nChunk
-){
- PoslistCallbackCtx *pCtx = (PoslistCallbackCtx*)pContext;
- UNUSED_PARAM(pUnused);
- assert_nc( nChunk>=0 );
- if( nChunk>0 ){
- /* Search through to find the first varint with value 1. This is the
- ** start of the next columns hits. */
- int i = 0;
- int iStart = 0;
-
- if( pCtx->eState==2 ){
- int iCol;
- fts5FastGetVarint32(pChunk, i, iCol);
- if( fts5IndexColsetTest(pCtx->pColset, iCol) ){
- pCtx->eState = 1;
- fts5BufferSafeAppendVarint(pCtx->pBuf, 1);
- }else{
- pCtx->eState = 0;
- }
- }
-
- do {
- while( i<nChunk && pChunk[i]!=0x01 ){
- while( pChunk[i] & 0x80 ) i++;
- i++;
- }
- if( pCtx->eState ){
- fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart);
- }
- if( i<nChunk ){
- int iCol;
- iStart = i;
- i++;
- if( i>=nChunk ){
- pCtx->eState = 2;
- }else{
- fts5FastGetVarint32(pChunk, i, iCol);
- pCtx->eState = fts5IndexColsetTest(pCtx->pColset, iCol);
- if( pCtx->eState ){
- fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart);
- iStart = i;
- }
- }
- }
- }while( i<nChunk );
- }
-}
-
-static void fts5ChunkIterate(
- Fts5Index *p, /* Index object */
- Fts5SegIter *pSeg, /* Poslist of this iterator */
- void *pCtx, /* Context pointer for xChunk callback */
- void (*xChunk)(Fts5Index*, void*, const u8*, int)
-){
- int nRem = pSeg->nPos; /* Number of bytes still to come */
- Fts5Data *pData = 0;
- u8 *pChunk = &pSeg->pLeaf->p[pSeg->iLeafOffset];
- int nChunk = MIN(nRem, pSeg->pLeaf->szLeaf - pSeg->iLeafOffset);
- int pgno = pSeg->iLeafPgno;
- int pgnoSave = 0;
-
- /* This function does notmwork with detail=none databases. */
- assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE );
-
- if( (pSeg->flags & FTS5_SEGITER_REVERSE)==0 ){
- pgnoSave = pgno+1;
- }
-
- while( 1 ){
- xChunk(p, pCtx, pChunk, nChunk);
- nRem -= nChunk;
- fts5DataRelease(pData);
- if( nRem<=0 ){
- break;
- }else{
- pgno++;
- pData = fts5DataRead(p, FTS5_SEGMENT_ROWID(pSeg->pSeg->iSegid, pgno));
- if( pData==0 ) break;
- pChunk = &pData->p[4];
- nChunk = MIN(nRem, pData->szLeaf - 4);
- if( pgno==pgnoSave ){
- assert( pSeg->pNextLeaf==0 );
- pSeg->pNextLeaf = pData;
- pData = 0;
- }
- }
- }
-}
-
-/*
-** Iterator pIter currently points to a valid entry (not EOF). This
-** function appends the position list data for the current entry to
-** buffer pBuf. It does not make a copy of the position-list size
-** field.
-*/
-static void fts5SegiterPoslist(
- Fts5Index *p,
- Fts5SegIter *pSeg,
- Fts5Colset *pColset,
- Fts5Buffer *pBuf
-){
- if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){
- if( pColset==0 ){
- fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback);
- }else{
- if( p->pConfig->eDetail==FTS5_DETAIL_FULL ){
- PoslistCallbackCtx sCtx;
- sCtx.pBuf = pBuf;
- sCtx.pColset = pColset;
- sCtx.eState = fts5IndexColsetTest(pColset, 0);
- assert( sCtx.eState==0 || sCtx.eState==1 );
- fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback);
- }else{
- PoslistOffsetsCtx sCtx;
- memset(&sCtx, 0, sizeof(sCtx));
- sCtx.pBuf = pBuf;
- sCtx.pColset = pColset;
- fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistOffsetsCallback);
- }
- }
- }
-}
-
-/*
-** IN/OUT parameter (*pa) points to a position list n bytes in size. If
-** the position list contains entries for column iCol, then (*pa) is set
-** to point to the sub-position-list for that column and the number of
-** bytes in it returned. Or, if the argument position list does not
-** contain any entries for column iCol, return 0.
-*/
-static int fts5IndexExtractCol(
- const u8 **pa, /* IN/OUT: Pointer to poslist */
- int n, /* IN: Size of poslist in bytes */
- int iCol /* Column to extract from poslist */
-){
- int iCurrent = 0; /* Anything before the first 0x01 is col 0 */
- const u8 *p = *pa;
- const u8 *pEnd = &p[n]; /* One byte past end of position list */
-
- while( iCol>iCurrent ){
- /* Advance pointer p until it points to pEnd or an 0x01 byte that is
- ** not part of a varint. Note that it is not possible for a negative
- ** or extremely large varint to occur within an uncorrupted position
- ** list. So the last byte of each varint may be assumed to have a clear
- ** 0x80 bit. */
- while( *p!=0x01 ){
- while( *p++ & 0x80 );
- if( p>=pEnd ) return 0;
- }
- *pa = p++;
- iCurrent = *p++;
- if( iCurrent & 0x80 ){
- p--;
- p += fts5GetVarint32(p, iCurrent);
- }
- }
- if( iCol!=iCurrent ) return 0;
-
- /* Advance pointer p until it points to pEnd or an 0x01 byte that is
- ** not part of a varint */
- while( p<pEnd && *p!=0x01 ){
- while( *p++ & 0x80 );
- }
-
- return p - (*pa);
-}
-
-static int fts5IndexExtractColset (
- Fts5Colset *pColset, /* Colset to filter on */
- const u8 *pPos, int nPos, /* Position list */
- Fts5Buffer *pBuf /* Output buffer */
-){
- int rc = SQLITE_OK;
- int i;
-
- fts5BufferZero(pBuf);
- for(i=0; i<pColset->nCol; i++){
- const u8 *pSub = pPos;
- int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]);
- if( nSub ){
- fts5BufferAppendBlob(&rc, pBuf, nSub, pSub);
- }
- }
- return rc;
-}
-
-/*
-** xSetOutputs callback used by detail=none tables.
-*/
-static void fts5IterSetOutputs_None(Fts5Iter *pIter, Fts5SegIter *pSeg){
- assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_NONE );
- pIter->base.iRowid = pSeg->iRowid;
- pIter->base.nData = pSeg->nPos;
-}
-
-/*
-** xSetOutputs callback used by detail=full and detail=col tables when no
-** column filters are specified.
-*/
-static void fts5IterSetOutputs_Nocolset(Fts5Iter *pIter, Fts5SegIter *pSeg){
- pIter->base.iRowid = pSeg->iRowid;
- pIter->base.nData = pSeg->nPos;
-
- assert( pIter->pIndex->pConfig->eDetail!=FTS5_DETAIL_NONE );
- assert( pIter->pColset==0 );
-
- if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){
- /* All data is stored on the current page. Populate the output
- ** variables to point into the body of the page object. */
- pIter->base.pData = &pSeg->pLeaf->p[pSeg->iLeafOffset];
- }else{
- /* The data is distributed over two or more pages. Copy it into the
- ** Fts5Iter.poslist buffer and then set the output pointer to point
- ** to this buffer. */
- fts5BufferZero(&pIter->poslist);
- fts5SegiterPoslist(pIter->pIndex, pSeg, 0, &pIter->poslist);
- pIter->base.pData = pIter->poslist.p;
- }
-}
-
-/*
-** xSetOutputs callback used by detail=col when there is a column filter
-** and there are 100 or more columns. Also called as a fallback from
-** fts5IterSetOutputs_Col100 if the column-list spans more than one page.
-*/
-static void fts5IterSetOutputs_Col(Fts5Iter *pIter, Fts5SegIter *pSeg){
- fts5BufferZero(&pIter->poslist);
- fts5SegiterPoslist(pIter->pIndex, pSeg, pIter->pColset, &pIter->poslist);
- pIter->base.iRowid = pSeg->iRowid;
- pIter->base.pData = pIter->poslist.p;
- pIter->base.nData = pIter->poslist.n;
-}
-
-/*
-** xSetOutputs callback used when:
-**
-** * detail=col,
-** * there is a column filter, and
-** * the table contains 100 or fewer columns.
-**
-** The last point is to ensure all column numbers are stored as
-** single-byte varints.
-*/
-static void fts5IterSetOutputs_Col100(Fts5Iter *pIter, Fts5SegIter *pSeg){
-
- assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_COLUMNS );
- assert( pIter->pColset );
-
- if( pSeg->iLeafOffset+pSeg->nPos>pSeg->pLeaf->szLeaf ){
- fts5IterSetOutputs_Col(pIter, pSeg);
- }else{
- u8 *a = (u8*)&pSeg->pLeaf->p[pSeg->iLeafOffset];
- u8 *pEnd = (u8*)&a[pSeg->nPos];
- int iPrev = 0;
- int *aiCol = pIter->pColset->aiCol;
- int *aiColEnd = &aiCol[pIter->pColset->nCol];
-
- u8 *aOut = pIter->poslist.p;
- int iPrevOut = 0;
-
- pIter->base.iRowid = pSeg->iRowid;
-
- while( a<pEnd ){
- iPrev += (int)a++[0] - 2;
- while( *aiCol<iPrev ){
- aiCol++;
- if( aiCol==aiColEnd ) goto setoutputs_col_out;
- }
- if( *aiCol==iPrev ){
- *aOut++ = (u8)((iPrev - iPrevOut) + 2);
- iPrevOut = iPrev;
- }
- }
-
-setoutputs_col_out:
- pIter->base.pData = pIter->poslist.p;
- pIter->base.nData = aOut - pIter->poslist.p;
- }
-}
-
-/*
-** xSetOutputs callback used by detail=full when there is a column filter.
-*/
-static void fts5IterSetOutputs_Full(Fts5Iter *pIter, Fts5SegIter *pSeg){
- Fts5Colset *pColset = pIter->pColset;
- pIter->base.iRowid = pSeg->iRowid;
-
- assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_FULL );
- assert( pColset );
-
- if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){
- /* All data is stored on the current page. Populate the output
- ** variables to point into the body of the page object. */
- const u8 *a = &pSeg->pLeaf->p[pSeg->iLeafOffset];
- if( pColset->nCol==1 ){
- pIter->base.nData = fts5IndexExtractCol(&a, pSeg->nPos,pColset->aiCol[0]);
- pIter->base.pData = a;
- }else{
- fts5BufferZero(&pIter->poslist);
- fts5IndexExtractColset(pColset, a, pSeg->nPos, &pIter->poslist);
- pIter->base.pData = pIter->poslist.p;
- pIter->base.nData = pIter->poslist.n;
- }
- }else{
- /* The data is distributed over two or more pages. Copy it into the
- ** Fts5Iter.poslist buffer and then set the output pointer to point
- ** to this buffer. */
- fts5BufferZero(&pIter->poslist);
- fts5SegiterPoslist(pIter->pIndex, pSeg, pColset, &pIter->poslist);
- pIter->base.pData = pIter->poslist.p;
- pIter->base.nData = pIter->poslist.n;
- }
-}
-
-static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){
- if( *pRc==SQLITE_OK ){
- Fts5Config *pConfig = pIter->pIndex->pConfig;
- if( pConfig->eDetail==FTS5_DETAIL_NONE ){
- pIter->xSetOutputs = fts5IterSetOutputs_None;
- }
-
- else if( pIter->pColset==0 ){
- pIter->xSetOutputs = fts5IterSetOutputs_Nocolset;
- }
-
- else if( pConfig->eDetail==FTS5_DETAIL_FULL ){
- pIter->xSetOutputs = fts5IterSetOutputs_Full;
- }
-
- else{
- assert( pConfig->eDetail==FTS5_DETAIL_COLUMNS );
- if( pConfig->nCol<=100 ){
- pIter->xSetOutputs = fts5IterSetOutputs_Col100;
- sqlite3Fts5BufferSize(pRc, &pIter->poslist, pConfig->nCol);
- }else{
- pIter->xSetOutputs = fts5IterSetOutputs_Col;
- }
- }
- }
-}
-
-
-/*
-** Allocate a new Fts5Iter object.
-**
-** The new object will be used to iterate through data in structure pStruct.
-** If iLevel is -ve, then all data in all segments is merged. Or, if iLevel
-** is zero or greater, data from the first nSegment segments on level iLevel
-** is merged.
-**
-** The iterator initially points to the first term/rowid entry in the
-** iterated data.
-*/
-static void fts5MultiIterNew(
- Fts5Index *p, /* FTS5 backend to iterate within */
- Fts5Structure *pStruct, /* Structure of specific index */
- int flags, /* FTS5INDEX_QUERY_XXX flags */
- Fts5Colset *pColset, /* Colset to filter on (or NULL) */
- const u8 *pTerm, int nTerm, /* Term to seek to (or NULL/0) */
- int iLevel, /* Level to iterate (-1 for all) */
- int nSegment, /* Number of segments to merge (iLevel>=0) */
- Fts5Iter **ppOut /* New object */
-){
- int nSeg = 0; /* Number of segment-iters in use */
- int iIter = 0; /* */
- int iSeg; /* Used to iterate through segments */
- Fts5StructureLevel *pLvl;
- Fts5Iter *pNew;
-
- assert( (pTerm==0 && nTerm==0) || iLevel<0 );
-
- /* Allocate space for the new multi-seg-iterator. */
- if( p->rc==SQLITE_OK ){
- if( iLevel<0 ){
- assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) );
- nSeg = pStruct->nSegment;
- nSeg += (p->pHash ? 1 : 0);
- }else{
- nSeg = MIN(pStruct->aLevel[iLevel].nSeg, nSegment);
- }
- }
- *ppOut = pNew = fts5MultiIterAlloc(p, nSeg);
- if( pNew==0 ) return;
- pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_DESC));
- pNew->bSkipEmpty = (0!=(flags & FTS5INDEX_QUERY_SKIPEMPTY));
- pNew->pStruct = pStruct;
- pNew->pColset = pColset;
- fts5StructureRef(pStruct);
- if( (flags & FTS5INDEX_QUERY_NOOUTPUT)==0 ){
- fts5IterSetOutputCb(&p->rc, pNew);
- }
-
- /* Initialize each of the component segment iterators. */
- if( p->rc==SQLITE_OK ){
- if( iLevel<0 ){
- Fts5StructureLevel *pEnd = &pStruct->aLevel[pStruct->nLevel];
- if( p->pHash ){
- /* Add a segment iterator for the current contents of the hash table. */
- Fts5SegIter *pIter = &pNew->aSeg[iIter++];
- fts5SegIterHashInit(p, pTerm, nTerm, flags, pIter);
- }
- for(pLvl=&pStruct->aLevel[0]; pLvl<pEnd; pLvl++){
- for(iSeg=pLvl->nSeg-1; iSeg>=0; iSeg--){
- Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
- Fts5SegIter *pIter = &pNew->aSeg[iIter++];
- if( pTerm==0 ){
- fts5SegIterInit(p, pSeg, pIter);
- }else{
- fts5SegIterSeekInit(p, pTerm, nTerm, flags, pSeg, pIter);
- }
- }
- }
- }else{
- pLvl = &pStruct->aLevel[iLevel];
- for(iSeg=nSeg-1; iSeg>=0; iSeg--){
- fts5SegIterInit(p, &pLvl->aSeg[iSeg], &pNew->aSeg[iIter++]);
- }
- }
- assert( iIter==nSeg );
- }
-
- /* If the above was successful, each component iterators now points
- ** to the first entry in its segment. In this case initialize the
- ** aFirst[] array. Or, if an error has occurred, free the iterator
- ** object and set the output variable to NULL. */
- if( p->rc==SQLITE_OK ){
- for(iIter=pNew->nSeg-1; iIter>0; iIter--){
- int iEq;
- if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){
- Fts5SegIter *pSeg = &pNew->aSeg[iEq];
- if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0);
- fts5MultiIterAdvanced(p, pNew, iEq, iIter);
- }
- }
- fts5MultiIterSetEof(pNew);
- fts5AssertMultiIterSetup(p, pNew);
-
- if( pNew->bSkipEmpty && fts5MultiIterIsEmpty(p, pNew) ){
- fts5MultiIterNext(p, pNew, 0, 0);
- }else if( pNew->base.bEof==0 ){
- Fts5SegIter *pSeg = &pNew->aSeg[pNew->aFirst[1].iFirst];
- pNew->xSetOutputs(pNew, pSeg);
- }
-
- }else{
- fts5MultiIterFree(pNew);
- *ppOut = 0;
- }
-}
-
-/*
-** Create an Fts5Iter that iterates through the doclist provided
-** as the second argument.
-*/
-static void fts5MultiIterNew2(
- Fts5Index *p, /* FTS5 backend to iterate within */
- Fts5Data *pData, /* Doclist to iterate through */
- int bDesc, /* True for descending rowid order */
- Fts5Iter **ppOut /* New object */
-){
- Fts5Iter *pNew;
- pNew = fts5MultiIterAlloc(p, 2);
- if( pNew ){
- Fts5SegIter *pIter = &pNew->aSeg[1];
-
- pIter->flags = FTS5_SEGITER_ONETERM;
- if( pData->szLeaf>0 ){
- pIter->pLeaf = pData;
- pIter->iLeafOffset = fts5GetVarint(pData->p, (u64*)&pIter->iRowid);
- pIter->iEndofDoclist = pData->nn;
- pNew->aFirst[1].iFirst = 1;
- if( bDesc ){
- pNew->bRev = 1;
- pIter->flags |= FTS5_SEGITER_REVERSE;
- fts5SegIterReverseInitPage(p, pIter);
- }else{
- fts5SegIterLoadNPos(p, pIter);
- }
- pData = 0;
- }else{
- pNew->base.bEof = 1;
- }
- fts5SegIterSetNext(p, pIter);
-
- *ppOut = pNew;
- }
-
- fts5DataRelease(pData);
-}
-
-/*
-** Return true if the iterator is at EOF or if an error has occurred.
-** False otherwise.
-*/
-static int fts5MultiIterEof(Fts5Index *p, Fts5Iter *pIter){
- assert( p->rc
- || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->base.bEof
- );
- return (p->rc || pIter->base.bEof);
-}
-
-/*
-** Return the rowid of the entry that the iterator currently points
-** to. If the iterator points to EOF when this function is called the
-** results are undefined.
-*/
-static i64 fts5MultiIterRowid(Fts5Iter *pIter){
- assert( pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf );
- return pIter->aSeg[ pIter->aFirst[1].iFirst ].iRowid;
-}
-
-/*
-** Move the iterator to the next entry at or following iMatch.
-*/
-static void fts5MultiIterNextFrom(
- Fts5Index *p,
- Fts5Iter *pIter,
- i64 iMatch
-){
- while( 1 ){
- i64 iRowid;
- fts5MultiIterNext(p, pIter, 1, iMatch);
- if( fts5MultiIterEof(p, pIter) ) break;
- iRowid = fts5MultiIterRowid(pIter);
- if( pIter->bRev==0 && iRowid>=iMatch ) break;
- if( pIter->bRev!=0 && iRowid<=iMatch ) break;
- }
-}
-
-/*
-** Return a pointer to a buffer containing the term associated with the
-** entry that the iterator currently points to.
-*/
-static const u8 *fts5MultiIterTerm(Fts5Iter *pIter, int *pn){
- Fts5SegIter *p = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
- *pn = p->term.n;
- return p->term.p;
-}
-
-/*
-** Allocate a new segment-id for the structure pStruct. The new segment
-** id must be between 1 and 65335 inclusive, and must not be used by
-** any currently existing segment. If a free segment id cannot be found,
-** SQLITE_FULL is returned.
-**
-** If an error has already occurred, this function is a no-op. 0 is
-** returned in this case.
-*/
-static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){
- int iSegid = 0;
-
- if( p->rc==SQLITE_OK ){
- if( pStruct->nSegment>=FTS5_MAX_SEGMENT ){
- p->rc = SQLITE_FULL;
- }else{
- /* FTS5_MAX_SEGMENT is currently defined as 2000. So the following
- ** array is 63 elements, or 252 bytes, in size. */
- u32 aUsed[(FTS5_MAX_SEGMENT+31) / 32];
- int iLvl, iSeg;
- int i;
- u32 mask;
- memset(aUsed, 0, sizeof(aUsed));
- for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
- for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
- int iId = pStruct->aLevel[iLvl].aSeg[iSeg].iSegid;
- if( iId<=FTS5_MAX_SEGMENT ){
- aUsed[(iId-1) / 32] |= 1 << ((iId-1) % 32);
- }
- }
- }
-
- for(i=0; aUsed[i]==0xFFFFFFFF; i++);
- mask = aUsed[i];
- for(iSegid=0; mask & (1 << iSegid); iSegid++);
- iSegid += 1 + i*32;
-
-#ifdef SQLITE_DEBUG
- for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
- for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
- assert( iSegid!=pStruct->aLevel[iLvl].aSeg[iSeg].iSegid );
- }
- }
- assert( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT );
-
- {
- sqlite3_stmt *pIdxSelect = fts5IdxSelectStmt(p);
- if( p->rc==SQLITE_OK ){
- u8 aBlob[2] = {0xff, 0xff};
- sqlite3_bind_int(pIdxSelect, 1, iSegid);
- sqlite3_bind_blob(pIdxSelect, 2, aBlob, 2, SQLITE_STATIC);
- assert( sqlite3_step(pIdxSelect)!=SQLITE_ROW );
- p->rc = sqlite3_reset(pIdxSelect);
- }
- }
-#endif
- }
- }
-
- return iSegid;
-}
-
-/*
-** Discard all data currently cached in the hash-tables.
-*/
-static void fts5IndexDiscardData(Fts5Index *p){
- assert( p->pHash || p->nPendingData==0 );
- if( p->pHash ){
- sqlite3Fts5HashClear(p->pHash);
- p->nPendingData = 0;
- }
-}
-
-/*
-** Return the size of the prefix, in bytes, that buffer
-** (pNew/<length-unknown>) shares with buffer (pOld/nOld).
-**
-** Buffer (pNew/<length-unknown>) is guaranteed to be greater
-** than buffer (pOld/nOld).
-*/
-static int fts5PrefixCompress(int nOld, const u8 *pOld, const u8 *pNew){
- int i;
- for(i=0; i<nOld; i++){
- if( pOld[i]!=pNew[i] ) break;
- }
- return i;
-}
-
-static void fts5WriteDlidxClear(
- Fts5Index *p,
- Fts5SegWriter *pWriter,
- int bFlush /* If true, write dlidx to disk */
-){
- int i;
- assert( bFlush==0 || (pWriter->nDlidx>0 && pWriter->aDlidx[0].buf.n>0) );
- for(i=0; i<pWriter->nDlidx; i++){
- Fts5DlidxWriter *pDlidx = &pWriter->aDlidx[i];
- if( pDlidx->buf.n==0 ) break;
- if( bFlush ){
- assert( pDlidx->pgno!=0 );
- fts5DataWrite(p,
- FTS5_DLIDX_ROWID(pWriter->iSegid, i, pDlidx->pgno),
- pDlidx->buf.p, pDlidx->buf.n
- );
- }
- sqlite3Fts5BufferZero(&pDlidx->buf);
- pDlidx->bPrevValid = 0;
- }
-}
-
-/*
-** Grow the pWriter->aDlidx[] array to at least nLvl elements in size.
-** Any new array elements are zeroed before returning.
-*/
-static int fts5WriteDlidxGrow(
- Fts5Index *p,
- Fts5SegWriter *pWriter,
- int nLvl
-){
- if( p->rc==SQLITE_OK && nLvl>=pWriter->nDlidx ){
- Fts5DlidxWriter *aDlidx = (Fts5DlidxWriter*)sqlite3_realloc(
- pWriter->aDlidx, sizeof(Fts5DlidxWriter) * nLvl
- );
- if( aDlidx==0 ){
- p->rc = SQLITE_NOMEM;
- }else{
- int nByte = sizeof(Fts5DlidxWriter) * (nLvl - pWriter->nDlidx);
- memset(&aDlidx[pWriter->nDlidx], 0, nByte);
- pWriter->aDlidx = aDlidx;
- pWriter->nDlidx = nLvl;
- }
- }
- return p->rc;
-}
-
-/*
-** If the current doclist-index accumulating in pWriter->aDlidx[] is large
-** enough, flush it to disk and return 1. Otherwise discard it and return
-** zero.
-*/
-static int fts5WriteFlushDlidx(Fts5Index *p, Fts5SegWriter *pWriter){
- int bFlag = 0;
-
- /* If there were FTS5_MIN_DLIDX_SIZE or more empty leaf pages written
- ** to the database, also write the doclist-index to disk. */
- if( pWriter->aDlidx[0].buf.n>0 && pWriter->nEmpty>=FTS5_MIN_DLIDX_SIZE ){
- bFlag = 1;
- }
- fts5WriteDlidxClear(p, pWriter, bFlag);
- pWriter->nEmpty = 0;
- return bFlag;
-}
-
-/*
-** This function is called whenever processing of the doclist for the
-** last term on leaf page (pWriter->iBtPage) is completed.
-**
-** The doclist-index for that term is currently stored in-memory within the
-** Fts5SegWriter.aDlidx[] array. If it is large enough, this function
-** writes it out to disk. Or, if it is too small to bother with, discards
-** it.
-**
-** Fts5SegWriter.btterm currently contains the first term on page iBtPage.
-*/
-static void fts5WriteFlushBtree(Fts5Index *p, Fts5SegWriter *pWriter){
- int bFlag;
-
- assert( pWriter->iBtPage || pWriter->nEmpty==0 );
- if( pWriter->iBtPage==0 ) return;
- bFlag = fts5WriteFlushDlidx(p, pWriter);
-
- if( p->rc==SQLITE_OK ){
- const char *z = (pWriter->btterm.n>0?(const char*)pWriter->btterm.p:"");
- /* The following was already done in fts5WriteInit(): */
- /* sqlite3_bind_int(p->pIdxWriter, 1, pWriter->iSegid); */
- sqlite3_bind_blob(p->pIdxWriter, 2, z, pWriter->btterm.n, SQLITE_STATIC);
- sqlite3_bind_int64(p->pIdxWriter, 3, bFlag + ((i64)pWriter->iBtPage<<1));
- sqlite3_step(p->pIdxWriter);
- p->rc = sqlite3_reset(p->pIdxWriter);
- }
- pWriter->iBtPage = 0;
-}
-
-/*
-** This is called once for each leaf page except the first that contains
-** at least one term. Argument (nTerm/pTerm) is the split-key - a term that
-** is larger than all terms written to earlier leaves, and equal to or
-** smaller than the first term on the new leaf.
-**
-** If an error occurs, an error code is left in Fts5Index.rc. If an error
-** has already occurred when this function is called, it is a no-op.
-*/
-static void fts5WriteBtreeTerm(
- Fts5Index *p, /* FTS5 backend object */
- Fts5SegWriter *pWriter, /* Writer object */
- int nTerm, const u8 *pTerm /* First term on new page */
-){
- fts5WriteFlushBtree(p, pWriter);
- fts5BufferSet(&p->rc, &pWriter->btterm, nTerm, pTerm);
- pWriter->iBtPage = pWriter->writer.pgno;
-}
-
-/*
-** This function is called when flushing a leaf page that contains no
-** terms at all to disk.
-*/
-static void fts5WriteBtreeNoTerm(
- Fts5Index *p, /* FTS5 backend object */
- Fts5SegWriter *pWriter /* Writer object */
-){
- /* If there were no rowids on the leaf page either and the doclist-index
- ** has already been started, append an 0x00 byte to it. */
- if( pWriter->bFirstRowidInPage && pWriter->aDlidx[0].buf.n>0 ){
- Fts5DlidxWriter *pDlidx = &pWriter->aDlidx[0];
- assert( pDlidx->bPrevValid );
- sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, 0);
- }
-
- /* Increment the "number of sequential leaves without a term" counter. */
- pWriter->nEmpty++;
-}
-
-static i64 fts5DlidxExtractFirstRowid(Fts5Buffer *pBuf){
- i64 iRowid;
- int iOff;
-
- iOff = 1 + fts5GetVarint(&pBuf->p[1], (u64*)&iRowid);
- fts5GetVarint(&pBuf->p[iOff], (u64*)&iRowid);
- return iRowid;
-}
-
-/*
-** Rowid iRowid has just been appended to the current leaf page. It is the
-** first on the page. This function appends an appropriate entry to the current
-** doclist-index.
-*/
-static void fts5WriteDlidxAppend(
- Fts5Index *p,
- Fts5SegWriter *pWriter,
- i64 iRowid
-){
- int i;
- int bDone = 0;
-
- for(i=0; p->rc==SQLITE_OK && bDone==0; i++){
- i64 iVal;
- Fts5DlidxWriter *pDlidx = &pWriter->aDlidx[i];
-
- if( pDlidx->buf.n>=p->pConfig->pgsz ){
- /* The current doclist-index page is full. Write it to disk and push
- ** a copy of iRowid (which will become the first rowid on the next
- ** doclist-index leaf page) up into the next level of the b-tree
- ** hierarchy. If the node being flushed is currently the root node,
- ** also push its first rowid upwards. */
- pDlidx->buf.p[0] = 0x01; /* Not the root node */
- fts5DataWrite(p,
- FTS5_DLIDX_ROWID(pWriter->iSegid, i, pDlidx->pgno),
- pDlidx->buf.p, pDlidx->buf.n
- );
- fts5WriteDlidxGrow(p, pWriter, i+2);
- pDlidx = &pWriter->aDlidx[i];
- if( p->rc==SQLITE_OK && pDlidx[1].buf.n==0 ){
- i64 iFirst = fts5DlidxExtractFirstRowid(&pDlidx->buf);
-
- /* This was the root node. Push its first rowid up to the new root. */
- pDlidx[1].pgno = pDlidx->pgno;
- sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx[1].buf, 0);
- sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx[1].buf, pDlidx->pgno);
- sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx[1].buf, iFirst);
- pDlidx[1].bPrevValid = 1;
- pDlidx[1].iPrev = iFirst;
- }
-
- sqlite3Fts5BufferZero(&pDlidx->buf);
- pDlidx->bPrevValid = 0;
- pDlidx->pgno++;
- }else{
- bDone = 1;
- }
-
- if( pDlidx->bPrevValid ){
- iVal = iRowid - pDlidx->iPrev;
- }else{
- i64 iPgno = (i==0 ? pWriter->writer.pgno : pDlidx[-1].pgno);
- assert( pDlidx->buf.n==0 );
- sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, !bDone);
- sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, iPgno);
- iVal = iRowid;
- }
-
- sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, iVal);
- pDlidx->bPrevValid = 1;
- pDlidx->iPrev = iRowid;
- }
-}
-
-static void fts5WriteFlushLeaf(Fts5Index *p, Fts5SegWriter *pWriter){
- static const u8 zero[] = { 0x00, 0x00, 0x00, 0x00 };
- Fts5PageWriter *pPage = &pWriter->writer;
- i64 iRowid;
-
-static int nCall = 0;
-nCall++;
-
- assert( (pPage->pgidx.n==0)==(pWriter->bFirstTermInPage) );
-
- /* Set the szLeaf header field. */
- assert( 0==fts5GetU16(&pPage->buf.p[2]) );
- fts5PutU16(&pPage->buf.p[2], (u16)pPage->buf.n);
-
- if( pWriter->bFirstTermInPage ){
- /* No term was written to this page. */
- assert( pPage->pgidx.n==0 );
- fts5WriteBtreeNoTerm(p, pWriter);
- }else{
- /* Append the pgidx to the page buffer. Set the szLeaf header field. */
- fts5BufferAppendBlob(&p->rc, &pPage->buf, pPage->pgidx.n, pPage->pgidx.p);
- }
-
- /* Write the page out to disk */
- iRowid = FTS5_SEGMENT_ROWID(pWriter->iSegid, pPage->pgno);
- fts5DataWrite(p, iRowid, pPage->buf.p, pPage->buf.n);
-
- /* Initialize the next page. */
- fts5BufferZero(&pPage->buf);
- fts5BufferZero(&pPage->pgidx);
- fts5BufferAppendBlob(&p->rc, &pPage->buf, 4, zero);
- pPage->iPrevPgidx = 0;
- pPage->pgno++;
-
- /* Increase the leaves written counter */
- pWriter->nLeafWritten++;
-
- /* The new leaf holds no terms or rowids */
- pWriter->bFirstTermInPage = 1;
- pWriter->bFirstRowidInPage = 1;
-}
-
-/*
-** Append term pTerm/nTerm to the segment being written by the writer passed
-** as the second argument.
-**
-** If an error occurs, set the Fts5Index.rc error code. If an error has
-** already occurred, this function is a no-op.
-*/
-static void fts5WriteAppendTerm(
- Fts5Index *p,
- Fts5SegWriter *pWriter,
- int nTerm, const u8 *pTerm
-){
- int nPrefix; /* Bytes of prefix compression for term */
- Fts5PageWriter *pPage = &pWriter->writer;
- Fts5Buffer *pPgidx = &pWriter->writer.pgidx;
-
- assert( p->rc==SQLITE_OK );
- assert( pPage->buf.n>=4 );
- assert( pPage->buf.n>4 || pWriter->bFirstTermInPage );
-
- /* If the current leaf page is full, flush it to disk. */
- if( (pPage->buf.n + pPgidx->n + nTerm + 2)>=p->pConfig->pgsz ){
- if( pPage->buf.n>4 ){
- fts5WriteFlushLeaf(p, pWriter);
- }
- fts5BufferGrow(&p->rc, &pPage->buf, nTerm+FTS5_DATA_PADDING);
- }
-
- /* TODO1: Updating pgidx here. */
- pPgidx->n += sqlite3Fts5PutVarint(
- &pPgidx->p[pPgidx->n], pPage->buf.n - pPage->iPrevPgidx
- );
- pPage->iPrevPgidx = pPage->buf.n;
-#if 0
- fts5PutU16(&pPgidx->p[pPgidx->n], pPage->buf.n);
- pPgidx->n += 2;
-#endif
-
- if( pWriter->bFirstTermInPage ){
- nPrefix = 0;
- if( pPage->pgno!=1 ){
- /* This is the first term on a leaf that is not the leftmost leaf in
- ** the segment b-tree. In this case it is necessary to add a term to
- ** the b-tree hierarchy that is (a) larger than the largest term
- ** already written to the segment and (b) smaller than or equal to
- ** this term. In other words, a prefix of (pTerm/nTerm) that is one
- ** byte longer than the longest prefix (pTerm/nTerm) shares with the
- ** previous term.
- **
- ** Usually, the previous term is available in pPage->term. The exception
- ** is if this is the first term written in an incremental-merge step.
- ** In this case the previous term is not available, so just write a
- ** copy of (pTerm/nTerm) into the parent node. This is slightly
- ** inefficient, but still correct. */
- int n = nTerm;
- if( pPage->term.n ){
- n = 1 + fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm);
- }
- fts5WriteBtreeTerm(p, pWriter, n, pTerm);
- pPage = &pWriter->writer;
- }
- }else{
- nPrefix = fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm);
- fts5BufferAppendVarint(&p->rc, &pPage->buf, nPrefix);
- }
-
- /* Append the number of bytes of new data, then the term data itself
- ** to the page. */
- fts5BufferAppendVarint(&p->rc, &pPage->buf, nTerm - nPrefix);
- fts5BufferAppendBlob(&p->rc, &pPage->buf, nTerm - nPrefix, &pTerm[nPrefix]);
-
- /* Update the Fts5PageWriter.term field. */
- fts5BufferSet(&p->rc, &pPage->term, nTerm, pTerm);
- pWriter->bFirstTermInPage = 0;
-
- pWriter->bFirstRowidInPage = 0;
- pWriter->bFirstRowidInDoclist = 1;
-
- assert( p->rc || (pWriter->nDlidx>0 && pWriter->aDlidx[0].buf.n==0) );
- pWriter->aDlidx[0].pgno = pPage->pgno;
-}
-
-/*
-** Append a rowid and position-list size field to the writers output.
-*/
-static void fts5WriteAppendRowid(
- Fts5Index *p,
- Fts5SegWriter *pWriter,
- i64 iRowid
-){
- if( p->rc==SQLITE_OK ){
- Fts5PageWriter *pPage = &pWriter->writer;
-
- if( (pPage->buf.n + pPage->pgidx.n)>=p->pConfig->pgsz ){
- fts5WriteFlushLeaf(p, pWriter);
- }
-
- /* If this is to be the first rowid written to the page, set the
- ** rowid-pointer in the page-header. Also append a value to the dlidx
- ** buffer, in case a doclist-index is required. */
- if( pWriter->bFirstRowidInPage ){
- fts5PutU16(pPage->buf.p, (u16)pPage->buf.n);
- fts5WriteDlidxAppend(p, pWriter, iRowid);
- }
-
- /* Write the rowid. */
- if( pWriter->bFirstRowidInDoclist || pWriter->bFirstRowidInPage ){
- fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid);
- }else{
- assert( p->rc || iRowid>pWriter->iPrevRowid );
- fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid);
- }
- pWriter->iPrevRowid = iRowid;
- pWriter->bFirstRowidInDoclist = 0;
- pWriter->bFirstRowidInPage = 0;
- }
-}
-
-static void fts5WriteAppendPoslistData(
- Fts5Index *p,
- Fts5SegWriter *pWriter,
- const u8 *aData,
- int nData
-){
- Fts5PageWriter *pPage = &pWriter->writer;
- const u8 *a = aData;
- int n = nData;
-
- assert( p->pConfig->pgsz>0 );
- while( p->rc==SQLITE_OK
- && (pPage->buf.n + pPage->pgidx.n + n)>=p->pConfig->pgsz
- ){
- int nReq = p->pConfig->pgsz - pPage->buf.n - pPage->pgidx.n;
- int nCopy = 0;
- while( nCopy<nReq ){
- i64 dummy;
- nCopy += fts5GetVarint(&a[nCopy], (u64*)&dummy);
- }
- fts5BufferAppendBlob(&p->rc, &pPage->buf, nCopy, a);
- a += nCopy;
- n -= nCopy;
- fts5WriteFlushLeaf(p, pWriter);
- }
- if( n>0 ){
- fts5BufferAppendBlob(&p->rc, &pPage->buf, n, a);
- }
-}
-
-/*
-** Flush any data cached by the writer object to the database. Free any
-** allocations associated with the writer.
-*/
-static void fts5WriteFinish(
- Fts5Index *p,
- Fts5SegWriter *pWriter, /* Writer object */
- int *pnLeaf /* OUT: Number of leaf pages in b-tree */
-){
- int i;
- Fts5PageWriter *pLeaf = &pWriter->writer;
- if( p->rc==SQLITE_OK ){
- assert( pLeaf->pgno>=1 );
- if( pLeaf->buf.n>4 ){
- fts5WriteFlushLeaf(p, pWriter);
- }
- *pnLeaf = pLeaf->pgno-1;
- if( pLeaf->pgno>1 ){
- fts5WriteFlushBtree(p, pWriter);
- }
- }
- fts5BufferFree(&pLeaf->term);
- fts5BufferFree(&pLeaf->buf);
- fts5BufferFree(&pLeaf->pgidx);
- fts5BufferFree(&pWriter->btterm);
-
- for(i=0; i<pWriter->nDlidx; i++){
- sqlite3Fts5BufferFree(&pWriter->aDlidx[i].buf);
- }
- sqlite3_free(pWriter->aDlidx);
-}
-
-static void fts5WriteInit(
- Fts5Index *p,
- Fts5SegWriter *pWriter,
- int iSegid
-){
- const int nBuffer = p->pConfig->pgsz + FTS5_DATA_PADDING;
-
- memset(pWriter, 0, sizeof(Fts5SegWriter));
- pWriter->iSegid = iSegid;
-
- fts5WriteDlidxGrow(p, pWriter, 1);
- pWriter->writer.pgno = 1;
- pWriter->bFirstTermInPage = 1;
- pWriter->iBtPage = 1;
-
- assert( pWriter->writer.buf.n==0 );
- assert( pWriter->writer.pgidx.n==0 );
-
- /* Grow the two buffers to pgsz + padding bytes in size. */
- sqlite3Fts5BufferSize(&p->rc, &pWriter->writer.pgidx, nBuffer);
- sqlite3Fts5BufferSize(&p->rc, &pWriter->writer.buf, nBuffer);
-
- if( p->pIdxWriter==0 ){
- Fts5Config *pConfig = p->pConfig;
- fts5IndexPrepareStmt(p, &p->pIdxWriter, sqlite3_mprintf(
- "INSERT INTO '%q'.'%q_idx'(segid,term,pgno) VALUES(?,?,?)",
- pConfig->zDb, pConfig->zName
- ));
- }
-
- if( p->rc==SQLITE_OK ){
- /* Initialize the 4-byte leaf-page header to 0x00. */
- memset(pWriter->writer.buf.p, 0, 4);
- pWriter->writer.buf.n = 4;
-
- /* Bind the current output segment id to the index-writer. This is an
- ** optimization over binding the same value over and over as rows are
- ** inserted into %_idx by the current writer. */
- sqlite3_bind_int(p->pIdxWriter, 1, pWriter->iSegid);
- }
-}
-
-/*
-** Iterator pIter was used to iterate through the input segments of on an
-** incremental merge operation. This function is called if the incremental
-** merge step has finished but the input has not been completely exhausted.
-*/
-static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){
- int i;
- Fts5Buffer buf;
- memset(&buf, 0, sizeof(Fts5Buffer));
- for(i=0; i<pIter->nSeg; i++){
- Fts5SegIter *pSeg = &pIter->aSeg[i];
- if( pSeg->pSeg==0 ){
- /* no-op */
- }else if( pSeg->pLeaf==0 ){
- /* All keys from this input segment have been transfered to the output.
- ** Set both the first and last page-numbers to 0 to indicate that the
- ** segment is now empty. */
- pSeg->pSeg->pgnoLast = 0;
- pSeg->pSeg->pgnoFirst = 0;
- }else{
- int iOff = pSeg->iTermLeafOffset; /* Offset on new first leaf page */
- i64 iLeafRowid;
- Fts5Data *pData;
- int iId = pSeg->pSeg->iSegid;
- u8 aHdr[4] = {0x00, 0x00, 0x00, 0x00};
-
- iLeafRowid = FTS5_SEGMENT_ROWID(iId, pSeg->iTermLeafPgno);
- pData = fts5DataRead(p, iLeafRowid);
- if( pData ){
- fts5BufferZero(&buf);
- fts5BufferGrow(&p->rc, &buf, pData->nn);
- fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr);
- fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n);
- fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p);
- fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff, &pData->p[iOff]);
- if( p->rc==SQLITE_OK ){
- /* Set the szLeaf field */
- fts5PutU16(&buf.p[2], (u16)buf.n);
- }
-
- /* Set up the new page-index array */
- fts5BufferAppendVarint(&p->rc, &buf, 4);
- if( pSeg->iLeafPgno==pSeg->iTermLeafPgno
- && pSeg->iEndofDoclist<pData->szLeaf
- ){
- int nDiff = pData->szLeaf - pSeg->iEndofDoclist;
- fts5BufferAppendVarint(&p->rc, &buf, buf.n - 1 - nDiff - 4);
- fts5BufferAppendBlob(&p->rc, &buf,
- pData->nn - pSeg->iPgidxOff, &pData->p[pSeg->iPgidxOff]
- );
- }
-
- fts5DataRelease(pData);
- pSeg->pSeg->pgnoFirst = pSeg->iTermLeafPgno;
- fts5DataDelete(p, FTS5_SEGMENT_ROWID(iId, 1), iLeafRowid);
- fts5DataWrite(p, iLeafRowid, buf.p, buf.n);
- }
- }
- }
- fts5BufferFree(&buf);
-}
-
-static void fts5MergeChunkCallback(
- Fts5Index *p,
- void *pCtx,
- const u8 *pChunk, int nChunk
-){
- Fts5SegWriter *pWriter = (Fts5SegWriter*)pCtx;
- fts5WriteAppendPoslistData(p, pWriter, pChunk, nChunk);
-}
-
-/*
-**
-*/
-static void fts5IndexMergeLevel(
- Fts5Index *p, /* FTS5 backend object */
- Fts5Structure **ppStruct, /* IN/OUT: Stucture of index */
- int iLvl, /* Level to read input from */
- int *pnRem /* Write up to this many output leaves */
-){
- Fts5Structure *pStruct = *ppStruct;
- Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
- Fts5StructureLevel *pLvlOut;
- Fts5Iter *pIter = 0; /* Iterator to read input data */
- int nRem = pnRem ? *pnRem : 0; /* Output leaf pages left to write */
- int nInput; /* Number of input segments */
- Fts5SegWriter writer; /* Writer object */
- Fts5StructureSegment *pSeg; /* Output segment */
- Fts5Buffer term;
- int bOldest; /* True if the output segment is the oldest */
- int eDetail = p->pConfig->eDetail;
- const int flags = FTS5INDEX_QUERY_NOOUTPUT;
-
- assert( iLvl<pStruct->nLevel );
- assert( pLvl->nMerge<=pLvl->nSeg );
-
- memset(&writer, 0, sizeof(Fts5SegWriter));
- memset(&term, 0, sizeof(Fts5Buffer));
- if( pLvl->nMerge ){
- pLvlOut = &pStruct->aLevel[iLvl+1];
- assert( pLvlOut->nSeg>0 );
- nInput = pLvl->nMerge;
- pSeg = &pLvlOut->aSeg[pLvlOut->nSeg-1];
-
- fts5WriteInit(p, &writer, pSeg->iSegid);
- writer.writer.pgno = pSeg->pgnoLast+1;
- writer.iBtPage = 0;
- }else{
- int iSegid = fts5AllocateSegid(p, pStruct);
-
- /* Extend the Fts5Structure object as required to ensure the output
- ** segment exists. */
- if( iLvl==pStruct->nLevel-1 ){
- fts5StructureAddLevel(&p->rc, ppStruct);
- pStruct = *ppStruct;
- }
- fts5StructureExtendLevel(&p->rc, pStruct, iLvl+1, 1, 0);
- if( p->rc ) return;
- pLvl = &pStruct->aLevel[iLvl];
- pLvlOut = &pStruct->aLevel[iLvl+1];
-
- fts5WriteInit(p, &writer, iSegid);
-
- /* Add the new segment to the output level */
- pSeg = &pLvlOut->aSeg[pLvlOut->nSeg];
- pLvlOut->nSeg++;
- pSeg->pgnoFirst = 1;
- pSeg->iSegid = iSegid;
- pStruct->nSegment++;
-
- /* Read input from all segments in the input level */
- nInput = pLvl->nSeg;
- }
- bOldest = (pLvlOut->nSeg==1 && pStruct->nLevel==iLvl+2);
-
- assert( iLvl>=0 );
- for(fts5MultiIterNew(p, pStruct, flags, 0, 0, 0, iLvl, nInput, &pIter);
- fts5MultiIterEof(p, pIter)==0;
- fts5MultiIterNext(p, pIter, 0, 0)
- ){
- Fts5SegIter *pSegIter = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
- int nPos; /* position-list size field value */
- int nTerm;
- const u8 *pTerm;
-
- /* Check for key annihilation. */
- if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue;
-
- pTerm = fts5MultiIterTerm(pIter, &nTerm);
- if( nTerm!=term.n || memcmp(pTerm, term.p, nTerm) ){
- if( pnRem && writer.nLeafWritten>nRem ){
- break;
- }
-
- /* This is a new term. Append a term to the output segment. */
- fts5WriteAppendTerm(p, &writer, nTerm, pTerm);
- fts5BufferSet(&p->rc, &term, nTerm, pTerm);
- }
-
- /* Append the rowid to the output */
- /* WRITEPOSLISTSIZE */
- fts5WriteAppendRowid(p, &writer, fts5MultiIterRowid(pIter));
-
- if( eDetail==FTS5_DETAIL_NONE ){
- if( pSegIter->bDel ){
- fts5BufferAppendVarint(&p->rc, &writer.writer.buf, 0);
- if( pSegIter->nPos>0 ){
- fts5BufferAppendVarint(&p->rc, &writer.writer.buf, 0);
- }
- }
- }else{
- /* Append the position-list data to the output */
- nPos = pSegIter->nPos*2 + pSegIter->bDel;
- fts5BufferAppendVarint(&p->rc, &writer.writer.buf, nPos);
- fts5ChunkIterate(p, pSegIter, (void*)&writer, fts5MergeChunkCallback);
- }
- }
-
- /* Flush the last leaf page to disk. Set the output segment b-tree height
- ** and last leaf page number at the same time. */
- fts5WriteFinish(p, &writer, &pSeg->pgnoLast);
-
- if( fts5MultiIterEof(p, pIter) ){
- int i;
-
- /* Remove the redundant segments from the %_data table */
- for(i=0; i<nInput; i++){
- fts5DataRemoveSegment(p, pLvl->aSeg[i].iSegid);
- }
-
- /* Remove the redundant segments from the input level */
- if( pLvl->nSeg!=nInput ){
- int nMove = (pLvl->nSeg - nInput) * sizeof(Fts5StructureSegment);
- memmove(pLvl->aSeg, &pLvl->aSeg[nInput], nMove);
- }
- pStruct->nSegment -= nInput;
- pLvl->nSeg -= nInput;
- pLvl->nMerge = 0;
- if( pSeg->pgnoLast==0 ){
- pLvlOut->nSeg--;
- pStruct->nSegment--;
- }
- }else{
- assert( pSeg->pgnoLast>0 );
- fts5TrimSegments(p, pIter);
- pLvl->nMerge = nInput;
- }
-
- fts5MultiIterFree(pIter);
- fts5BufferFree(&term);
- if( pnRem ) *pnRem -= writer.nLeafWritten;
-}
-
-/*
-** Do up to nPg pages of automerge work on the index.
-**
-** Return true if any changes were actually made, or false otherwise.
-*/
-static int fts5IndexMerge(
- Fts5Index *p, /* FTS5 backend object */
- Fts5Structure **ppStruct, /* IN/OUT: Current structure of index */
- int nPg, /* Pages of work to do */
- int nMin /* Minimum number of segments to merge */
-){
- int nRem = nPg;
- int bRet = 0;
- Fts5Structure *pStruct = *ppStruct;
- while( nRem>0 && p->rc==SQLITE_OK ){
- int iLvl; /* To iterate through levels */
- int iBestLvl = 0; /* Level offering the most input segments */
- int nBest = 0; /* Number of input segments on best level */
-
- /* Set iBestLvl to the level to read input segments from. */
- assert( pStruct->nLevel>0 );
- for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
- Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
- if( pLvl->nMerge ){
- if( pLvl->nMerge>nBest ){
- iBestLvl = iLvl;
- nBest = pLvl->nMerge;
- }
- break;
- }
- if( pLvl->nSeg>nBest ){
- nBest = pLvl->nSeg;
- iBestLvl = iLvl;
- }
- }
-
- /* If nBest is still 0, then the index must be empty. */
-#ifdef SQLITE_DEBUG
- for(iLvl=0; nBest==0 && iLvl<pStruct->nLevel; iLvl++){
- assert( pStruct->aLevel[iLvl].nSeg==0 );
- }
-#endif
-
- if( nBest<nMin && pStruct->aLevel[iBestLvl].nMerge==0 ){
- break;
- }
- bRet = 1;
- fts5IndexMergeLevel(p, &pStruct, iBestLvl, &nRem);
- if( p->rc==SQLITE_OK && pStruct->aLevel[iBestLvl].nMerge==0 ){
- fts5StructurePromote(p, iBestLvl+1, pStruct);
- }
- }
- *ppStruct = pStruct;
- return bRet;
-}
-
-/*
-** A total of nLeaf leaf pages of data has just been flushed to a level-0
-** segment. This function updates the write-counter accordingly and, if
-** necessary, performs incremental merge work.
-**
-** If an error occurs, set the Fts5Index.rc error code. If an error has
-** already occurred, this function is a no-op.
-*/
-static void fts5IndexAutomerge(
- Fts5Index *p, /* FTS5 backend object */
- Fts5Structure **ppStruct, /* IN/OUT: Current structure of index */
- int nLeaf /* Number of output leaves just written */
-){
- if( p->rc==SQLITE_OK && p->pConfig->nAutomerge>0 ){
- Fts5Structure *pStruct = *ppStruct;
- u64 nWrite; /* Initial value of write-counter */
- int nWork; /* Number of work-quanta to perform */
- int nRem; /* Number of leaf pages left to write */
-
- /* Update the write-counter. While doing so, set nWork. */
- nWrite = pStruct->nWriteCounter;
- nWork = (int)(((nWrite + nLeaf) / p->nWorkUnit) - (nWrite / p->nWorkUnit));
- pStruct->nWriteCounter += nLeaf;
- nRem = (int)(p->nWorkUnit * nWork * pStruct->nLevel);
-
- fts5IndexMerge(p, ppStruct, nRem, p->pConfig->nAutomerge);
- }
-}
-
-static void fts5IndexCrisismerge(
- Fts5Index *p, /* FTS5 backend object */
- Fts5Structure **ppStruct /* IN/OUT: Current structure of index */
-){
- const int nCrisis = p->pConfig->nCrisisMerge;
- Fts5Structure *pStruct = *ppStruct;
- int iLvl = 0;
-
- assert( p->rc!=SQLITE_OK || pStruct->nLevel>0 );
- while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){
- fts5IndexMergeLevel(p, &pStruct, iLvl, 0);
- assert( p->rc!=SQLITE_OK || pStruct->nLevel>(iLvl+1) );
- fts5StructurePromote(p, iLvl+1, pStruct);
- iLvl++;
- }
- *ppStruct = pStruct;
-}
-
-static int fts5IndexReturn(Fts5Index *p){
- int rc = p->rc;
- p->rc = SQLITE_OK;
- return rc;
-}
-
-typedef struct Fts5FlushCtx Fts5FlushCtx;
-struct Fts5FlushCtx {
- Fts5Index *pIdx;
- Fts5SegWriter writer;
-};
-
-/*
-** Buffer aBuf[] contains a list of varints, all small enough to fit
-** in a 32-bit integer. Return the size of the largest prefix of this
-** list nMax bytes or less in size.
-*/
-static int fts5PoslistPrefix(const u8 *aBuf, int nMax){
- int ret;
- u32 dummy;
- ret = fts5GetVarint32(aBuf, dummy);
- if( ret<nMax ){
- while( 1 ){
- int i = fts5GetVarint32(&aBuf[ret], dummy);
- if( (ret + i) > nMax ) break;
- ret += i;
- }
- }
- return ret;
-}
-
-/*
-** Flush the contents of in-memory hash table iHash to a new level-0
-** segment on disk. Also update the corresponding structure record.
-**
-** If an error occurs, set the Fts5Index.rc error code. If an error has
-** already occurred, this function is a no-op.
-*/
-static void fts5FlushOneHash(Fts5Index *p){
- Fts5Hash *pHash = p->pHash;
- Fts5Structure *pStruct;
- int iSegid;
- int pgnoLast = 0; /* Last leaf page number in segment */
-
- /* Obtain a reference to the index structure and allocate a new segment-id
- ** for the new level-0 segment. */
- pStruct = fts5StructureRead(p);
- iSegid = fts5AllocateSegid(p, pStruct);
- fts5StructureInvalidate(p);
-
- if( iSegid ){
- const int pgsz = p->pConfig->pgsz;
- int eDetail = p->pConfig->eDetail;
- Fts5StructureSegment *pSeg; /* New segment within pStruct */
- Fts5Buffer *pBuf; /* Buffer in which to assemble leaf page */
- Fts5Buffer *pPgidx; /* Buffer in which to assemble pgidx */
-
- Fts5SegWriter writer;
- fts5WriteInit(p, &writer, iSegid);
-
- pBuf = &writer.writer.buf;
- pPgidx = &writer.writer.pgidx;
-
- /* fts5WriteInit() should have initialized the buffers to (most likely)
- ** the maximum space required. */
- assert( p->rc || pBuf->nSpace>=(pgsz + FTS5_DATA_PADDING) );
- assert( p->rc || pPgidx->nSpace>=(pgsz + FTS5_DATA_PADDING) );
-
- /* Begin scanning through hash table entries. This loop runs once for each
- ** term/doclist currently stored within the hash table. */
- if( p->rc==SQLITE_OK ){
- p->rc = sqlite3Fts5HashScanInit(pHash, 0, 0);
- }
- while( p->rc==SQLITE_OK && 0==sqlite3Fts5HashScanEof(pHash) ){
- const char *zTerm; /* Buffer containing term */
- const u8 *pDoclist; /* Pointer to doclist for this term */
- int nDoclist; /* Size of doclist in bytes */
-
- /* Write the term for this entry to disk. */
- sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist);
- fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm);
-
- assert( writer.bFirstRowidInPage==0 );
- if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
- /* The entire doclist will fit on the current leaf. */
- fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist);
- }else{
- i64 iRowid = 0;
- i64 iDelta = 0;
- int iOff = 0;
-
- /* The entire doclist will not fit on this leaf. The following
- ** loop iterates through the poslists that make up the current
- ** doclist. */
- while( p->rc==SQLITE_OK && iOff<nDoclist ){
- iOff += fts5GetVarint(&pDoclist[iOff], (u64*)&iDelta);
- iRowid += iDelta;
-
- if( writer.bFirstRowidInPage ){
- fts5PutU16(&pBuf->p[0], (u16)pBuf->n); /* first rowid on page */
- pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
- writer.bFirstRowidInPage = 0;
- fts5WriteDlidxAppend(p, &writer, iRowid);
- }else{
- pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta);
- }
- assert( pBuf->n<=pBuf->nSpace );
-
- if( eDetail==FTS5_DETAIL_NONE ){
- if( iOff<nDoclist && pDoclist[iOff]==0 ){
- pBuf->p[pBuf->n++] = 0;
- iOff++;
- if( iOff<nDoclist && pDoclist[iOff]==0 ){
- pBuf->p[pBuf->n++] = 0;
- iOff++;
- }
- }
- if( (pBuf->n + pPgidx->n)>=pgsz ){
- fts5WriteFlushLeaf(p, &writer);
- }
- }else{
- int bDummy;
- int nPos;
- int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy);
- nCopy += nPos;
- if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){
- /* The entire poslist will fit on the current leaf. So copy
- ** it in one go. */
- fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy);
- }else{
- /* The entire poslist will not fit on this leaf. So it needs
- ** to be broken into sections. The only qualification being
- ** that each varint must be stored contiguously. */
- const u8 *pPoslist = &pDoclist[iOff];
- int iPos = 0;
- while( p->rc==SQLITE_OK ){
- int nSpace = pgsz - pBuf->n - pPgidx->n;
- int n = 0;
- if( (nCopy - iPos)<=nSpace ){
- n = nCopy - iPos;
- }else{
- n = fts5PoslistPrefix(&pPoslist[iPos], nSpace);
- }
- assert( n>0 );
- fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n);
- iPos += n;
- if( (pBuf->n + pPgidx->n)>=pgsz ){
- fts5WriteFlushLeaf(p, &writer);
- }
- if( iPos>=nCopy ) break;
- }
- }
- iOff += nCopy;
- }
- }
- }
-
- /* TODO2: Doclist terminator written here. */
- /* pBuf->p[pBuf->n++] = '\0'; */
- assert( pBuf->n<=pBuf->nSpace );
- sqlite3Fts5HashScanNext(pHash);
- }
- sqlite3Fts5HashClear(pHash);
- fts5WriteFinish(p, &writer, &pgnoLast);
-
- /* Update the Fts5Structure. It is written back to the database by the
- ** fts5StructureRelease() call below. */
- if( pStruct->nLevel==0 ){
- fts5StructureAddLevel(&p->rc, &pStruct);
- }
- fts5StructureExtendLevel(&p->rc, pStruct, 0, 1, 0);
- if( p->rc==SQLITE_OK ){
- pSeg = &pStruct->aLevel[0].aSeg[ pStruct->aLevel[0].nSeg++ ];
- pSeg->iSegid = iSegid;
- pSeg->pgnoFirst = 1;
- pSeg->pgnoLast = pgnoLast;
- pStruct->nSegment++;
- }
- fts5StructurePromote(p, 0, pStruct);
- }
-
- fts5IndexAutomerge(p, &pStruct, pgnoLast);
- fts5IndexCrisismerge(p, &pStruct);
- fts5StructureWrite(p, pStruct);
- fts5StructureRelease(pStruct);
-}
-
-/*
-** Flush any data stored in the in-memory hash tables to the database.
-*/
-static void fts5IndexFlush(Fts5Index *p){
- /* Unless it is empty, flush the hash table to disk */
- if( p->nPendingData ){
- assert( p->pHash );
- p->nPendingData = 0;
- fts5FlushOneHash(p);
- }
-}
-
-static Fts5Structure *fts5IndexOptimizeStruct(
- Fts5Index *p,
- Fts5Structure *pStruct
-){
- Fts5Structure *pNew = 0;
- int nByte = sizeof(Fts5Structure);
- int nSeg = pStruct->nSegment;
- int i;
-
- /* Figure out if this structure requires optimization. A structure does
- ** not require optimization if either:
- **
- ** + it consists of fewer than two segments, or
- ** + all segments are on the same level, or
- ** + all segments except one are currently inputs to a merge operation.
- **
- ** In the first case, return NULL. In the second, increment the ref-count
- ** on *pStruct and return a copy of the pointer to it.
- */
- if( nSeg<2 ) return 0;
- for(i=0; i<pStruct->nLevel; i++){
- int nThis = pStruct->aLevel[i].nSeg;
- if( nThis==nSeg || (nThis==nSeg-1 && pStruct->aLevel[i].nMerge==nThis) ){
- fts5StructureRef(pStruct);
- return pStruct;
- }
- assert( pStruct->aLevel[i].nMerge<=nThis );
- }
-
- nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel);
- pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte);
-
- if( pNew ){
- Fts5StructureLevel *pLvl;
- nByte = nSeg * sizeof(Fts5StructureSegment);
- pNew->nLevel = pStruct->nLevel+1;
- pNew->nRef = 1;
- pNew->nWriteCounter = pStruct->nWriteCounter;
- pLvl = &pNew->aLevel[pStruct->nLevel];
- pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&p->rc, nByte);
- if( pLvl->aSeg ){
- int iLvl, iSeg;
- int iSegOut = 0;
- /* Iterate through all segments, from oldest to newest. Add them to
- ** the new Fts5Level object so that pLvl->aSeg[0] is the oldest
- ** segment in the data structure. */
- for(iLvl=pStruct->nLevel-1; iLvl>=0; iLvl--){
- for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
- pLvl->aSeg[iSegOut] = pStruct->aLevel[iLvl].aSeg[iSeg];
- iSegOut++;
- }
- }
- pNew->nSegment = pLvl->nSeg = nSeg;
- }else{
- sqlite3_free(pNew);
- pNew = 0;
- }
- }
-
- return pNew;
-}
-
-static int sqlite3Fts5IndexOptimize(Fts5Index *p){
- Fts5Structure *pStruct;
- Fts5Structure *pNew = 0;
-
- assert( p->rc==SQLITE_OK );
- fts5IndexFlush(p);
- pStruct = fts5StructureRead(p);
- fts5StructureInvalidate(p);
-
- if( pStruct ){
- pNew = fts5IndexOptimizeStruct(p, pStruct);
- }
- fts5StructureRelease(pStruct);
-
- assert( pNew==0 || pNew->nSegment>0 );
- if( pNew ){
- int iLvl;
- for(iLvl=0; pNew->aLevel[iLvl].nSeg==0; iLvl++){}
- while( p->rc==SQLITE_OK && pNew->aLevel[iLvl].nSeg>0 ){
- int nRem = FTS5_OPT_WORK_UNIT;
- fts5IndexMergeLevel(p, &pNew, iLvl, &nRem);
- }
-
- fts5StructureWrite(p, pNew);
- fts5StructureRelease(pNew);
- }
-
- return fts5IndexReturn(p);
-}
-
-/*
-** This is called to implement the special "VALUES('merge', $nMerge)"
-** INSERT command.
-*/
-static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
- Fts5Structure *pStruct = fts5StructureRead(p);
- if( pStruct ){
- int nMin = p->pConfig->nUsermerge;
- fts5StructureInvalidate(p);
- if( nMerge<0 ){
- Fts5Structure *pNew = fts5IndexOptimizeStruct(p, pStruct);
- fts5StructureRelease(pStruct);
- pStruct = pNew;
- nMin = 2;
- nMerge = nMerge*-1;
- }
- if( pStruct && pStruct->nLevel ){
- if( fts5IndexMerge(p, &pStruct, nMerge, nMin) ){
- fts5StructureWrite(p, pStruct);
- }
- }
- fts5StructureRelease(pStruct);
- }
- return fts5IndexReturn(p);
-}
-
-static void fts5AppendRowid(
- Fts5Index *p,
- i64 iDelta,
- Fts5Iter *pUnused,
- Fts5Buffer *pBuf
-){
- UNUSED_PARAM(pUnused);
- fts5BufferAppendVarint(&p->rc, pBuf, iDelta);
-}
-
-static void fts5AppendPoslist(
- Fts5Index *p,
- i64 iDelta,
- Fts5Iter *pMulti,
- Fts5Buffer *pBuf
-){
- int nData = pMulti->base.nData;
- assert( nData>0 );
- if( p->rc==SQLITE_OK && 0==fts5BufferGrow(&p->rc, pBuf, nData+9+9) ){
- fts5BufferSafeAppendVarint(pBuf, iDelta);
- fts5BufferSafeAppendVarint(pBuf, nData*2);
- fts5BufferSafeAppendBlob(pBuf, pMulti->base.pData, nData);
- }
-}
-
-
-static void fts5DoclistIterNext(Fts5DoclistIter *pIter){
- u8 *p = pIter->aPoslist + pIter->nSize + pIter->nPoslist;
-
- assert( pIter->aPoslist );
- if( p>=pIter->aEof ){
- pIter->aPoslist = 0;
- }else{
- i64 iDelta;
-
- p += fts5GetVarint(p, (u64*)&iDelta);
- pIter->iRowid += iDelta;
-
- /* Read position list size */
- if( p[0] & 0x80 ){
- int nPos;
- pIter->nSize = fts5GetVarint32(p, nPos);
- pIter->nPoslist = (nPos>>1);
- }else{
- pIter->nPoslist = ((int)(p[0])) >> 1;
- pIter->nSize = 1;
- }
-
- pIter->aPoslist = p;
- }
-}
-
-static void fts5DoclistIterInit(
- Fts5Buffer *pBuf,
- Fts5DoclistIter *pIter
-){
- memset(pIter, 0, sizeof(*pIter));
- pIter->aPoslist = pBuf->p;
- pIter->aEof = &pBuf->p[pBuf->n];
- fts5DoclistIterNext(pIter);
-}
-
-#if 0
-/*
-** Append a doclist to buffer pBuf.
-**
-** This function assumes that space within the buffer has already been
-** allocated.
-*/
-static void fts5MergeAppendDocid(
- Fts5Buffer *pBuf, /* Buffer to write to */
- i64 *piLastRowid, /* IN/OUT: Previous rowid written (if any) */
- i64 iRowid /* Rowid to append */
-){
- assert( pBuf->n!=0 || (*piLastRowid)==0 );
- fts5BufferSafeAppendVarint(pBuf, iRowid - *piLastRowid);
- *piLastRowid = iRowid;
-}
-#endif
-
-#define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) { \
- assert( (pBuf)->n!=0 || (iLastRowid)==0 ); \
- fts5BufferSafeAppendVarint((pBuf), (iRowid) - (iLastRowid)); \
- (iLastRowid) = (iRowid); \
-}
-
-/*
-** Swap the contents of buffer *p1 with that of *p2.
-*/
-static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){
- Fts5Buffer tmp = *p1;
- *p1 = *p2;
- *p2 = tmp;
-}
-
-static void fts5NextRowid(Fts5Buffer *pBuf, int *piOff, i64 *piRowid){
- int i = *piOff;
- if( i>=pBuf->n ){
- *piOff = -1;
- }else{
- u64 iVal;
- *piOff = i + sqlite3Fts5GetVarint(&pBuf->p[i], &iVal);
- *piRowid += iVal;
- }
-}
-
-/*
-** This is the equivalent of fts5MergePrefixLists() for detail=none mode.
-** In this case the buffers consist of a delta-encoded list of rowids only.
-*/
-static void fts5MergeRowidLists(
- Fts5Index *p, /* FTS5 backend object */
- Fts5Buffer *p1, /* First list to merge */
- Fts5Buffer *p2 /* Second list to merge */
-){
- int i1 = 0;
- int i2 = 0;
- i64 iRowid1 = 0;
- i64 iRowid2 = 0;
- i64 iOut = 0;
-
- Fts5Buffer out;
- memset(&out, 0, sizeof(out));
- sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n);
- if( p->rc ) return;
-
- fts5NextRowid(p1, &i1, &iRowid1);
- fts5NextRowid(p2, &i2, &iRowid2);
- while( i1>=0 || i2>=0 ){
- if( i1>=0 && (i2<0 || iRowid1<iRowid2) ){
- assert( iOut==0 || iRowid1>iOut );
- fts5BufferSafeAppendVarint(&out, iRowid1 - iOut);
- iOut = iRowid1;
- fts5NextRowid(p1, &i1, &iRowid1);
- }else{
- assert( iOut==0 || iRowid2>iOut );
- fts5BufferSafeAppendVarint(&out, iRowid2 - iOut);
- iOut = iRowid2;
- if( i1>=0 && iRowid1==iRowid2 ){
- fts5NextRowid(p1, &i1, &iRowid1);
- }
- fts5NextRowid(p2, &i2, &iRowid2);
- }
- }
-
- fts5BufferSwap(&out, p1);
- fts5BufferFree(&out);
-}
-
-/*
-** Buffers p1 and p2 contain doclists. This function merges the content
-** of the two doclists together and sets buffer p1 to the result before
-** returning.
-**
-** If an error occurs, an error code is left in p->rc. If an error has
-** already occurred, this function is a no-op.
-*/
-static void fts5MergePrefixLists(
- Fts5Index *p, /* FTS5 backend object */
- Fts5Buffer *p1, /* First list to merge */
- Fts5Buffer *p2 /* Second list to merge */
-){
- if( p2->n ){
- i64 iLastRowid = 0;
- Fts5DoclistIter i1;
- Fts5DoclistIter i2;
- Fts5Buffer out = {0, 0, 0};
- Fts5Buffer tmp = {0, 0, 0};
-
- if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n) ) return;
- fts5DoclistIterInit(p1, &i1);
- fts5DoclistIterInit(p2, &i2);
-
- while( 1 ){
- if( i1.iRowid<i2.iRowid ){
- /* Copy entry from i1 */
- fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid);
- fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.nPoslist+i1.nSize);
- fts5DoclistIterNext(&i1);
- if( i1.aPoslist==0 ) break;
- }
- else if( i2.iRowid!=i1.iRowid ){
- /* Copy entry from i2 */
- fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
- fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.nPoslist+i2.nSize);
- fts5DoclistIterNext(&i2);
- if( i2.aPoslist==0 ) break;
- }
- else{
- /* Merge the two position lists. */
- i64 iPos1 = 0;
- i64 iPos2 = 0;
- int iOff1 = 0;
- int iOff2 = 0;
- u8 *a1 = &i1.aPoslist[i1.nSize];
- u8 *a2 = &i2.aPoslist[i2.nSize];
-
- i64 iPrev = 0;
- Fts5PoslistWriter writer;
- memset(&writer, 0, sizeof(writer));
-
- fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
- fts5BufferZero(&tmp);
- sqlite3Fts5BufferSize(&p->rc, &tmp, i1.nPoslist + i2.nPoslist);
- if( p->rc ) break;
-
- sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
- sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
- assert( iPos1>=0 && iPos2>=0 );
-
- if( iPos1<iPos2 ){
- sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
- sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
- }else{
- sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
- sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
- }
-
- if( iPos1>=0 && iPos2>=0 ){
- while( 1 ){
- if( iPos1<iPos2 ){
- if( iPos1!=iPrev ){
- sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
- }
- sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
- if( iPos1<0 ) break;
- }else{
- assert( iPos2!=iPrev );
- sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
- sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
- if( iPos2<0 ) break;
- }
- }
- }
-
- if( iPos1>=0 ){
- if( iPos1!=iPrev ){
- sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
- }
- fts5BufferSafeAppendBlob(&tmp, &a1[iOff1], i1.nPoslist-iOff1);
- }else{
- assert( iPos2>=0 && iPos2!=iPrev );
- sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
- fts5BufferSafeAppendBlob(&tmp, &a2[iOff2], i2.nPoslist-iOff2);
- }
-
- /* WRITEPOSLISTSIZE */
- fts5BufferSafeAppendVarint(&out, tmp.n * 2);
- fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n);
- fts5DoclistIterNext(&i1);
- fts5DoclistIterNext(&i2);
- if( i1.aPoslist==0 || i2.aPoslist==0 ) break;
- }
- }
-
- if( i1.aPoslist ){
- fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid);
- fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.aEof - i1.aPoslist);
- }
- else if( i2.aPoslist ){
- fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
- fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.aEof - i2.aPoslist);
- }
-
- fts5BufferSet(&p->rc, p1, out.n, out.p);
- fts5BufferFree(&tmp);
- fts5BufferFree(&out);
- }
-}
-
-static void fts5SetupPrefixIter(
- Fts5Index *p, /* Index to read from */
- int bDesc, /* True for "ORDER BY rowid DESC" */
- const u8 *pToken, /* Buffer containing prefix to match */
- int nToken, /* Size of buffer pToken in bytes */
- Fts5Colset *pColset, /* Restrict matches to these columns */
- Fts5Iter **ppIter /* OUT: New iterator */
-){
- Fts5Structure *pStruct;
- Fts5Buffer *aBuf;
- const int nBuf = 32;
-
- void (*xMerge)(Fts5Index*, Fts5Buffer*, Fts5Buffer*);
- void (*xAppend)(Fts5Index*, i64, Fts5Iter*, Fts5Buffer*);
- if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
- xMerge = fts5MergeRowidLists;
- xAppend = fts5AppendRowid;
- }else{
- xMerge = fts5MergePrefixLists;
- xAppend = fts5AppendPoslist;
- }
-
- aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf);
- pStruct = fts5StructureRead(p);
-
- if( aBuf && pStruct ){
- const int flags = FTS5INDEX_QUERY_SCAN
- | FTS5INDEX_QUERY_SKIPEMPTY
- | FTS5INDEX_QUERY_NOOUTPUT;
- int i;
- i64 iLastRowid = 0;
- Fts5Iter *p1 = 0; /* Iterator used to gather data from index */
- Fts5Data *pData;
- Fts5Buffer doclist;
- int bNewTerm = 1;
-
- memset(&doclist, 0, sizeof(doclist));
- fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1);
- fts5IterSetOutputCb(&p->rc, p1);
- for( /* no-op */ ;
- fts5MultiIterEof(p, p1)==0;
- fts5MultiIterNext2(p, p1, &bNewTerm)
- ){
- Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
- int nTerm = pSeg->term.n;
- const u8 *pTerm = pSeg->term.p;
- p1->xSetOutputs(p1, pSeg);
-
- assert_nc( memcmp(pToken, pTerm, MIN(nToken, nTerm))<=0 );
- if( bNewTerm ){
- if( nTerm<nToken || memcmp(pToken, pTerm, nToken) ) break;
- }
-
- if( p1->base.nData==0 ) continue;
-
- if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){
- for(i=0; p->rc==SQLITE_OK && doclist.n; i++){
- assert( i<nBuf );
- if( aBuf[i].n==0 ){
- fts5BufferSwap(&doclist, &aBuf[i]);
- fts5BufferZero(&doclist);
- }else{
- xMerge(p, &doclist, &aBuf[i]);
- fts5BufferZero(&aBuf[i]);
- }
- }
- iLastRowid = 0;
- }
-
- xAppend(p, p1->base.iRowid-iLastRowid, p1, &doclist);
- iLastRowid = p1->base.iRowid;
- }
-
- for(i=0; i<nBuf; i++){
- if( p->rc==SQLITE_OK ){
- xMerge(p, &doclist, &aBuf[i]);
- }
- fts5BufferFree(&aBuf[i]);
- }
- fts5MultiIterFree(p1);
-
- pData = fts5IdxMalloc(p, sizeof(Fts5Data) + doclist.n);
- if( pData ){
- pData->p = (u8*)&pData[1];
- pData->nn = pData->szLeaf = doclist.n;
- memcpy(pData->p, doclist.p, doclist.n);
- fts5MultiIterNew2(p, pData, bDesc, ppIter);
- }
- fts5BufferFree(&doclist);
- }
-
- fts5StructureRelease(pStruct);
- sqlite3_free(aBuf);
-}
-
-
-/*
-** Indicate that all subsequent calls to sqlite3Fts5IndexWrite() pertain
-** to the document with rowid iRowid.
-*/
-static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
- assert( p->rc==SQLITE_OK );
-
- /* Allocate the hash table if it has not already been allocated */
- if( p->pHash==0 ){
- p->rc = sqlite3Fts5HashNew(p->pConfig, &p->pHash, &p->nPendingData);
- }
-
- /* Flush the hash table to disk if required */
- if( iRowid<p->iWriteRowid
- || (iRowid==p->iWriteRowid && p->bDelete==0)
- || (p->nPendingData > p->pConfig->nHashSize)
- ){
- fts5IndexFlush(p);
- }
-
- p->iWriteRowid = iRowid;
- p->bDelete = bDelete;
- return fts5IndexReturn(p);
-}
-
-/*
-** Commit data to disk.
-*/
-static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){
- assert( p->rc==SQLITE_OK );
- fts5IndexFlush(p);
- if( bCommit ) fts5CloseReader(p);
- return fts5IndexReturn(p);
-}
-
-/*
-** Discard any data stored in the in-memory hash tables. Do not write it
-** to the database. Additionally, assume that the contents of the %_data
-** table may have changed on disk. So any in-memory caches of %_data
-** records must be invalidated.
-*/
-static int sqlite3Fts5IndexRollback(Fts5Index *p){
- fts5CloseReader(p);
- fts5IndexDiscardData(p);
- fts5StructureInvalidate(p);
- /* assert( p->rc==SQLITE_OK ); */
- return SQLITE_OK;
-}
-
-/*
-** The %_data table is completely empty when this function is called. This
-** function populates it with the initial structure objects for each index,
-** and the initial version of the "averages" record (a zero-byte blob).
-*/
-static int sqlite3Fts5IndexReinit(Fts5Index *p){
- Fts5Structure s;
- fts5StructureInvalidate(p);
- memset(&s, 0, sizeof(Fts5Structure));
- fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0);
- fts5StructureWrite(p, &s);
- return fts5IndexReturn(p);
-}
-
-/*
-** Open a new Fts5Index handle. If the bCreate argument is true, create
-** and initialize the underlying %_data table.
-**
-** If successful, set *pp to point to the new object and return SQLITE_OK.
-** Otherwise, set *pp to NULL and return an SQLite error code.
-*/
-static int sqlite3Fts5IndexOpen(
- Fts5Config *pConfig,
- int bCreate,
- Fts5Index **pp,
- char **pzErr
-){
- int rc = SQLITE_OK;
- Fts5Index *p; /* New object */
-
- *pp = p = (Fts5Index*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Index));
- if( rc==SQLITE_OK ){
- p->pConfig = pConfig;
- p->nWorkUnit = FTS5_WORK_UNIT;
- p->zDataTbl = sqlite3Fts5Mprintf(&rc, "%s_data", pConfig->zName);
- if( p->zDataTbl && bCreate ){
- rc = sqlite3Fts5CreateTable(
- pConfig, "data", "id INTEGER PRIMARY KEY, block BLOB", 0, pzErr
- );
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5CreateTable(pConfig, "idx",
- "segid, term, pgno, PRIMARY KEY(segid, term)",
- 1, pzErr
- );
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5IndexReinit(p);
- }
- }
- }
-
- assert( rc!=SQLITE_OK || p->rc==SQLITE_OK );
- if( rc ){
- sqlite3Fts5IndexClose(p);
- *pp = 0;
- }
- return rc;
-}
-
-/*
-** Close a handle opened by an earlier call to sqlite3Fts5IndexOpen().
-*/
-static int sqlite3Fts5IndexClose(Fts5Index *p){
- int rc = SQLITE_OK;
- if( p ){
- assert( p->pReader==0 );
- fts5StructureInvalidate(p);
- sqlite3_finalize(p->pWriter);
- sqlite3_finalize(p->pDeleter);
- sqlite3_finalize(p->pIdxWriter);
- sqlite3_finalize(p->pIdxDeleter);
- sqlite3_finalize(p->pIdxSelect);
- sqlite3_finalize(p->pDataVersion);
- sqlite3Fts5HashFree(p->pHash);
- sqlite3_free(p->zDataTbl);
- sqlite3_free(p);
- }
- return rc;
-}
-
-/*
-** Argument p points to a buffer containing utf-8 text that is n bytes in
-** size. Return the number of bytes in the nChar character prefix of the
-** buffer, or 0 if there are less than nChar characters in total.
-*/
-static int sqlite3Fts5IndexCharlenToBytelen(
- const char *p,
- int nByte,
- int nChar
-){
- int n = 0;
- int i;
- for(i=0; i<nChar; i++){
- if( n>=nByte ) return 0; /* Input contains fewer than nChar chars */
- if( (unsigned char)p[n++]>=0xc0 ){
- while( (p[n] & 0xc0)==0x80 ) n++;
- }
- }
- return n;
-}
-
-/*
-** pIn is a UTF-8 encoded string, nIn bytes in size. Return the number of
-** unicode characters in the string.
-*/
-static int fts5IndexCharlen(const char *pIn, int nIn){
- int nChar = 0;
- int i = 0;
- while( i<nIn ){
- if( (unsigned char)pIn[i++]>=0xc0 ){
- while( i<nIn && (pIn[i] & 0xc0)==0x80 ) i++;
- }
- nChar++;
- }
- return nChar;
-}
-
-/*
-** Insert or remove data to or from the index. Each time a document is
-** added to or removed from the index, this function is called one or more
-** times.
-**
-** For an insert, it must be called once for each token in the new document.
-** If the operation is a delete, it must be called (at least) once for each
-** unique token in the document with an iCol value less than zero. The iPos
-** argument is ignored for a delete.
-*/
-static int sqlite3Fts5IndexWrite(
- Fts5Index *p, /* Index to write to */
- int iCol, /* Column token appears in (-ve -> delete) */
- int iPos, /* Position of token within column */
- const char *pToken, int nToken /* Token to add or remove to or from index */
-){
- int i; /* Used to iterate through indexes */
- int rc = SQLITE_OK; /* Return code */
- Fts5Config *pConfig = p->pConfig;
-
- assert( p->rc==SQLITE_OK );
- assert( (iCol<0)==p->bDelete );
-
- /* Add the entry to the main terms index. */
- rc = sqlite3Fts5HashWrite(
- p->pHash, p->iWriteRowid, iCol, iPos, FTS5_MAIN_PREFIX, pToken, nToken
- );
-
- for(i=0; i<pConfig->nPrefix && rc==SQLITE_OK; i++){
- const int nChar = pConfig->aPrefix[i];
- int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar);
- if( nByte ){
- rc = sqlite3Fts5HashWrite(p->pHash,
- p->iWriteRowid, iCol, iPos, (char)(FTS5_MAIN_PREFIX+i+1), pToken,
- nByte
- );
- }
- }
-
- return rc;
-}
-
-/*
-** Open a new iterator to iterate though all rowid that match the
-** specified token or token prefix.
-*/
-static int sqlite3Fts5IndexQuery(
- Fts5Index *p, /* FTS index to query */
- const char *pToken, int nToken, /* Token (or prefix) to query for */
- int flags, /* Mask of FTS5INDEX_QUERY_X flags */
- Fts5Colset *pColset, /* Match these columns only */
- Fts5IndexIter **ppIter /* OUT: New iterator object */
-){
- Fts5Config *pConfig = p->pConfig;
- Fts5Iter *pRet = 0;
- Fts5Buffer buf = {0, 0, 0};
-
- /* If the QUERY_SCAN flag is set, all other flags must be clear. */
- assert( (flags & FTS5INDEX_QUERY_SCAN)==0 || flags==FTS5INDEX_QUERY_SCAN );
-
- if( sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){
- int iIdx = 0; /* Index to search */
- memcpy(&buf.p[1], pToken, nToken);
-
- /* Figure out which index to search and set iIdx accordingly. If this
- ** is a prefix query for which there is no prefix index, set iIdx to
- ** greater than pConfig->nPrefix to indicate that the query will be
- ** satisfied by scanning multiple terms in the main index.
- **
- ** If the QUERY_TEST_NOIDX flag was specified, then this must be a
- ** prefix-query. Instead of using a prefix-index (if one exists),
- ** evaluate the prefix query using the main FTS index. This is used
- ** for internal sanity checking by the integrity-check in debug
- ** mode only. */
-#ifdef SQLITE_DEBUG
- if( pConfig->bPrefixIndex==0 || (flags & FTS5INDEX_QUERY_TEST_NOIDX) ){
- assert( flags & FTS5INDEX_QUERY_PREFIX );
- iIdx = 1+pConfig->nPrefix;
- }else
-#endif
- if( flags & FTS5INDEX_QUERY_PREFIX ){
- int nChar = fts5IndexCharlen(pToken, nToken);
- for(iIdx=1; iIdx<=pConfig->nPrefix; iIdx++){
- if( pConfig->aPrefix[iIdx-1]==nChar ) break;
- }
- }
-
- if( iIdx<=pConfig->nPrefix ){
- /* Straight index lookup */
- Fts5Structure *pStruct = fts5StructureRead(p);
- buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx);
- if( pStruct ){
- fts5MultiIterNew(p, pStruct, flags | FTS5INDEX_QUERY_SKIPEMPTY,
- pColset, buf.p, nToken+1, -1, 0, &pRet
- );
- fts5StructureRelease(pStruct);
- }
- }else{
- /* Scan multiple terms in the main index */
- int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0;
- buf.p[0] = FTS5_MAIN_PREFIX;
- fts5SetupPrefixIter(p, bDesc, buf.p, nToken+1, pColset, &pRet);
- assert( p->rc!=SQLITE_OK || pRet->pColset==0 );
- fts5IterSetOutputCb(&p->rc, pRet);
- if( p->rc==SQLITE_OK ){
- Fts5SegIter *pSeg = &pRet->aSeg[pRet->aFirst[1].iFirst];
- if( pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg);
- }
- }
-
- if( p->rc ){
- sqlite3Fts5IterClose(&pRet->base);
- pRet = 0;
- fts5CloseReader(p);
- }
-
- *ppIter = &pRet->base;
- sqlite3Fts5BufferFree(&buf);
- }
- return fts5IndexReturn(p);
-}
-
-/*
-** Return true if the iterator passed as the only argument is at EOF.
-*/
-/*
-** Move to the next matching rowid.
-*/
-static int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){
- Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
- assert( pIter->pIndex->rc==SQLITE_OK );
- fts5MultiIterNext(pIter->pIndex, pIter, 0, 0);
- return fts5IndexReturn(pIter->pIndex);
-}
-
-/*
-** Move to the next matching term/rowid. Used by the fts5vocab module.
-*/
-static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIndexIter){
- Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
- Fts5Index *p = pIter->pIndex;
-
- assert( pIter->pIndex->rc==SQLITE_OK );
-
- fts5MultiIterNext(p, pIter, 0, 0);
- if( p->rc==SQLITE_OK ){
- Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
- if( pSeg->pLeaf && pSeg->term.p[0]!=FTS5_MAIN_PREFIX ){
- fts5DataRelease(pSeg->pLeaf);
- pSeg->pLeaf = 0;
- pIter->base.bEof = 1;
- }
- }
-
- return fts5IndexReturn(pIter->pIndex);
-}
-
-/*
-** Move to the next matching rowid that occurs at or after iMatch. The
-** definition of "at or after" depends on whether this iterator iterates
-** in ascending or descending rowid order.
-*/
-static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){
- Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
- fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch);
- return fts5IndexReturn(pIter->pIndex);
-}
-
-/*
-** Return the current term.
-*/
-static const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){
- int n;
- const char *z = (const char*)fts5MultiIterTerm((Fts5Iter*)pIndexIter, &n);
- *pn = n-1;
- return &z[1];
-}
-
-/*
-** Close an iterator opened by an earlier call to sqlite3Fts5IndexQuery().
-*/
-static void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){
- if( pIndexIter ){
- Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
- Fts5Index *pIndex = pIter->pIndex;
- fts5MultiIterFree(pIter);
- fts5CloseReader(pIndex);
- }
-}
-
-/*
-** Read and decode the "averages" record from the database.
-**
-** Parameter anSize must point to an array of size nCol, where nCol is
-** the number of user defined columns in the FTS table.
-*/
-static int sqlite3Fts5IndexGetAverages(Fts5Index *p, i64 *pnRow, i64 *anSize){
- int nCol = p->pConfig->nCol;
- Fts5Data *pData;
-
- *pnRow = 0;
- memset(anSize, 0, sizeof(i64) * nCol);
- pData = fts5DataRead(p, FTS5_AVERAGES_ROWID);
- if( p->rc==SQLITE_OK && pData->nn ){
- int i = 0;
- int iCol;
- i += fts5GetVarint(&pData->p[i], (u64*)pnRow);
- for(iCol=0; i<pData->nn && iCol<nCol; iCol++){
- i += fts5GetVarint(&pData->p[i], (u64*)&anSize[iCol]);
- }
- }
-
- fts5DataRelease(pData);
- return fts5IndexReturn(p);
-}
-
-/*
-** Replace the current "averages" record with the contents of the buffer
-** supplied as the second argument.
-*/
-static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8 *pData, int nData){
- assert( p->rc==SQLITE_OK );
- fts5DataWrite(p, FTS5_AVERAGES_ROWID, pData, nData);
- return fts5IndexReturn(p);
-}
-
-/*
-** Return the total number of blocks this module has read from the %_data
-** table since it was created.
-*/
-static int sqlite3Fts5IndexReads(Fts5Index *p){
- return p->nRead;
-}
-
-/*
-** Set the 32-bit cookie value stored at the start of all structure
-** records to the value passed as the second argument.
-**
-** Return SQLITE_OK if successful, or an SQLite error code if an error
-** occurs.
-*/
-static int sqlite3Fts5IndexSetCookie(Fts5Index *p, int iNew){
- int rc; /* Return code */
- Fts5Config *pConfig = p->pConfig; /* Configuration object */
- u8 aCookie[4]; /* Binary representation of iNew */
- sqlite3_blob *pBlob = 0;
-
- assert( p->rc==SQLITE_OK );
- sqlite3Fts5Put32(aCookie, iNew);
-
- rc = sqlite3_blob_open(pConfig->db, pConfig->zDb, p->zDataTbl,
- "block", FTS5_STRUCTURE_ROWID, 1, &pBlob
- );
- if( rc==SQLITE_OK ){
- sqlite3_blob_write(pBlob, aCookie, 4, 0);
- rc = sqlite3_blob_close(pBlob);
- }
-
- return rc;
-}
-
-static int sqlite3Fts5IndexLoadConfig(Fts5Index *p){
- Fts5Structure *pStruct;
- pStruct = fts5StructureRead(p);
- fts5StructureRelease(pStruct);
- return fts5IndexReturn(p);
-}
-
-
-/*************************************************************************
-**************************************************************************
-** Below this point is the implementation of the integrity-check
-** functionality.
-*/
-
-/*
-** Return a simple checksum value based on the arguments.
-*/
-static u64 sqlite3Fts5IndexEntryCksum(
- i64 iRowid,
- int iCol,
- int iPos,
- int iIdx,
- const char *pTerm,
- int nTerm
-){
- int i;
- u64 ret = iRowid;
- ret += (ret<<3) + iCol;
- ret += (ret<<3) + iPos;
- if( iIdx>=0 ) ret += (ret<<3) + (FTS5_MAIN_PREFIX + iIdx);
- for(i=0; i<nTerm; i++) ret += (ret<<3) + pTerm[i];
- return ret;
-}
-
-#ifdef SQLITE_DEBUG
-/*
-** This function is purely an internal test. It does not contribute to
-** FTS functionality, or even the integrity-check, in any way.
-**
-** Instead, it tests that the same set of pgno/rowid combinations are
-** visited regardless of whether the doclist-index identified by parameters
-** iSegid/iLeaf is iterated in forwards or reverse order.
-*/
-static void fts5TestDlidxReverse(
- Fts5Index *p,
- int iSegid, /* Segment id to load from */
- int iLeaf /* Load doclist-index for this leaf */
-){
- Fts5DlidxIter *pDlidx = 0;
- u64 cksum1 = 13;
- u64 cksum2 = 13;
-
- for(pDlidx=fts5DlidxIterInit(p, 0, iSegid, iLeaf);
- fts5DlidxIterEof(p, pDlidx)==0;
- fts5DlidxIterNext(p, pDlidx)
- ){
- i64 iRowid = fts5DlidxIterRowid(pDlidx);
- int pgno = fts5DlidxIterPgno(pDlidx);
- assert( pgno>iLeaf );
- cksum1 += iRowid + ((i64)pgno<<32);
- }
- fts5DlidxIterFree(pDlidx);
- pDlidx = 0;
-
- for(pDlidx=fts5DlidxIterInit(p, 1, iSegid, iLeaf);
- fts5DlidxIterEof(p, pDlidx)==0;
- fts5DlidxIterPrev(p, pDlidx)
- ){
- i64 iRowid = fts5DlidxIterRowid(pDlidx);
- int pgno = fts5DlidxIterPgno(pDlidx);
- assert( fts5DlidxIterPgno(pDlidx)>iLeaf );
- cksum2 += iRowid + ((i64)pgno<<32);
- }
- fts5DlidxIterFree(pDlidx);
- pDlidx = 0;
-
- if( p->rc==SQLITE_OK && cksum1!=cksum2 ) p->rc = FTS5_CORRUPT;
-}
-
-static int fts5QueryCksum(
- Fts5Index *p, /* Fts5 index object */
- int iIdx,
- const char *z, /* Index key to query for */
- int n, /* Size of index key in bytes */
- int flags, /* Flags for Fts5IndexQuery */
- u64 *pCksum /* IN/OUT: Checksum value */
-){
- int eDetail = p->pConfig->eDetail;
- u64 cksum = *pCksum;
- Fts5IndexIter *pIter = 0;
- int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter);
-
- while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIter) ){
- i64 rowid = pIter->iRowid;
-
- if( eDetail==FTS5_DETAIL_NONE ){
- cksum ^= sqlite3Fts5IndexEntryCksum(rowid, 0, 0, iIdx, z, n);
- }else{
- Fts5PoslistReader sReader;
- for(sqlite3Fts5PoslistReaderInit(pIter->pData, pIter->nData, &sReader);
- sReader.bEof==0;
- sqlite3Fts5PoslistReaderNext(&sReader)
- ){
- int iCol = FTS5_POS2COLUMN(sReader.iPos);
- int iOff = FTS5_POS2OFFSET(sReader.iPos);
- cksum ^= sqlite3Fts5IndexEntryCksum(rowid, iCol, iOff, iIdx, z, n);
- }
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5IterNext(pIter);
- }
- }
- sqlite3Fts5IterClose(pIter);
-
- *pCksum = cksum;
- return rc;
-}
-
-
-/*
-** This function is also purely an internal test. It does not contribute to
-** FTS functionality, or even the integrity-check, in any way.
-*/
-static void fts5TestTerm(
- Fts5Index *p,
- Fts5Buffer *pPrev, /* Previous term */
- const char *z, int n, /* Possibly new term to test */
- u64 expected,
- u64 *pCksum
-){
- int rc = p->rc;
- if( pPrev->n==0 ){
- fts5BufferSet(&rc, pPrev, n, (const u8*)z);
- }else
- if( rc==SQLITE_OK && (pPrev->n!=n || memcmp(pPrev->p, z, n)) ){
- u64 cksum3 = *pCksum;
- const char *zTerm = (const char*)&pPrev->p[1]; /* term sans prefix-byte */
- int nTerm = pPrev->n-1; /* Size of zTerm in bytes */
- int iIdx = (pPrev->p[0] - FTS5_MAIN_PREFIX);
- int flags = (iIdx==0 ? 0 : FTS5INDEX_QUERY_PREFIX);
- u64 ck1 = 0;
- u64 ck2 = 0;
-
- /* Check that the results returned for ASC and DESC queries are
- ** the same. If not, call this corruption. */
- rc = fts5QueryCksum(p, iIdx, zTerm, nTerm, flags, &ck1);
- if( rc==SQLITE_OK ){
- int f = flags|FTS5INDEX_QUERY_DESC;
- rc = fts5QueryCksum(p, iIdx, zTerm, nTerm, f, &ck2);
- }
- if( rc==SQLITE_OK && ck1!=ck2 ) rc = FTS5_CORRUPT;
-
- /* If this is a prefix query, check that the results returned if the
- ** the index is disabled are the same. In both ASC and DESC order.
- **
- ** This check may only be performed if the hash table is empty. This
- ** is because the hash table only supports a single scan query at
- ** a time, and the multi-iter loop from which this function is called
- ** is already performing such a scan. */
- if( p->nPendingData==0 ){
- if( iIdx>0 && rc==SQLITE_OK ){
- int f = flags|FTS5INDEX_QUERY_TEST_NOIDX;
- ck2 = 0;
- rc = fts5QueryCksum(p, iIdx, zTerm, nTerm, f, &ck2);
- if( rc==SQLITE_OK && ck1!=ck2 ) rc = FTS5_CORRUPT;
- }
- if( iIdx>0 && rc==SQLITE_OK ){
- int f = flags|FTS5INDEX_QUERY_TEST_NOIDX|FTS5INDEX_QUERY_DESC;
- ck2 = 0;
- rc = fts5QueryCksum(p, iIdx, zTerm, nTerm, f, &ck2);
- if( rc==SQLITE_OK && ck1!=ck2 ) rc = FTS5_CORRUPT;
- }
- }
-
- cksum3 ^= ck1;
- fts5BufferSet(&rc, pPrev, n, (const u8*)z);
-
- if( rc==SQLITE_OK && cksum3!=expected ){
- rc = FTS5_CORRUPT;
- }
- *pCksum = cksum3;
- }
- p->rc = rc;
-}
-
-#else
-# define fts5TestDlidxReverse(x,y,z)
-# define fts5TestTerm(u,v,w,x,y,z)
-#endif
-
-/*
-** Check that:
-**
-** 1) All leaves of pSeg between iFirst and iLast (inclusive) exist and
-** contain zero terms.
-** 2) All leaves of pSeg between iNoRowid and iLast (inclusive) exist and
-** contain zero rowids.
-*/
-static void fts5IndexIntegrityCheckEmpty(
- Fts5Index *p,
- Fts5StructureSegment *pSeg, /* Segment to check internal consistency */
- int iFirst,
- int iNoRowid,
- int iLast
-){
- int i;
-
- /* Now check that the iter.nEmpty leaves following the current leaf
- ** (a) exist and (b) contain no terms. */
- for(i=iFirst; p->rc==SQLITE_OK && i<=iLast; i++){
- Fts5Data *pLeaf = fts5DataRead(p, FTS5_SEGMENT_ROWID(pSeg->iSegid, i));
- if( pLeaf ){
- if( !fts5LeafIsTermless(pLeaf) ) p->rc = FTS5_CORRUPT;
- if( i>=iNoRowid && 0!=fts5LeafFirstRowidOff(pLeaf) ) p->rc = FTS5_CORRUPT;
- }
- fts5DataRelease(pLeaf);
- }
-}
-
-static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){
- int iTermOff = 0;
- int ii;
-
- Fts5Buffer buf1 = {0,0,0};
- Fts5Buffer buf2 = {0,0,0};
-
- ii = pLeaf->szLeaf;
- while( ii<pLeaf->nn && p->rc==SQLITE_OK ){
- int res;
- int iOff;
- int nIncr;
-
- ii += fts5GetVarint32(&pLeaf->p[ii], nIncr);
- iTermOff += nIncr;
- iOff = iTermOff;
-
- if( iOff>=pLeaf->szLeaf ){
- p->rc = FTS5_CORRUPT;
- }else if( iTermOff==nIncr ){
- int nByte;
- iOff += fts5GetVarint32(&pLeaf->p[iOff], nByte);
- if( (iOff+nByte)>pLeaf->szLeaf ){
- p->rc = FTS5_CORRUPT;
- }else{
- fts5BufferSet(&p->rc, &buf1, nByte, &pLeaf->p[iOff]);
- }
- }else{
- int nKeep, nByte;
- iOff += fts5GetVarint32(&pLeaf->p[iOff], nKeep);
- iOff += fts5GetVarint32(&pLeaf->p[iOff], nByte);
- if( nKeep>buf1.n || (iOff+nByte)>pLeaf->szLeaf ){
- p->rc = FTS5_CORRUPT;
- }else{
- buf1.n = nKeep;
- fts5BufferAppendBlob(&p->rc, &buf1, nByte, &pLeaf->p[iOff]);
- }
-
- if( p->rc==SQLITE_OK ){
- res = fts5BufferCompare(&buf1, &buf2);
- if( res<=0 ) p->rc = FTS5_CORRUPT;
- }
- }
- fts5BufferSet(&p->rc, &buf2, buf1.n, buf1.p);
- }
-
- fts5BufferFree(&buf1);
- fts5BufferFree(&buf2);
-}
-
-static void fts5IndexIntegrityCheckSegment(
- Fts5Index *p, /* FTS5 backend object */
- Fts5StructureSegment *pSeg /* Segment to check internal consistency */
-){
- Fts5Config *pConfig = p->pConfig;
- sqlite3_stmt *pStmt = 0;
- int rc2;
- int iIdxPrevLeaf = pSeg->pgnoFirst-1;
- int iDlidxPrevLeaf = pSeg->pgnoLast;
-
- if( pSeg->pgnoFirst==0 ) return;
-
- fts5IndexPrepareStmt(p, &pStmt, sqlite3_mprintf(
- "SELECT segid, term, (pgno>>1), (pgno&1) FROM %Q.'%q_idx' WHERE segid=%d",
- pConfig->zDb, pConfig->zName, pSeg->iSegid
- ));
-
- /* Iterate through the b-tree hierarchy. */
- while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
- i64 iRow; /* Rowid for this leaf */
- Fts5Data *pLeaf; /* Data for this leaf */
-
- int nIdxTerm = sqlite3_column_bytes(pStmt, 1);
- const char *zIdxTerm = (const char*)sqlite3_column_text(pStmt, 1);
- int iIdxLeaf = sqlite3_column_int(pStmt, 2);
- int bIdxDlidx = sqlite3_column_int(pStmt, 3);
-
- /* If the leaf in question has already been trimmed from the segment,
- ** ignore this b-tree entry. Otherwise, load it into memory. */
- if( iIdxLeaf<pSeg->pgnoFirst ) continue;
- iRow = FTS5_SEGMENT_ROWID(pSeg->iSegid, iIdxLeaf);
- pLeaf = fts5DataRead(p, iRow);
- if( pLeaf==0 ) break;
-
- /* Check that the leaf contains at least one term, and that it is equal
- ** to or larger than the split-key in zIdxTerm. Also check that if there
- ** is also a rowid pointer within the leaf page header, it points to a
- ** location before the term. */
- if( pLeaf->nn<=pLeaf->szLeaf ){
- p->rc = FTS5_CORRUPT;
- }else{
- int iOff; /* Offset of first term on leaf */
- int iRowidOff; /* Offset of first rowid on leaf */
- int nTerm; /* Size of term on leaf in bytes */
- int res; /* Comparison of term and split-key */
-
- iOff = fts5LeafFirstTermOff(pLeaf);
- iRowidOff = fts5LeafFirstRowidOff(pLeaf);
- if( iRowidOff>=iOff ){
- p->rc = FTS5_CORRUPT;
- }else{
- iOff += fts5GetVarint32(&pLeaf->p[iOff], nTerm);
- res = memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm));
- if( res==0 ) res = nTerm - nIdxTerm;
- if( res<0 ) p->rc = FTS5_CORRUPT;
- }
-
- fts5IntegrityCheckPgidx(p, pLeaf);
- }
- fts5DataRelease(pLeaf);
- if( p->rc ) break;
-
- /* Now check that the iter.nEmpty leaves following the current leaf
- ** (a) exist and (b) contain no terms. */
- fts5IndexIntegrityCheckEmpty(
- p, pSeg, iIdxPrevLeaf+1, iDlidxPrevLeaf+1, iIdxLeaf-1
- );
- if( p->rc ) break;
-
- /* If there is a doclist-index, check that it looks right. */
- if( bIdxDlidx ){
- Fts5DlidxIter *pDlidx = 0; /* For iterating through doclist index */
- int iPrevLeaf = iIdxLeaf;
- int iSegid = pSeg->iSegid;
- int iPg = 0;
- i64 iKey;
-
- for(pDlidx=fts5DlidxIterInit(p, 0, iSegid, iIdxLeaf);
- fts5DlidxIterEof(p, pDlidx)==0;
- fts5DlidxIterNext(p, pDlidx)
- ){
-
- /* Check any rowid-less pages that occur before the current leaf. */
- for(iPg=iPrevLeaf+1; iPg<fts5DlidxIterPgno(pDlidx); iPg++){
- iKey = FTS5_SEGMENT_ROWID(iSegid, iPg);
- pLeaf = fts5DataRead(p, iKey);
- if( pLeaf ){
- if( fts5LeafFirstRowidOff(pLeaf)!=0 ) p->rc = FTS5_CORRUPT;
- fts5DataRelease(pLeaf);
- }
- }
- iPrevLeaf = fts5DlidxIterPgno(pDlidx);
-
- /* Check that the leaf page indicated by the iterator really does
- ** contain the rowid suggested by the same. */
- iKey = FTS5_SEGMENT_ROWID(iSegid, iPrevLeaf);
- pLeaf = fts5DataRead(p, iKey);
- if( pLeaf ){
- i64 iRowid;
- int iRowidOff = fts5LeafFirstRowidOff(pLeaf);
- ASSERT_SZLEAF_OK(pLeaf);
- if( iRowidOff>=pLeaf->szLeaf ){
- p->rc = FTS5_CORRUPT;
- }else{
- fts5GetVarint(&pLeaf->p[iRowidOff], (u64*)&iRowid);
- if( iRowid!=fts5DlidxIterRowid(pDlidx) ) p->rc = FTS5_CORRUPT;
- }
- fts5DataRelease(pLeaf);
- }
- }
-
- iDlidxPrevLeaf = iPg;
- fts5DlidxIterFree(pDlidx);
- fts5TestDlidxReverse(p, iSegid, iIdxLeaf);
- }else{
- iDlidxPrevLeaf = pSeg->pgnoLast;
- /* TODO: Check there is no doclist index */
- }
-
- iIdxPrevLeaf = iIdxLeaf;
- }
-
- rc2 = sqlite3_finalize(pStmt);
- if( p->rc==SQLITE_OK ) p->rc = rc2;
-
- /* Page iter.iLeaf must now be the rightmost leaf-page in the segment */
-#if 0
- if( p->rc==SQLITE_OK && iter.iLeaf!=pSeg->pgnoLast ){
- p->rc = FTS5_CORRUPT;
- }
-#endif
-}
-
-
-/*
-** Run internal checks to ensure that the FTS index (a) is internally
-** consistent and (b) contains entries for which the XOR of the checksums
-** as calculated by sqlite3Fts5IndexEntryCksum() is cksum.
-**
-** Return SQLITE_CORRUPT if any of the internal checks fail, or if the
-** checksum does not match. Return SQLITE_OK if all checks pass without
-** error, or some other SQLite error code if another error (e.g. OOM)
-** occurs.
-*/
-static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
- int eDetail = p->pConfig->eDetail;
- u64 cksum2 = 0; /* Checksum based on contents of indexes */
- Fts5Buffer poslist = {0,0,0}; /* Buffer used to hold a poslist */
- Fts5Iter *pIter; /* Used to iterate through entire index */
- Fts5Structure *pStruct; /* Index structure */
-
-#ifdef SQLITE_DEBUG
- /* Used by extra internal tests only run if NDEBUG is not defined */
- u64 cksum3 = 0; /* Checksum based on contents of indexes */
- Fts5Buffer term = {0,0,0}; /* Buffer used to hold most recent term */
-#endif
- const int flags = FTS5INDEX_QUERY_NOOUTPUT;
-
- /* Load the FTS index structure */
- pStruct = fts5StructureRead(p);
-
- /* Check that the internal nodes of each segment match the leaves */
- if( pStruct ){
- int iLvl, iSeg;
- for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
- for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
- Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg];
- fts5IndexIntegrityCheckSegment(p, pSeg);
- }
- }
- }
-
- /* The cksum argument passed to this function is a checksum calculated
- ** based on all expected entries in the FTS index (including prefix index
- ** entries). This block checks that a checksum calculated based on the
- ** actual contents of FTS index is identical.
- **
- ** Two versions of the same checksum are calculated. The first (stack
- ** variable cksum2) based on entries extracted from the full-text index
- ** while doing a linear scan of each individual index in turn.
- **
- ** As each term visited by the linear scans, a separate query for the
- ** same term is performed. cksum3 is calculated based on the entries
- ** extracted by these queries.
- */
- for(fts5MultiIterNew(p, pStruct, flags, 0, 0, 0, -1, 0, &pIter);
- fts5MultiIterEof(p, pIter)==0;
- fts5MultiIterNext(p, pIter, 0, 0)
- ){
- int n; /* Size of term in bytes */
- i64 iPos = 0; /* Position read from poslist */
- int iOff = 0; /* Offset within poslist */
- i64 iRowid = fts5MultiIterRowid(pIter);
- char *z = (char*)fts5MultiIterTerm(pIter, &n);
-
- /* If this is a new term, query for it. Update cksum3 with the results. */
- fts5TestTerm(p, &term, z, n, cksum2, &cksum3);
-
- if( eDetail==FTS5_DETAIL_NONE ){
- if( 0==fts5MultiIterIsEmpty(p, pIter) ){
- cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, 0, 0, -1, z, n);
- }
- }else{
- poslist.n = 0;
- fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst], 0, &poslist);
- while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){
- int iCol = FTS5_POS2COLUMN(iPos);
- int iTokOff = FTS5_POS2OFFSET(iPos);
- cksum2 ^= sqlite3Fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n);
- }
- }
- }
- fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3);
-
- fts5MultiIterFree(pIter);
- if( p->rc==SQLITE_OK && cksum!=cksum2 ) p->rc = FTS5_CORRUPT;
-
- fts5StructureRelease(pStruct);
-#ifdef SQLITE_DEBUG
- fts5BufferFree(&term);
-#endif
- fts5BufferFree(&poslist);
- return fts5IndexReturn(p);
-}
-
-/*************************************************************************
-**************************************************************************
-** Below this point is the implementation of the fts5_decode() scalar
-** function only.
-*/
-
-/*
-** Decode a segment-data rowid from the %_data table. This function is
-** the opposite of macro FTS5_SEGMENT_ROWID().
-*/
-static void fts5DecodeRowid(
- i64 iRowid, /* Rowid from %_data table */
- int *piSegid, /* OUT: Segment id */
- int *pbDlidx, /* OUT: Dlidx flag */
- int *piHeight, /* OUT: Height */
- int *piPgno /* OUT: Page number */
-){
- *piPgno = (int)(iRowid & (((i64)1 << FTS5_DATA_PAGE_B) - 1));
- iRowid >>= FTS5_DATA_PAGE_B;
-
- *piHeight = (int)(iRowid & (((i64)1 << FTS5_DATA_HEIGHT_B) - 1));
- iRowid >>= FTS5_DATA_HEIGHT_B;
-
- *pbDlidx = (int)(iRowid & 0x0001);
- iRowid >>= FTS5_DATA_DLI_B;
-
- *piSegid = (int)(iRowid & (((i64)1 << FTS5_DATA_ID_B) - 1));
-}
-
-static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){
- int iSegid, iHeight, iPgno, bDlidx; /* Rowid compenents */
- fts5DecodeRowid(iKey, &iSegid, &bDlidx, &iHeight, &iPgno);
-
- if( iSegid==0 ){
- if( iKey==FTS5_AVERAGES_ROWID ){
- sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{averages} ");
- }else{
- sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{structure}");
- }
- }
- else{
- sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{%ssegid=%d h=%d pgno=%d}",
- bDlidx ? "dlidx " : "", iSegid, iHeight, iPgno
- );
- }
-}
-
-static void fts5DebugStructure(
- int *pRc, /* IN/OUT: error code */
- Fts5Buffer *pBuf,
- Fts5Structure *p
-){
- int iLvl, iSeg; /* Iterate through levels, segments */
-
- for(iLvl=0; iLvl<p->nLevel; iLvl++){
- Fts5StructureLevel *pLvl = &p->aLevel[iLvl];
- sqlite3Fts5BufferAppendPrintf(pRc, pBuf,
- " {lvl=%d nMerge=%d nSeg=%d", iLvl, pLvl->nMerge, pLvl->nSeg
- );
- for(iSeg=0; iSeg<pLvl->nSeg; iSeg++){
- Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
- sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d}",
- pSeg->iSegid, pSeg->pgnoFirst, pSeg->pgnoLast
- );
- }
- sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "}");
- }
-}
-
-/*
-** This is part of the fts5_decode() debugging aid.
-**
-** Arguments pBlob/nBlob contain a serialized Fts5Structure object. This
-** function appends a human-readable representation of the same object
-** to the buffer passed as the second argument.
-*/
-static void fts5DecodeStructure(
- int *pRc, /* IN/OUT: error code */
- Fts5Buffer *pBuf,
- const u8 *pBlob, int nBlob
-){
- int rc; /* Return code */
- Fts5Structure *p = 0; /* Decoded structure object */
-
- rc = fts5StructureDecode(pBlob, nBlob, 0, &p);
- if( rc!=SQLITE_OK ){
- *pRc = rc;
- return;
- }
-
- fts5DebugStructure(pRc, pBuf, p);
- fts5StructureRelease(p);
-}
-
-/*
-** This is part of the fts5_decode() debugging aid.
-**
-** Arguments pBlob/nBlob contain an "averages" record. This function
-** appends a human-readable representation of record to the buffer passed
-** as the second argument.
-*/
-static void fts5DecodeAverages(
- int *pRc, /* IN/OUT: error code */
- Fts5Buffer *pBuf,
- const u8 *pBlob, int nBlob
-){
- int i = 0;
- const char *zSpace = "";
-
- while( i<nBlob ){
- u64 iVal;
- i += sqlite3Fts5GetVarint(&pBlob[i], &iVal);
- sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "%s%d", zSpace, (int)iVal);
- zSpace = " ";
- }
-}
-
-/*
-** Buffer (a/n) is assumed to contain a list of serialized varints. Read
-** each varint and append its string representation to buffer pBuf. Return
-** after either the input buffer is exhausted or a 0 value is read.
-**
-** The return value is the number of bytes read from the input buffer.
-*/
-static int fts5DecodePoslist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){
- int iOff = 0;
- while( iOff<n ){
- int iVal;
- iOff += fts5GetVarint32(&a[iOff], iVal);
- sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %d", iVal);
- }
- return iOff;
-}
-
-/*
-** The start of buffer (a/n) contains the start of a doclist. The doclist
-** may or may not finish within the buffer. This function appends a text
-** representation of the part of the doclist that is present to buffer
-** pBuf.
-**
-** The return value is the number of bytes read from the input buffer.
-*/
-static int fts5DecodeDoclist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){
- i64 iDocid = 0;
- int iOff = 0;
-
- if( n>0 ){
- iOff = sqlite3Fts5GetVarint(a, (u64*)&iDocid);
- sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " id=%lld", iDocid);
- }
- while( iOff<n ){
- int nPos;
- int bDel;
- iOff += fts5GetPoslistSize(&a[iOff], &nPos, &bDel);
- sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " nPos=%d%s", nPos, bDel?"*":"");
- iOff += fts5DecodePoslist(pRc, pBuf, &a[iOff], MIN(n-iOff, nPos));
- if( iOff<n ){
- i64 iDelta;
- iOff += sqlite3Fts5GetVarint(&a[iOff], (u64*)&iDelta);
- iDocid += iDelta;
- sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " id=%lld", iDocid);
- }
- }
-
- return iOff;
-}
-
-/*
-** This function is part of the fts5_decode() debugging function. It is
-** only ever used with detail=none tables.
-**
-** Buffer (pData/nData) contains a doclist in the format used by detail=none
-** tables. This function appends a human-readable version of that list to
-** buffer pBuf.
-**
-** If *pRc is other than SQLITE_OK when this function is called, it is a
-** no-op. If an OOM or other error occurs within this function, *pRc is
-** set to an SQLite error code before returning. The final state of buffer
-** pBuf is undefined in this case.
-*/
-static void fts5DecodeRowidList(
- int *pRc, /* IN/OUT: Error code */
- Fts5Buffer *pBuf, /* Buffer to append text to */
- const u8 *pData, int nData /* Data to decode list-of-rowids from */
-){
- int i = 0;
- i64 iRowid = 0;
-
- while( i<nData ){
- const char *zApp = "";
- u64 iVal;
- i += sqlite3Fts5GetVarint(&pData[i], &iVal);
- iRowid += iVal;
-
- if( i<nData && pData[i]==0x00 ){
- i++;
- if( i<nData && pData[i]==0x00 ){
- i++;
- zApp = "+";
- }else{
- zApp = "*";
- }
- }
-
- sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %lld%s", iRowid, zApp);
- }
-}
-
-/*
-** The implementation of user-defined scalar function fts5_decode().
-*/
-static void fts5DecodeFunction(
- sqlite3_context *pCtx, /* Function call context */
- int nArg, /* Number of args (always 2) */
- sqlite3_value **apVal /* Function arguments */
-){
- i64 iRowid; /* Rowid for record being decoded */
- int iSegid,iHeight,iPgno,bDlidx;/* Rowid components */
- const u8 *aBlob; int n; /* Record to decode */
- u8 *a = 0;
- Fts5Buffer s; /* Build up text to return here */
- int rc = SQLITE_OK; /* Return code */
- int nSpace = 0;
- int eDetailNone = (sqlite3_user_data(pCtx)!=0);
-
- assert( nArg==2 );
- UNUSED_PARAM(nArg);
- memset(&s, 0, sizeof(Fts5Buffer));
- iRowid = sqlite3_value_int64(apVal[0]);
-
- /* Make a copy of the second argument (a blob) in aBlob[]. The aBlob[]
- ** copy is followed by FTS5_DATA_ZERO_PADDING 0x00 bytes, which prevents
- ** buffer overreads even if the record is corrupt. */
- n = sqlite3_value_bytes(apVal[1]);
- aBlob = sqlite3_value_blob(apVal[1]);
- nSpace = n + FTS5_DATA_ZERO_PADDING;
- a = (u8*)sqlite3Fts5MallocZero(&rc, nSpace);
- if( a==0 ) goto decode_out;
- memcpy(a, aBlob, n);
-
-
- fts5DecodeRowid(iRowid, &iSegid, &bDlidx, &iHeight, &iPgno);
-
- fts5DebugRowid(&rc, &s, iRowid);
- if( bDlidx ){
- Fts5Data dlidx;
- Fts5DlidxLvl lvl;
-
- dlidx.p = a;
- dlidx.nn = n;
-
- memset(&lvl, 0, sizeof(Fts5DlidxLvl));
- lvl.pData = &dlidx;
- lvl.iLeafPgno = iPgno;
-
- for(fts5DlidxLvlNext(&lvl); lvl.bEof==0; fts5DlidxLvlNext(&lvl)){
- sqlite3Fts5BufferAppendPrintf(&rc, &s,
- " %d(%lld)", lvl.iLeafPgno, lvl.iRowid
- );
- }
- }else if( iSegid==0 ){
- if( iRowid==FTS5_AVERAGES_ROWID ){
- fts5DecodeAverages(&rc, &s, a, n);
- }else{
- fts5DecodeStructure(&rc, &s, a, n);
- }
- }else if( eDetailNone ){
- Fts5Buffer term; /* Current term read from page */
- int szLeaf;
- int iPgidxOff = szLeaf = fts5GetU16(&a[2]);
- int iTermOff;
- int nKeep = 0;
- int iOff;
-
- memset(&term, 0, sizeof(Fts5Buffer));
-
- /* Decode any entries that occur before the first term. */
- if( szLeaf<n ){
- iPgidxOff += fts5GetVarint32(&a[iPgidxOff], iTermOff);
- }else{
- iTermOff = szLeaf;
- }
- fts5DecodeRowidList(&rc, &s, &a[4], iTermOff-4);
-
- iOff = iTermOff;
- while( iOff<szLeaf ){
- int nAppend;
-
- /* Read the term data for the next term*/
- iOff += fts5GetVarint32(&a[iOff], nAppend);
- term.n = nKeep;
- fts5BufferAppendBlob(&rc, &term, nAppend, &a[iOff]);
- sqlite3Fts5BufferAppendPrintf(
- &rc, &s, " term=%.*s", term.n, (const char*)term.p
- );
- iOff += nAppend;
-
- /* Figure out where the doclist for this term ends */
- if( iPgidxOff<n ){
- int nIncr;
- iPgidxOff += fts5GetVarint32(&a[iPgidxOff], nIncr);
- iTermOff += nIncr;
- }else{
- iTermOff = szLeaf;
- }
-
- fts5DecodeRowidList(&rc, &s, &a[iOff], iTermOff-iOff);
- iOff = iTermOff;
- if( iOff<szLeaf ){
- iOff += fts5GetVarint32(&a[iOff], nKeep);
- }
- }
-
- fts5BufferFree(&term);
- }else{
- Fts5Buffer term; /* Current term read from page */
- int szLeaf; /* Offset of pgidx in a[] */
- int iPgidxOff;
- int iPgidxPrev = 0; /* Previous value read from pgidx */
- int iTermOff = 0;
- int iRowidOff = 0;
- int iOff;
- int nDoclist;
-
- memset(&term, 0, sizeof(Fts5Buffer));
-
- if( n<4 ){
- sqlite3Fts5BufferSet(&rc, &s, 7, (const u8*)"corrupt");
- goto decode_out;
- }else{
- iRowidOff = fts5GetU16(&a[0]);
- iPgidxOff = szLeaf = fts5GetU16(&a[2]);
- if( iPgidxOff<n ){
- fts5GetVarint32(&a[iPgidxOff], iTermOff);
- }
- }
-
- /* Decode the position list tail at the start of the page */
- if( iRowidOff!=0 ){
- iOff = iRowidOff;
- }else if( iTermOff!=0 ){
- iOff = iTermOff;
- }else{
- iOff = szLeaf;
- }
- fts5DecodePoslist(&rc, &s, &a[4], iOff-4);
-
- /* Decode any more doclist data that appears on the page before the
- ** first term. */
- nDoclist = (iTermOff ? iTermOff : szLeaf) - iOff;
- fts5DecodeDoclist(&rc, &s, &a[iOff], nDoclist);
-
- while( iPgidxOff<n ){
- int bFirst = (iPgidxOff==szLeaf); /* True for first term on page */
- int nByte; /* Bytes of data */
- int iEnd;
-
- iPgidxOff += fts5GetVarint32(&a[iPgidxOff], nByte);
- iPgidxPrev += nByte;
- iOff = iPgidxPrev;
-
- if( iPgidxOff<n ){
- fts5GetVarint32(&a[iPgidxOff], nByte);
- iEnd = iPgidxPrev + nByte;
- }else{
- iEnd = szLeaf;
- }
-
- if( bFirst==0 ){
- iOff += fts5GetVarint32(&a[iOff], nByte);
- term.n = nByte;
- }
- iOff += fts5GetVarint32(&a[iOff], nByte);
- fts5BufferAppendBlob(&rc, &term, nByte, &a[iOff]);
- iOff += nByte;
-
- sqlite3Fts5BufferAppendPrintf(
- &rc, &s, " term=%.*s", term.n, (const char*)term.p
- );
- iOff += fts5DecodeDoclist(&rc, &s, &a[iOff], iEnd-iOff);
- }
-
- fts5BufferFree(&term);
- }
-
- decode_out:
- sqlite3_free(a);
- if( rc==SQLITE_OK ){
- sqlite3_result_text(pCtx, (const char*)s.p, s.n, SQLITE_TRANSIENT);
- }else{
- sqlite3_result_error_code(pCtx, rc);
- }
- fts5BufferFree(&s);
-}
-
-/*
-** The implementation of user-defined scalar function fts5_rowid().
-*/
-static void fts5RowidFunction(
- sqlite3_context *pCtx, /* Function call context */
- int nArg, /* Number of args (always 2) */
- sqlite3_value **apVal /* Function arguments */
-){
- const char *zArg;
- if( nArg==0 ){
- sqlite3_result_error(pCtx, "should be: fts5_rowid(subject, ....)", -1);
- }else{
- zArg = (const char*)sqlite3_value_text(apVal[0]);
- if( 0==sqlite3_stricmp(zArg, "segment") ){
- i64 iRowid;
- int segid, pgno;
- if( nArg!=3 ){
- sqlite3_result_error(pCtx,
- "should be: fts5_rowid('segment', segid, pgno))", -1
- );
- }else{
- segid = sqlite3_value_int(apVal[1]);
- pgno = sqlite3_value_int(apVal[2]);
- iRowid = FTS5_SEGMENT_ROWID(segid, pgno);
- sqlite3_result_int64(pCtx, iRowid);
- }
- }else{
- sqlite3_result_error(pCtx,
- "first arg to fts5_rowid() must be 'segment'" , -1
- );
- }
- }
-}
-
-/*
-** This is called as part of registering the FTS5 module with database
-** connection db. It registers several user-defined scalar functions useful
-** with FTS5.
-**
-** If successful, SQLITE_OK is returned. If an error occurs, some other
-** SQLite error code is returned instead.
-*/
-static int sqlite3Fts5IndexInit(sqlite3 *db){
- int rc = sqlite3_create_function(
- db, "fts5_decode", 2, SQLITE_UTF8, 0, fts5DecodeFunction, 0, 0
- );
-
- if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(
- db, "fts5_decode_none", 2,
- SQLITE_UTF8, (void*)db, fts5DecodeFunction, 0, 0
- );
- }
-
- if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(
- db, "fts5_rowid", -1, SQLITE_UTF8, 0, fts5RowidFunction, 0, 0
- );
- }
- return rc;
-}
-
-
-static int sqlite3Fts5IndexReset(Fts5Index *p){
- assert( p->pStruct==0 || p->iStructVersion!=0 );
- if( fts5IndexDataVersion(p)!=p->iStructVersion ){
- fts5StructureInvalidate(p);
- }
- return fts5IndexReturn(p);
-}
-
-/*
-** 2014 Jun 09
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This is an SQLite module implementing full-text search.
-*/
-
-
-/* #include "fts5Int.h" */
-
-/*
-** This variable is set to false when running tests for which the on disk
-** structures should not be corrupt. Otherwise, true. If it is false, extra
-** assert() conditions in the fts5 code are activated - conditions that are
-** only true if it is guaranteed that the fts5 database is not corrupt.
-*/
-SQLITE_API int sqlite3_fts5_may_be_corrupt = 1;
-
-
-typedef struct Fts5Auxdata Fts5Auxdata;
-typedef struct Fts5Auxiliary Fts5Auxiliary;
-typedef struct Fts5Cursor Fts5Cursor;
-typedef struct Fts5Sorter Fts5Sorter;
-typedef struct Fts5Table Fts5Table;
-typedef struct Fts5TokenizerModule Fts5TokenizerModule;
-
-/*
-** NOTES ON TRANSACTIONS:
-**
-** SQLite invokes the following virtual table methods as transactions are
-** opened and closed by the user:
-**
-** xBegin(): Start of a new transaction.
-** xSync(): Initial part of two-phase commit.
-** xCommit(): Final part of two-phase commit.
-** xRollback(): Rollback the transaction.
-**
-** Anything that is required as part of a commit that may fail is performed
-** in the xSync() callback. Current versions of SQLite ignore any errors
-** returned by xCommit().
-**
-** And as sub-transactions are opened/closed:
-**
-** xSavepoint(int S): Open savepoint S.
-** xRelease(int S): Commit and close savepoint S.
-** xRollbackTo(int S): Rollback to start of savepoint S.
-**
-** During a write-transaction the fts5_index.c module may cache some data
-** in-memory. It is flushed to disk whenever xSync(), xRelease() or
-** xSavepoint() is called. And discarded whenever xRollback() or xRollbackTo()
-** is called.
-**
-** Additionally, if SQLITE_DEBUG is defined, an instance of the following
-** structure is used to record the current transaction state. This information
-** is not required, but it is used in the assert() statements executed by
-** function fts5CheckTransactionState() (see below).
-*/
-struct Fts5TransactionState {
- int eState; /* 0==closed, 1==open, 2==synced */
- int iSavepoint; /* Number of open savepoints (0 -> none) */
-};
-
-/*
-** A single object of this type is allocated when the FTS5 module is
-** registered with a database handle. It is used to store pointers to
-** all registered FTS5 extensions - tokenizers and auxiliary functions.
-*/
-struct Fts5Global {
- fts5_api api; /* User visible part of object (see fts5.h) */
- sqlite3 *db; /* Associated database connection */
- i64 iNextId; /* Used to allocate unique cursor ids */
- Fts5Auxiliary *pAux; /* First in list of all aux. functions */
- Fts5TokenizerModule *pTok; /* First in list of all tokenizer modules */
- Fts5TokenizerModule *pDfltTok; /* Default tokenizer module */
- Fts5Cursor *pCsr; /* First in list of all open cursors */
-};
-
-/*
-** Each auxiliary function registered with the FTS5 module is represented
-** by an object of the following type. All such objects are stored as part
-** of the Fts5Global.pAux list.
-*/
-struct Fts5Auxiliary {
- Fts5Global *pGlobal; /* Global context for this function */
- char *zFunc; /* Function name (nul-terminated) */
- void *pUserData; /* User-data pointer */
- fts5_extension_function xFunc; /* Callback function */
- void (*xDestroy)(void*); /* Destructor function */
- Fts5Auxiliary *pNext; /* Next registered auxiliary function */
-};
-
-/*
-** Each tokenizer module registered with the FTS5 module is represented
-** by an object of the following type. All such objects are stored as part
-** of the Fts5Global.pTok list.
-*/
-struct Fts5TokenizerModule {
- char *zName; /* Name of tokenizer */
- void *pUserData; /* User pointer passed to xCreate() */
- fts5_tokenizer x; /* Tokenizer functions */
- void (*xDestroy)(void*); /* Destructor function */
- Fts5TokenizerModule *pNext; /* Next registered tokenizer module */
-};
-
-/*
-** Virtual-table object.
-*/
-struct Fts5Table {
- sqlite3_vtab base; /* Base class used by SQLite core */
- Fts5Config *pConfig; /* Virtual table configuration */
- Fts5Index *pIndex; /* Full-text index */
- Fts5Storage *pStorage; /* Document store */
- Fts5Global *pGlobal; /* Global (connection wide) data */
- Fts5Cursor *pSortCsr; /* Sort data from this cursor */
-#ifdef SQLITE_DEBUG
- struct Fts5TransactionState ts;
-#endif
-};
-
-struct Fts5MatchPhrase {
- Fts5Buffer *pPoslist; /* Pointer to current poslist */
- int nTerm; /* Size of phrase in terms */
-};
-
-/*
-** pStmt:
-** SELECT rowid, <fts> FROM <fts> ORDER BY +rank;
-**
-** aIdx[]:
-** There is one entry in the aIdx[] array for each phrase in the query,
-** the value of which is the offset within aPoslist[] following the last
-** byte of the position list for the corresponding phrase.
-*/
-struct Fts5Sorter {
- sqlite3_stmt *pStmt;
- i64 iRowid; /* Current rowid */
- const u8 *aPoslist; /* Position lists for current row */
- int nIdx; /* Number of entries in aIdx[] */
- int aIdx[1]; /* Offsets into aPoslist for current row */
-};
-
-
-/*
-** Virtual-table cursor object.
-**
-** iSpecial:
-** If this is a 'special' query (refer to function fts5SpecialMatch()),
-** then this variable contains the result of the query.
-**
-** iFirstRowid, iLastRowid:
-** These variables are only used for FTS5_PLAN_MATCH cursors. Assuming the
-** cursor iterates in ascending order of rowids, iFirstRowid is the lower
-** limit of rowids to return, and iLastRowid the upper. In other words, the
-** WHERE clause in the user's query might have been:
-**
-** <tbl> MATCH <expr> AND rowid BETWEEN $iFirstRowid AND $iLastRowid
-**
-** If the cursor iterates in descending order of rowid, iFirstRowid
-** is the upper limit (i.e. the "first" rowid visited) and iLastRowid
-** the lower.
-*/
-struct Fts5Cursor {
- sqlite3_vtab_cursor base; /* Base class used by SQLite core */
- Fts5Cursor *pNext; /* Next cursor in Fts5Cursor.pCsr list */
- int *aColumnSize; /* Values for xColumnSize() */
- i64 iCsrId; /* Cursor id */
-
- /* Zero from this point onwards on cursor reset */
- int ePlan; /* FTS5_PLAN_XXX value */
- int bDesc; /* True for "ORDER BY rowid DESC" queries */
- i64 iFirstRowid; /* Return no rowids earlier than this */
- i64 iLastRowid; /* Return no rowids later than this */
- sqlite3_stmt *pStmt; /* Statement used to read %_content */
- Fts5Expr *pExpr; /* Expression for MATCH queries */
- Fts5Sorter *pSorter; /* Sorter for "ORDER BY rank" queries */
- int csrflags; /* Mask of cursor flags (see below) */
- i64 iSpecial; /* Result of special query */
-
- /* "rank" function. Populated on demand from vtab.xColumn(). */
- char *zRank; /* Custom rank function */
- char *zRankArgs; /* Custom rank function args */
- Fts5Auxiliary *pRank; /* Rank callback (or NULL) */
- int nRankArg; /* Number of trailing arguments for rank() */
- sqlite3_value **apRankArg; /* Array of trailing arguments */
- sqlite3_stmt *pRankArgStmt; /* Origin of objects in apRankArg[] */
-
- /* Auxiliary data storage */
- Fts5Auxiliary *pAux; /* Currently executing extension function */
- Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */
-
- /* Cache used by auxiliary functions xInst() and xInstCount() */
- Fts5PoslistReader *aInstIter; /* One for each phrase */
- int nInstAlloc; /* Size of aInst[] array (entries / 3) */
- int nInstCount; /* Number of phrase instances */
- int *aInst; /* 3 integers per phrase instance */
-};
-
-/*
-** Bits that make up the "idxNum" parameter passed indirectly by
-** xBestIndex() to xFilter().
-*/
-#define FTS5_BI_MATCH 0x0001 /* <tbl> MATCH ? */
-#define FTS5_BI_RANK 0x0002 /* rank MATCH ? */
-#define FTS5_BI_ROWID_EQ 0x0004 /* rowid == ? */
-#define FTS5_BI_ROWID_LE 0x0008 /* rowid <= ? */
-#define FTS5_BI_ROWID_GE 0x0010 /* rowid >= ? */
-
-#define FTS5_BI_ORDER_RANK 0x0020
-#define FTS5_BI_ORDER_ROWID 0x0040
-#define FTS5_BI_ORDER_DESC 0x0080
-
-/*
-** Values for Fts5Cursor.csrflags
-*/
-#define FTS5CSR_EOF 0x01
-#define FTS5CSR_REQUIRE_CONTENT 0x02
-#define FTS5CSR_REQUIRE_DOCSIZE 0x04
-#define FTS5CSR_REQUIRE_INST 0x08
-#define FTS5CSR_FREE_ZRANK 0x10
-#define FTS5CSR_REQUIRE_RESEEK 0x20
-#define FTS5CSR_REQUIRE_POSLIST 0x40
-
-#define BitFlagAllTest(x,y) (((x) & (y))==(y))
-#define BitFlagTest(x,y) (((x) & (y))!=0)
-
-
-/*
-** Macros to Set(), Clear() and Test() cursor flags.
-*/
-#define CsrFlagSet(pCsr, flag) ((pCsr)->csrflags |= (flag))
-#define CsrFlagClear(pCsr, flag) ((pCsr)->csrflags &= ~(flag))
-#define CsrFlagTest(pCsr, flag) ((pCsr)->csrflags & (flag))
-
-struct Fts5Auxdata {
- Fts5Auxiliary *pAux; /* Extension to which this belongs */
- void *pPtr; /* Pointer value */
- void(*xDelete)(void*); /* Destructor */
- Fts5Auxdata *pNext; /* Next object in linked list */
-};
-
-#ifdef SQLITE_DEBUG
-#define FTS5_BEGIN 1
-#define FTS5_SYNC 2
-#define FTS5_COMMIT 3
-#define FTS5_ROLLBACK 4
-#define FTS5_SAVEPOINT 5
-#define FTS5_RELEASE 6
-#define FTS5_ROLLBACKTO 7
-static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){
- switch( op ){
- case FTS5_BEGIN:
- assert( p->ts.eState==0 );
- p->ts.eState = 1;
- p->ts.iSavepoint = -1;
- break;
-
- case FTS5_SYNC:
- assert( p->ts.eState==1 );
- p->ts.eState = 2;
- break;
-
- case FTS5_COMMIT:
- assert( p->ts.eState==2 );
- p->ts.eState = 0;
- break;
-
- case FTS5_ROLLBACK:
- assert( p->ts.eState==1 || p->ts.eState==2 || p->ts.eState==0 );
- p->ts.eState = 0;
- break;
-
- case FTS5_SAVEPOINT:
- assert( p->ts.eState==1 );
- assert( iSavepoint>=0 );
- assert( iSavepoint>p->ts.iSavepoint );
- p->ts.iSavepoint = iSavepoint;
- break;
-
- case FTS5_RELEASE:
- assert( p->ts.eState==1 );
- assert( iSavepoint>=0 );
- assert( iSavepoint<=p->ts.iSavepoint );
- p->ts.iSavepoint = iSavepoint-1;
- break;
-
- case FTS5_ROLLBACKTO:
- assert( p->ts.eState==1 );
- assert( iSavepoint>=0 );
- assert( iSavepoint<=p->ts.iSavepoint );
- p->ts.iSavepoint = iSavepoint;
- break;
- }
-}
-#else
-# define fts5CheckTransactionState(x,y,z)
-#endif
-
-/*
-** Return true if pTab is a contentless table.
-*/
-static int fts5IsContentless(Fts5Table *pTab){
- return pTab->pConfig->eContent==FTS5_CONTENT_NONE;
-}
-
-/*
-** Delete a virtual table handle allocated by fts5InitVtab().
-*/
-static void fts5FreeVtab(Fts5Table *pTab){
- if( pTab ){
- sqlite3Fts5IndexClose(pTab->pIndex);
- sqlite3Fts5StorageClose(pTab->pStorage);
- sqlite3Fts5ConfigFree(pTab->pConfig);
- sqlite3_free(pTab);
- }
-}
-
-/*
-** The xDisconnect() virtual table method.
-*/
-static int fts5DisconnectMethod(sqlite3_vtab *pVtab){
- fts5FreeVtab((Fts5Table*)pVtab);
- return SQLITE_OK;
-}
-
-/*
-** The xDestroy() virtual table method.
-*/
-static int fts5DestroyMethod(sqlite3_vtab *pVtab){
- Fts5Table *pTab = (Fts5Table*)pVtab;
- int rc = sqlite3Fts5DropAll(pTab->pConfig);
- if( rc==SQLITE_OK ){
- fts5FreeVtab((Fts5Table*)pVtab);
- }
- return rc;
-}
-
-/*
-** This function is the implementation of both the xConnect and xCreate
-** methods of the FTS3 virtual table.
-**
-** The argv[] array contains the following:
-**
-** argv[0] -> module name ("fts5")
-** argv[1] -> database name
-** argv[2] -> table name
-** argv[...] -> "column name" and other module argument fields.
-*/
-static int fts5InitVtab(
- int bCreate, /* True for xCreate, false for xConnect */
- sqlite3 *db, /* The SQLite database connection */
- void *pAux, /* Hash table containing tokenizers */
- int argc, /* Number of elements in argv array */
- const char * const *argv, /* xCreate/xConnect argument array */
- sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */
- char **pzErr /* Write any error message here */
-){
- Fts5Global *pGlobal = (Fts5Global*)pAux;
- const char **azConfig = (const char**)argv;
- int rc = SQLITE_OK; /* Return code */
- Fts5Config *pConfig = 0; /* Results of parsing argc/argv */
- Fts5Table *pTab = 0; /* New virtual table object */
-
- /* Allocate the new vtab object and parse the configuration */
- pTab = (Fts5Table*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Table));
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5ConfigParse(pGlobal, db, argc, azConfig, &pConfig, pzErr);
- assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 );
- }
- if( rc==SQLITE_OK ){
- pTab->pConfig = pConfig;
- pTab->pGlobal = pGlobal;
- }
-
- /* Open the index sub-system */
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5IndexOpen(pConfig, bCreate, &pTab->pIndex, pzErr);
- }
-
- /* Open the storage sub-system */
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5StorageOpen(
- pConfig, pTab->pIndex, bCreate, &pTab->pStorage, pzErr
- );
- }
-
- /* Call sqlite3_declare_vtab() */
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5ConfigDeclareVtab(pConfig);
- }
-
- /* Load the initial configuration */
- if( rc==SQLITE_OK ){
- assert( pConfig->pzErrmsg==0 );
- pConfig->pzErrmsg = pzErr;
- rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex);
- sqlite3Fts5IndexRollback(pTab->pIndex);
- pConfig->pzErrmsg = 0;
- }
-
- if( rc!=SQLITE_OK ){
- fts5FreeVtab(pTab);
- pTab = 0;
- }else if( bCreate ){
- fts5CheckTransactionState(pTab, FTS5_BEGIN, 0);
- }
- *ppVTab = (sqlite3_vtab*)pTab;
- return rc;
-}
-
-/*
-** The xConnect() and xCreate() methods for the virtual table. All the
-** work is done in function fts5InitVtab().
-*/
-static int fts5ConnectMethod(
- sqlite3 *db, /* Database connection */
- void *pAux, /* Pointer to tokenizer hash table */
- int argc, /* Number of elements in argv array */
- const char * const *argv, /* xCreate/xConnect argument array */
- sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
- char **pzErr /* OUT: sqlite3_malloc'd error message */
-){
- return fts5InitVtab(0, db, pAux, argc, argv, ppVtab, pzErr);
-}
-static int fts5CreateMethod(
- sqlite3 *db, /* Database connection */
- void *pAux, /* Pointer to tokenizer hash table */
- int argc, /* Number of elements in argv array */
- const char * const *argv, /* xCreate/xConnect argument array */
- sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
- char **pzErr /* OUT: sqlite3_malloc'd error message */
-){
- return fts5InitVtab(1, db, pAux, argc, argv, ppVtab, pzErr);
-}
-
-/*
-** The different query plans.
-*/
-#define FTS5_PLAN_MATCH 1 /* (<tbl> MATCH ?) */
-#define FTS5_PLAN_SOURCE 2 /* A source cursor for SORTED_MATCH */
-#define FTS5_PLAN_SPECIAL 3 /* An internal query */
-#define FTS5_PLAN_SORTED_MATCH 4 /* (<tbl> MATCH ? ORDER BY rank) */
-#define FTS5_PLAN_SCAN 5 /* No usable constraint */
-#define FTS5_PLAN_ROWID 6 /* (rowid = ?) */
-
-/*
-** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this
-** extension is currently being used by a version of SQLite too old to
-** support index-info flags. In that case this function is a no-op.
-*/
-static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
-#if SQLITE_VERSION_NUMBER>=3008012
-#ifndef SQLITE_CORE
- if( sqlite3_libversion_number()>=3008012 )
-#endif
- {
- pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE;
- }
-#endif
-}
-
-/*
-** Implementation of the xBestIndex method for FTS5 tables. Within the
-** WHERE constraint, it searches for the following:
-**
-** 1. A MATCH constraint against the special column.
-** 2. A MATCH constraint against the "rank" column.
-** 3. An == constraint against the rowid column.
-** 4. A < or <= constraint against the rowid column.
-** 5. A > or >= constraint against the rowid column.
-**
-** Within the ORDER BY, either:
-**
-** 5. ORDER BY rank [ASC|DESC]
-** 6. ORDER BY rowid [ASC|DESC]
-**
-** Costs are assigned as follows:
-**
-** a) If an unusable MATCH operator is present in the WHERE clause, the
-** cost is unconditionally set to 1e50 (a really big number).
-**
-** a) If a MATCH operator is present, the cost depends on the other
-** constraints also present. As follows:
-**
-** * No other constraints: cost=1000.0
-** * One rowid range constraint: cost=750.0
-** * Both rowid range constraints: cost=500.0
-** * An == rowid constraint: cost=100.0
-**
-** b) Otherwise, if there is no MATCH:
-**
-** * No other constraints: cost=1000000.0
-** * One rowid range constraint: cost=750000.0
-** * Both rowid range constraints: cost=250000.0
-** * An == rowid constraint: cost=10.0
-**
-** Costs are not modified by the ORDER BY clause.
-*/
-static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
- Fts5Table *pTab = (Fts5Table*)pVTab;
- Fts5Config *pConfig = pTab->pConfig;
- int idxFlags = 0; /* Parameter passed through to xFilter() */
- int bHasMatch;
- int iNext;
- int i;
-
- struct Constraint {
- int op; /* Mask against sqlite3_index_constraint.op */
- int fts5op; /* FTS5 mask for idxFlags */
- int iCol; /* 0==rowid, 1==tbl, 2==rank */
- int omit; /* True to omit this if found */
- int iConsIndex; /* Index in pInfo->aConstraint[] */
- } aConstraint[] = {
- {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ,
- FTS5_BI_MATCH, 1, 1, -1},
- {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ,
- FTS5_BI_RANK, 2, 1, -1},
- {SQLITE_INDEX_CONSTRAINT_EQ, FTS5_BI_ROWID_EQ, 0, 0, -1},
- {SQLITE_INDEX_CONSTRAINT_LT|SQLITE_INDEX_CONSTRAINT_LE,
- FTS5_BI_ROWID_LE, 0, 0, -1},
- {SQLITE_INDEX_CONSTRAINT_GT|SQLITE_INDEX_CONSTRAINT_GE,
- FTS5_BI_ROWID_GE, 0, 0, -1},
- };
-
- int aColMap[3];
- aColMap[0] = -1;
- aColMap[1] = pConfig->nCol;
- aColMap[2] = pConfig->nCol+1;
-
- /* Set idxFlags flags for all WHERE clause terms that will be used. */
- for(i=0; i<pInfo->nConstraint; i++){
- struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
- int j;
- for(j=0; j<ArraySize(aConstraint); j++){
- struct Constraint *pC = &aConstraint[j];
- if( p->iColumn==aColMap[pC->iCol] && p->op & pC->op ){
- if( p->usable ){
- pC->iConsIndex = i;
- idxFlags |= pC->fts5op;
- }else if( j==0 ){
- /* As there exists an unusable MATCH constraint this is an
- ** unusable plan. Set a prohibitively high cost. */
- pInfo->estimatedCost = 1e50;
- return SQLITE_OK;
- }
- }
- }
- }
-
- /* Set idxFlags flags for the ORDER BY clause */
- if( pInfo->nOrderBy==1 ){
- int iSort = pInfo->aOrderBy[0].iColumn;
- if( iSort==(pConfig->nCol+1) && BitFlagTest(idxFlags, FTS5_BI_MATCH) ){
- idxFlags |= FTS5_BI_ORDER_RANK;
- }else if( iSort==-1 ){
- idxFlags |= FTS5_BI_ORDER_ROWID;
- }
- if( BitFlagTest(idxFlags, FTS5_BI_ORDER_RANK|FTS5_BI_ORDER_ROWID) ){
- pInfo->orderByConsumed = 1;
- if( pInfo->aOrderBy[0].desc ){
- idxFlags |= FTS5_BI_ORDER_DESC;
- }
- }
- }
-
- /* Calculate the estimated cost based on the flags set in idxFlags. */
- bHasMatch = BitFlagTest(idxFlags, FTS5_BI_MATCH);
- if( BitFlagTest(idxFlags, FTS5_BI_ROWID_EQ) ){
- pInfo->estimatedCost = bHasMatch ? 100.0 : 10.0;
- if( bHasMatch==0 ) fts5SetUniqueFlag(pInfo);
- }else if( BitFlagAllTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){
- pInfo->estimatedCost = bHasMatch ? 500.0 : 250000.0;
- }else if( BitFlagTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){
- pInfo->estimatedCost = bHasMatch ? 750.0 : 750000.0;
- }else{
- pInfo->estimatedCost = bHasMatch ? 1000.0 : 1000000.0;
- }
-
- /* Assign argvIndex values to each constraint in use. */
- iNext = 1;
- for(i=0; i<ArraySize(aConstraint); i++){
- struct Constraint *pC = &aConstraint[i];
- if( pC->iConsIndex>=0 ){
- pInfo->aConstraintUsage[pC->iConsIndex].argvIndex = iNext++;
- pInfo->aConstraintUsage[pC->iConsIndex].omit = (unsigned char)pC->omit;
- }
- }
-
- pInfo->idxNum = idxFlags;
- return SQLITE_OK;
-}
-
-static int fts5NewTransaction(Fts5Table *pTab){
- Fts5Cursor *pCsr;
- for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
- if( pCsr->base.pVtab==(sqlite3_vtab*)pTab ) return SQLITE_OK;
- }
- return sqlite3Fts5StorageReset(pTab->pStorage);
-}
-
-/*
-** Implementation of xOpen method.
-*/
-static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
- Fts5Table *pTab = (Fts5Table*)pVTab;
- Fts5Config *pConfig = pTab->pConfig;
- Fts5Cursor *pCsr = 0; /* New cursor object */
- int nByte; /* Bytes of space to allocate */
- int rc; /* Return code */
-
- rc = fts5NewTransaction(pTab);
- if( rc==SQLITE_OK ){
- nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int);
- pCsr = (Fts5Cursor*)sqlite3_malloc(nByte);
- if( pCsr ){
- Fts5Global *pGlobal = pTab->pGlobal;
- memset(pCsr, 0, nByte);
- pCsr->aColumnSize = (int*)&pCsr[1];
- pCsr->pNext = pGlobal->pCsr;
- pGlobal->pCsr = pCsr;
- pCsr->iCsrId = ++pGlobal->iNextId;
- }else{
- rc = SQLITE_NOMEM;
- }
- }
- *ppCsr = (sqlite3_vtab_cursor*)pCsr;
- return rc;
-}
-
-static int fts5StmtType(Fts5Cursor *pCsr){
- if( pCsr->ePlan==FTS5_PLAN_SCAN ){
- return (pCsr->bDesc) ? FTS5_STMT_SCAN_DESC : FTS5_STMT_SCAN_ASC;
- }
- return FTS5_STMT_LOOKUP;
-}
-
-/*
-** This function is called after the cursor passed as the only argument
-** is moved to point at a different row. It clears all cached data
-** specific to the previous row stored by the cursor object.
-*/
-static void fts5CsrNewrow(Fts5Cursor *pCsr){
- CsrFlagSet(pCsr,
- FTS5CSR_REQUIRE_CONTENT
- | FTS5CSR_REQUIRE_DOCSIZE
- | FTS5CSR_REQUIRE_INST
- | FTS5CSR_REQUIRE_POSLIST
- );
-}
-
-static void fts5FreeCursorComponents(Fts5Cursor *pCsr){
- Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
- Fts5Auxdata *pData;
- Fts5Auxdata *pNext;
-
- sqlite3_free(pCsr->aInstIter);
- sqlite3_free(pCsr->aInst);
- if( pCsr->pStmt ){
- int eStmt = fts5StmtType(pCsr);
- sqlite3Fts5StorageStmtRelease(pTab->pStorage, eStmt, pCsr->pStmt);
- }
- if( pCsr->pSorter ){
- Fts5Sorter *pSorter = pCsr->pSorter;
- sqlite3_finalize(pSorter->pStmt);
- sqlite3_free(pSorter);
- }
-
- if( pCsr->ePlan!=FTS5_PLAN_SOURCE ){
- sqlite3Fts5ExprFree(pCsr->pExpr);
- }
-
- for(pData=pCsr->pAuxdata; pData; pData=pNext){
- pNext = pData->pNext;
- if( pData->xDelete ) pData->xDelete(pData->pPtr);
- sqlite3_free(pData);
- }
-
- sqlite3_finalize(pCsr->pRankArgStmt);
- sqlite3_free(pCsr->apRankArg);
-
- if( CsrFlagTest(pCsr, FTS5CSR_FREE_ZRANK) ){
- sqlite3_free(pCsr->zRank);
- sqlite3_free(pCsr->zRankArgs);
- }
-
- memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan - (u8*)pCsr));
-}
-
-
-/*
-** Close the cursor. For additional information see the documentation
-** on the xClose method of the virtual table interface.
-*/
-static int fts5CloseMethod(sqlite3_vtab_cursor *pCursor){
- if( pCursor ){
- Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
- Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
- Fts5Cursor **pp;
-
- fts5FreeCursorComponents(pCsr);
- /* Remove the cursor from the Fts5Global.pCsr list */
- for(pp=&pTab->pGlobal->pCsr; (*pp)!=pCsr; pp=&(*pp)->pNext);
- *pp = pCsr->pNext;
-
- sqlite3_free(pCsr);
- }
- return SQLITE_OK;
-}
-
-static int fts5SorterNext(Fts5Cursor *pCsr){
- Fts5Sorter *pSorter = pCsr->pSorter;
- int rc;
-
- rc = sqlite3_step(pSorter->pStmt);
- if( rc==SQLITE_DONE ){
- rc = SQLITE_OK;
- CsrFlagSet(pCsr, FTS5CSR_EOF);
- }else if( rc==SQLITE_ROW ){
- const u8 *a;
- const u8 *aBlob;
- int nBlob;
- int i;
- int iOff = 0;
- rc = SQLITE_OK;
-
- pSorter->iRowid = sqlite3_column_int64(pSorter->pStmt, 0);
- nBlob = sqlite3_column_bytes(pSorter->pStmt, 1);
- aBlob = a = sqlite3_column_blob(pSorter->pStmt, 1);
-
- /* nBlob==0 in detail=none mode. */
- if( nBlob>0 ){
- for(i=0; i<(pSorter->nIdx-1); i++){
- int iVal;
- a += fts5GetVarint32(a, iVal);
- iOff += iVal;
- pSorter->aIdx[i] = iOff;
- }
- pSorter->aIdx[i] = &aBlob[nBlob] - a;
- pSorter->aPoslist = a;
- }
-
- fts5CsrNewrow(pCsr);
- }
-
- return rc;
-}
-
-
-/*
-** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors
-** open on table pTab.
-*/
-static void fts5TripCursors(Fts5Table *pTab){
- Fts5Cursor *pCsr;
- for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
- if( pCsr->ePlan==FTS5_PLAN_MATCH
- && pCsr->base.pVtab==(sqlite3_vtab*)pTab
- ){
- CsrFlagSet(pCsr, FTS5CSR_REQUIRE_RESEEK);
- }
- }
-}
-
-/*
-** If the REQUIRE_RESEEK flag is set on the cursor passed as the first
-** argument, close and reopen all Fts5IndexIter iterators that the cursor
-** is using. Then attempt to move the cursor to a rowid equal to or laster
-** (in the cursors sort order - ASC or DESC) than the current rowid.
-**
-** If the new rowid is not equal to the old, set output parameter *pbSkip
-** to 1 before returning. Otherwise, leave it unchanged.
-**
-** Return SQLITE_OK if successful or if no reseek was required, or an
-** error code if an error occurred.
-*/
-static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
- int rc = SQLITE_OK;
- assert( *pbSkip==0 );
- if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_RESEEK) ){
- Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
- int bDesc = pCsr->bDesc;
- i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr);
-
- rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->pIndex, iRowid, bDesc);
- if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){
- *pbSkip = 1;
- }
-
- CsrFlagClear(pCsr, FTS5CSR_REQUIRE_RESEEK);
- fts5CsrNewrow(pCsr);
- if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
- CsrFlagSet(pCsr, FTS5CSR_EOF);
- *pbSkip = 1;
- }
- }
- return rc;
-}
-
-
-/*
-** Advance the cursor to the next row in the table that matches the
-** search criteria.
-**
-** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned
-** even if we reach end-of-file. The fts5EofMethod() will be called
-** subsequently to determine whether or not an EOF was hit.
-*/
-static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
- Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
- int rc;
-
- assert( (pCsr->ePlan<3)==
- (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE)
- );
- assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) );
-
- if( pCsr->ePlan<3 ){
- int bSkip = 0;
- if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc;
- rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid);
- CsrFlagSet(pCsr, sqlite3Fts5ExprEof(pCsr->pExpr));
- fts5CsrNewrow(pCsr);
- }else{
- switch( pCsr->ePlan ){
- case FTS5_PLAN_SPECIAL: {
- CsrFlagSet(pCsr, FTS5CSR_EOF);
- rc = SQLITE_OK;
- break;
- }
-
- case FTS5_PLAN_SORTED_MATCH: {
- rc = fts5SorterNext(pCsr);
- break;
- }
-
- default:
- rc = sqlite3_step(pCsr->pStmt);
- if( rc!=SQLITE_ROW ){
- CsrFlagSet(pCsr, FTS5CSR_EOF);
- rc = sqlite3_reset(pCsr->pStmt);
- }else{
- rc = SQLITE_OK;
- }
- break;
- }
- }
-
- return rc;
-}
-
-
-static int fts5PrepareStatement(
- sqlite3_stmt **ppStmt,
- Fts5Config *pConfig,
- const char *zFmt,
- ...
-){
- sqlite3_stmt *pRet = 0;
- int rc;
- char *zSql;
- va_list ap;
-
- va_start(ap, zFmt);
- zSql = sqlite3_vmprintf(zFmt, ap);
- if( zSql==0 ){
- rc = SQLITE_NOMEM;
- }else{
- rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pRet, 0);
- if( rc!=SQLITE_OK ){
- *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db));
- }
- sqlite3_free(zSql);
- }
-
- va_end(ap);
- *ppStmt = pRet;
- return rc;
-}
-
-static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
- Fts5Config *pConfig = pTab->pConfig;
- Fts5Sorter *pSorter;
- int nPhrase;
- int nByte;
- int rc;
- const char *zRank = pCsr->zRank;
- const char *zRankArgs = pCsr->zRankArgs;
-
- nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
- nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1);
- pSorter = (Fts5Sorter*)sqlite3_malloc(nByte);
- if( pSorter==0 ) return SQLITE_NOMEM;
- memset(pSorter, 0, nByte);
- pSorter->nIdx = nPhrase;
-
- /* TODO: It would be better to have some system for reusing statement
- ** handles here, rather than preparing a new one for each query. But that
- ** is not possible as SQLite reference counts the virtual table objects.
- ** And since the statement required here reads from this very virtual
- ** table, saving it creates a circular reference.
- **
- ** If SQLite a built-in statement cache, this wouldn't be a problem. */
- rc = fts5PrepareStatement(&pSorter->pStmt, pConfig,
- "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(%s%s%s) %s",
- pConfig->zDb, pConfig->zName, zRank, pConfig->zName,
- (zRankArgs ? ", " : ""),
- (zRankArgs ? zRankArgs : ""),
- bDesc ? "DESC" : "ASC"
- );
-
- pCsr->pSorter = pSorter;
- if( rc==SQLITE_OK ){
- assert( pTab->pSortCsr==0 );
- pTab->pSortCsr = pCsr;
- rc = fts5SorterNext(pCsr);
- pTab->pSortCsr = 0;
- }
-
- if( rc!=SQLITE_OK ){
- sqlite3_finalize(pSorter->pStmt);
- sqlite3_free(pSorter);
- pCsr->pSorter = 0;
- }
-
- return rc;
-}
-
-static int fts5CursorFirst(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
- int rc;
- Fts5Expr *pExpr = pCsr->pExpr;
- rc = sqlite3Fts5ExprFirst(pExpr, pTab->pIndex, pCsr->iFirstRowid, bDesc);
- if( sqlite3Fts5ExprEof(pExpr) ){
- CsrFlagSet(pCsr, FTS5CSR_EOF);
- }
- fts5CsrNewrow(pCsr);
- return rc;
-}
-
-/*
-** Process a "special" query. A special query is identified as one with a
-** MATCH expression that begins with a '*' character. The remainder of
-** the text passed to the MATCH operator are used as the special query
-** parameters.
-*/
-static int fts5SpecialMatch(
- Fts5Table *pTab,
- Fts5Cursor *pCsr,
- const char *zQuery
-){
- int rc = SQLITE_OK; /* Return code */
- const char *z = zQuery; /* Special query text */
- int n; /* Number of bytes in text at z */
-
- while( z[0]==' ' ) z++;
- for(n=0; z[n] && z[n]!=' '; n++);
-
- assert( pTab->base.zErrMsg==0 );
- pCsr->ePlan = FTS5_PLAN_SPECIAL;
-
- if( 0==sqlite3_strnicmp("reads", z, n) ){
- pCsr->iSpecial = sqlite3Fts5IndexReads(pTab->pIndex);
- }
- else if( 0==sqlite3_strnicmp("id", z, n) ){
- pCsr->iSpecial = pCsr->iCsrId;
- }
- else{
- /* An unrecognized directive. Return an error message. */
- pTab->base.zErrMsg = sqlite3_mprintf("unknown special query: %.*s", n, z);
- rc = SQLITE_ERROR;
- }
-
- return rc;
-}
-
-/*
-** Search for an auxiliary function named zName that can be used with table
-** pTab. If one is found, return a pointer to the corresponding Fts5Auxiliary
-** structure. Otherwise, if no such function exists, return NULL.
-*/
-static Fts5Auxiliary *fts5FindAuxiliary(Fts5Table *pTab, const char *zName){
- Fts5Auxiliary *pAux;
-
- for(pAux=pTab->pGlobal->pAux; pAux; pAux=pAux->pNext){
- if( sqlite3_stricmp(zName, pAux->zFunc)==0 ) return pAux;
- }
-
- /* No function of the specified name was found. Return 0. */
- return 0;
-}
-
-
-static int fts5FindRankFunction(Fts5Cursor *pCsr){
- Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
- Fts5Config *pConfig = pTab->pConfig;
- int rc = SQLITE_OK;
- Fts5Auxiliary *pAux = 0;
- const char *zRank = pCsr->zRank;
- const char *zRankArgs = pCsr->zRankArgs;
-
- if( zRankArgs ){
- char *zSql = sqlite3Fts5Mprintf(&rc, "SELECT %s", zRankArgs);
- if( zSql ){
- sqlite3_stmt *pStmt = 0;
- rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pStmt, 0);
- sqlite3_free(zSql);
- assert( rc==SQLITE_OK || pCsr->pRankArgStmt==0 );
- if( rc==SQLITE_OK ){
- if( SQLITE_ROW==sqlite3_step(pStmt) ){
- int nByte;
- pCsr->nRankArg = sqlite3_column_count(pStmt);
- nByte = sizeof(sqlite3_value*)*pCsr->nRankArg;
- pCsr->apRankArg = (sqlite3_value**)sqlite3Fts5MallocZero(&rc, nByte);
- if( rc==SQLITE_OK ){
- int i;
- for(i=0; i<pCsr->nRankArg; i++){
- pCsr->apRankArg[i] = sqlite3_column_value(pStmt, i);
- }
- }
- pCsr->pRankArgStmt = pStmt;
- }else{
- rc = sqlite3_finalize(pStmt);
- assert( rc!=SQLITE_OK );
- }
- }
- }
- }
-
- if( rc==SQLITE_OK ){
- pAux = fts5FindAuxiliary(pTab, zRank);
- if( pAux==0 ){
- assert( pTab->base.zErrMsg==0 );
- pTab->base.zErrMsg = sqlite3_mprintf("no such function: %s", zRank);
- rc = SQLITE_ERROR;
- }
- }
-
- pCsr->pRank = pAux;
- return rc;
-}
-
-
-static int fts5CursorParseRank(
- Fts5Config *pConfig,
- Fts5Cursor *pCsr,
- sqlite3_value *pRank
-){
- int rc = SQLITE_OK;
- if( pRank ){
- const char *z = (const char*)sqlite3_value_text(pRank);
- char *zRank = 0;
- char *zRankArgs = 0;
-
- if( z==0 ){
- if( sqlite3_value_type(pRank)==SQLITE_NULL ) rc = SQLITE_ERROR;
- }else{
- rc = sqlite3Fts5ConfigParseRank(z, &zRank, &zRankArgs);
- }
- if( rc==SQLITE_OK ){
- pCsr->zRank = zRank;
- pCsr->zRankArgs = zRankArgs;
- CsrFlagSet(pCsr, FTS5CSR_FREE_ZRANK);
- }else if( rc==SQLITE_ERROR ){
- pCsr->base.pVtab->zErrMsg = sqlite3_mprintf(
- "parse error in rank function: %s", z
- );
- }
- }else{
- if( pConfig->zRank ){
- pCsr->zRank = (char*)pConfig->zRank;
- pCsr->zRankArgs = (char*)pConfig->zRankArgs;
- }else{
- pCsr->zRank = (char*)FTS5_DEFAULT_RANK;
- pCsr->zRankArgs = 0;
- }
- }
- return rc;
-}
-
-static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){
- if( pVal ){
- int eType = sqlite3_value_numeric_type(pVal);
- if( eType==SQLITE_INTEGER ){
- return sqlite3_value_int64(pVal);
- }
- }
- return iDefault;
-}
-
-/*
-** This is the xFilter interface for the virtual table. See
-** the virtual table xFilter method documentation for additional
-** information.
-**
-** There are three possible query strategies:
-**
-** 1. Full-text search using a MATCH operator.
-** 2. A by-rowid lookup.
-** 3. A full-table scan.
-*/
-static int fts5FilterMethod(
- sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */
- int idxNum, /* Strategy index */
- const char *zUnused, /* Unused */
- int nVal, /* Number of elements in apVal */
- sqlite3_value **apVal /* Arguments for the indexing scheme */
-){
- Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
- Fts5Config *pConfig = pTab->pConfig;
- Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
- int rc = SQLITE_OK; /* Error code */
- int iVal = 0; /* Counter for apVal[] */
- int bDesc; /* True if ORDER BY [rank|rowid] DESC */
- int bOrderByRank; /* True if ORDER BY rank */
- sqlite3_value *pMatch = 0; /* <tbl> MATCH ? expression (or NULL) */
- sqlite3_value *pRank = 0; /* rank MATCH ? expression (or NULL) */
- sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */
- sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */
- sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */
- char **pzErrmsg = pConfig->pzErrmsg;
-
- UNUSED_PARAM(zUnused);
- UNUSED_PARAM(nVal);
-
- if( pCsr->ePlan ){
- fts5FreeCursorComponents(pCsr);
- memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
- }
-
- assert( pCsr->pStmt==0 );
- assert( pCsr->pExpr==0 );
- assert( pCsr->csrflags==0 );
- assert( pCsr->pRank==0 );
- assert( pCsr->zRank==0 );
- assert( pCsr->zRankArgs==0 );
-
- assert( pzErrmsg==0 || pzErrmsg==&pTab->base.zErrMsg );
- pConfig->pzErrmsg = &pTab->base.zErrMsg;
-
- /* Decode the arguments passed through to this function.
- **
- ** Note: The following set of if(...) statements must be in the same
- ** order as the corresponding entries in the struct at the top of
- ** fts5BestIndexMethod(). */
- if( BitFlagTest(idxNum, FTS5_BI_MATCH) ) pMatch = apVal[iVal++];
- if( BitFlagTest(idxNum, FTS5_BI_RANK) ) pRank = apVal[iVal++];
- if( BitFlagTest(idxNum, FTS5_BI_ROWID_EQ) ) pRowidEq = apVal[iVal++];
- if( BitFlagTest(idxNum, FTS5_BI_ROWID_LE) ) pRowidLe = apVal[iVal++];
- if( BitFlagTest(idxNum, FTS5_BI_ROWID_GE) ) pRowidGe = apVal[iVal++];
- assert( iVal==nVal );
- bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0);
- pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0);
-
- /* Set the cursor upper and lower rowid limits. Only some strategies
- ** actually use them. This is ok, as the xBestIndex() method leaves the
- ** sqlite3_index_constraint.omit flag clear for range constraints
- ** on the rowid field. */
- if( pRowidEq ){
- pRowidLe = pRowidGe = pRowidEq;
- }
- if( bDesc ){
- pCsr->iFirstRowid = fts5GetRowidLimit(pRowidLe, LARGEST_INT64);
- pCsr->iLastRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64);
- }else{
- pCsr->iLastRowid = fts5GetRowidLimit(pRowidLe, LARGEST_INT64);
- pCsr->iFirstRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64);
- }
-
- if( pTab->pSortCsr ){
- /* If pSortCsr is non-NULL, then this call is being made as part of
- ** processing for a "... MATCH <expr> ORDER BY rank" query (ePlan is
- ** set to FTS5_PLAN_SORTED_MATCH). pSortCsr is the cursor that will
- ** return results to the user for this query. The current cursor
- ** (pCursor) is used to execute the query issued by function
- ** fts5CursorFirstSorted() above. */
- assert( pRowidEq==0 && pRowidLe==0 && pRowidGe==0 && pRank==0 );
- assert( nVal==0 && pMatch==0 && bOrderByRank==0 && bDesc==0 );
- assert( pCsr->iLastRowid==LARGEST_INT64 );
- assert( pCsr->iFirstRowid==SMALLEST_INT64 );
- pCsr->ePlan = FTS5_PLAN_SOURCE;
- pCsr->pExpr = pTab->pSortCsr->pExpr;
- rc = fts5CursorFirst(pTab, pCsr, bDesc);
- sqlite3Fts5ExprClearEof(pCsr->pExpr);
- }else if( pMatch ){
- const char *zExpr = (const char*)sqlite3_value_text(apVal[0]);
- if( zExpr==0 ) zExpr = "";
-
- rc = fts5CursorParseRank(pConfig, pCsr, pRank);
- if( rc==SQLITE_OK ){
- if( zExpr[0]=='*' ){
- /* The user has issued a query of the form "MATCH '*...'". This
- ** indicates that the MATCH expression is not a full text query,
- ** but a request for an internal parameter. */
- rc = fts5SpecialMatch(pTab, pCsr, &zExpr[1]);
- }else{
- char **pzErr = &pTab->base.zErrMsg;
- rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pCsr->pExpr, pzErr);
- if( rc==SQLITE_OK ){
- if( bOrderByRank ){
- pCsr->ePlan = FTS5_PLAN_SORTED_MATCH;
- rc = fts5CursorFirstSorted(pTab, pCsr, bDesc);
- }else{
- pCsr->ePlan = FTS5_PLAN_MATCH;
- rc = fts5CursorFirst(pTab, pCsr, bDesc);
- }
- }
- }
- }
- }else if( pConfig->zContent==0 ){
- *pConfig->pzErrmsg = sqlite3_mprintf(
- "%s: table does not support scanning", pConfig->zName
- );
- rc = SQLITE_ERROR;
- }else{
- /* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup
- ** by rowid (ePlan==FTS5_PLAN_ROWID). */
- pCsr->ePlan = (pRowidEq ? FTS5_PLAN_ROWID : FTS5_PLAN_SCAN);
- rc = sqlite3Fts5StorageStmt(
- pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->base.zErrMsg
- );
- if( rc==SQLITE_OK ){
- if( pCsr->ePlan==FTS5_PLAN_ROWID ){
- sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
- }else{
- sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iFirstRowid);
- sqlite3_bind_int64(pCsr->pStmt, 2, pCsr->iLastRowid);
- }
- rc = fts5NextMethod(pCursor);
- }
- }
-
- pConfig->pzErrmsg = pzErrmsg;
- return rc;
-}
-
-/*
-** This is the xEof method of the virtual table. SQLite calls this
-** routine to find out if it has reached the end of a result set.
-*/
-static int fts5EofMethod(sqlite3_vtab_cursor *pCursor){
- Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
- return (CsrFlagTest(pCsr, FTS5CSR_EOF) ? 1 : 0);
-}
-
-/*
-** Return the rowid that the cursor currently points to.
-*/
-static i64 fts5CursorRowid(Fts5Cursor *pCsr){
- assert( pCsr->ePlan==FTS5_PLAN_MATCH
- || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
- || pCsr->ePlan==FTS5_PLAN_SOURCE
- );
- if( pCsr->pSorter ){
- return pCsr->pSorter->iRowid;
- }else{
- return sqlite3Fts5ExprRowid(pCsr->pExpr);
- }
-}
-
-/*
-** This is the xRowid method. The SQLite core calls this routine to
-** retrieve the rowid for the current row of the result set. fts5
-** exposes %_content.rowid as the rowid for the virtual table. The
-** rowid should be written to *pRowid.
-*/
-static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
- Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
- int ePlan = pCsr->ePlan;
-
- assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
- switch( ePlan ){
- case FTS5_PLAN_SPECIAL:
- *pRowid = 0;
- break;
-
- case FTS5_PLAN_SOURCE:
- case FTS5_PLAN_MATCH:
- case FTS5_PLAN_SORTED_MATCH:
- *pRowid = fts5CursorRowid(pCsr);
- break;
-
- default:
- *pRowid = sqlite3_column_int64(pCsr->pStmt, 0);
- break;
- }
-
- return SQLITE_OK;
-}
-
-/*
-** If the cursor requires seeking (bSeekRequired flag is set), seek it.
-** Return SQLITE_OK if no error occurs, or an SQLite error code otherwise.
-**
-** If argument bErrormsg is true and an error occurs, an error message may
-** be left in sqlite3_vtab.zErrMsg.
-*/
-static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
- int rc = SQLITE_OK;
-
- /* If the cursor does not yet have a statement handle, obtain one now. */
- if( pCsr->pStmt==0 ){
- Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
- int eStmt = fts5StmtType(pCsr);
- rc = sqlite3Fts5StorageStmt(
- pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->base.zErrMsg:0)
- );
- assert( rc!=SQLITE_OK || pTab->base.zErrMsg==0 );
- assert( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) );
- }
-
- if( rc==SQLITE_OK && CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ){
- assert( pCsr->pExpr );
- sqlite3_reset(pCsr->pStmt);
- sqlite3_bind_int64(pCsr->pStmt, 1, fts5CursorRowid(pCsr));
- rc = sqlite3_step(pCsr->pStmt);
- if( rc==SQLITE_ROW ){
- rc = SQLITE_OK;
- CsrFlagClear(pCsr, FTS5CSR_REQUIRE_CONTENT);
- }else{
- rc = sqlite3_reset(pCsr->pStmt);
- if( rc==SQLITE_OK ){
- rc = FTS5_CORRUPT;
- }
- }
- }
- return rc;
-}
-
-static void fts5SetVtabError(Fts5Table *p, const char *zFormat, ...){
- va_list ap; /* ... printf arguments */
- va_start(ap, zFormat);
- assert( p->base.zErrMsg==0 );
- p->base.zErrMsg = sqlite3_vmprintf(zFormat, ap);
- va_end(ap);
-}
-
-/*
-** This function is called to handle an FTS INSERT command. In other words,
-** an INSERT statement of the form:
-**
-** INSERT INTO fts(fts) VALUES($pCmd)
-** INSERT INTO fts(fts, rank) VALUES($pCmd, $pVal)
-**
-** Argument pVal is the value assigned to column "fts" by the INSERT
-** statement. This function returns SQLITE_OK if successful, or an SQLite
-** error code if an error occurs.
-**
-** The commands implemented by this function are documented in the "Special
-** INSERT Directives" section of the documentation. It should be updated if
-** more commands are added to this function.
-*/
-static int fts5SpecialInsert(
- Fts5Table *pTab, /* Fts5 table object */
- const char *zCmd, /* Text inserted into table-name column */
- sqlite3_value *pVal /* Value inserted into rank column */
-){
- Fts5Config *pConfig = pTab->pConfig;
- int rc = SQLITE_OK;
- int bError = 0;
-
- if( 0==sqlite3_stricmp("delete-all", zCmd) ){
- if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
- fts5SetVtabError(pTab,
- "'delete-all' may only be used with a "
- "contentless or external content fts5 table"
- );
- rc = SQLITE_ERROR;
- }else{
- rc = sqlite3Fts5StorageDeleteAll(pTab->pStorage);
- }
- }else if( 0==sqlite3_stricmp("rebuild", zCmd) ){
- if( pConfig->eContent==FTS5_CONTENT_NONE ){
- fts5SetVtabError(pTab,
- "'rebuild' may not be used with a contentless fts5 table"
- );
- rc = SQLITE_ERROR;
- }else{
- rc = sqlite3Fts5StorageRebuild(pTab->pStorage);
- }
- }else if( 0==sqlite3_stricmp("optimize", zCmd) ){
- rc = sqlite3Fts5StorageOptimize(pTab->pStorage);
- }else if( 0==sqlite3_stricmp("merge", zCmd) ){
- int nMerge = sqlite3_value_int(pVal);
- rc = sqlite3Fts5StorageMerge(pTab->pStorage, nMerge);
- }else if( 0==sqlite3_stricmp("integrity-check", zCmd) ){
- rc = sqlite3Fts5StorageIntegrity(pTab->pStorage);
-#ifdef SQLITE_DEBUG
- }else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){
- pConfig->bPrefixIndex = sqlite3_value_int(pVal);
-#endif
- }else{
- rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex);
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5ConfigSetValue(pTab->pConfig, zCmd, pVal, &bError);
- }
- if( rc==SQLITE_OK ){
- if( bError ){
- rc = SQLITE_ERROR;
- }else{
- rc = sqlite3Fts5StorageConfigValue(pTab->pStorage, zCmd, pVal, 0);
- }
- }
- }
- return rc;
-}
-
-static int fts5SpecialDelete(
- Fts5Table *pTab,
- sqlite3_value **apVal
-){
- int rc = SQLITE_OK;
- int eType1 = sqlite3_value_type(apVal[1]);
- if( eType1==SQLITE_INTEGER ){
- sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]);
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]);
- }
- return rc;
-}
-
-static void fts5StorageInsert(
- int *pRc,
- Fts5Table *pTab,
- sqlite3_value **apVal,
- i64 *piRowid
-){
- int rc = *pRc;
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, piRowid);
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *piRowid);
- }
- *pRc = rc;
-}
-
-/*
-** This function is the implementation of the xUpdate callback used by
-** FTS3 virtual tables. It is invoked by SQLite each time a row is to be
-** inserted, updated or deleted.
-**
-** A delete specifies a single argument - the rowid of the row to remove.
-**
-** Update and insert operations pass:
-**
-** 1. The "old" rowid, or NULL.
-** 2. The "new" rowid.
-** 3. Values for each of the nCol matchable columns.
-** 4. Values for the two hidden columns (<tablename> and "rank").
-*/
-static int fts5UpdateMethod(
- sqlite3_vtab *pVtab, /* Virtual table handle */
- int nArg, /* Size of argument array */
- sqlite3_value **apVal, /* Array of arguments */
- sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */
-){
- Fts5Table *pTab = (Fts5Table*)pVtab;
- Fts5Config *pConfig = pTab->pConfig;
- int eType0; /* value_type() of apVal[0] */
- int rc = SQLITE_OK; /* Return code */
-
- /* A transaction must be open when this is called. */
- assert( pTab->ts.eState==1 );
-
- assert( pVtab->zErrMsg==0 );
- assert( nArg==1 || nArg==(2+pConfig->nCol+2) );
- assert( nArg==1
- || sqlite3_value_type(apVal[1])==SQLITE_INTEGER
- || sqlite3_value_type(apVal[1])==SQLITE_NULL
- );
- assert( pTab->pConfig->pzErrmsg==0 );
- pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg;
-
- /* Put any active cursors into REQUIRE_SEEK state. */
- fts5TripCursors(pTab);
-
- eType0 = sqlite3_value_type(apVal[0]);
- if( eType0==SQLITE_NULL
- && sqlite3_value_type(apVal[2+pConfig->nCol])!=SQLITE_NULL
- ){
- /* A "special" INSERT op. These are handled separately. */
- const char *z = (const char*)sqlite3_value_text(apVal[2+pConfig->nCol]);
- if( pConfig->eContent!=FTS5_CONTENT_NORMAL
- && 0==sqlite3_stricmp("delete", z)
- ){
- rc = fts5SpecialDelete(pTab, apVal);
- }else{
- rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
- }
- }else{
- /* A regular INSERT, UPDATE or DELETE statement. The trick here is that
- ** any conflict on the rowid value must be detected before any
- ** modifications are made to the database file. There are 4 cases:
- **
- ** 1) DELETE
- ** 2) UPDATE (rowid not modified)
- ** 3) UPDATE (rowid modified)
- ** 4) INSERT
- **
- ** Cases 3 and 4 may violate the rowid constraint.
- */
- int eConflict = SQLITE_ABORT;
- if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
- eConflict = sqlite3_vtab_on_conflict(pConfig->db);
- }
-
- assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL );
- assert( nArg!=1 || eType0==SQLITE_INTEGER );
-
- /* Filter out attempts to run UPDATE or DELETE on contentless tables.
- ** This is not suported. */
- if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){
- pTab->base.zErrMsg = sqlite3_mprintf(
- "cannot %s contentless fts5 table: %s",
- (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
- );
- rc = SQLITE_ERROR;
- }
-
- /* DELETE */
- else if( nArg==1 ){
- i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
- }
-
- /* INSERT */
- else if( eType0!=SQLITE_INTEGER ){
- /* If this is a REPLACE, first remove the current entry (if any) */
- if( eConflict==SQLITE_REPLACE
- && sqlite3_value_type(apVal[1])==SQLITE_INTEGER
- ){
- i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
- }
- fts5StorageInsert(&rc, pTab, apVal, pRowid);
- }
-
- /* UPDATE */
- else{
- i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
- i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
- if( iOld!=iNew ){
- if( eConflict==SQLITE_REPLACE ){
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
- }
- fts5StorageInsert(&rc, pTab, apVal, pRowid);
- }else{
- rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid);
- }
- }
- }else{
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
- fts5StorageInsert(&rc, pTab, apVal, pRowid);
- }
- }
- }
-
- pTab->pConfig->pzErrmsg = 0;
- return rc;
-}
-
-/*
-** Implementation of xSync() method.
-*/
-static int fts5SyncMethod(sqlite3_vtab *pVtab){
- int rc;
- Fts5Table *pTab = (Fts5Table*)pVtab;
- fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
- pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg;
- fts5TripCursors(pTab);
- rc = sqlite3Fts5StorageSync(pTab->pStorage, 1);
- pTab->pConfig->pzErrmsg = 0;
- return rc;
-}
-
-/*
-** Implementation of xBegin() method.
-*/
-static int fts5BeginMethod(sqlite3_vtab *pVtab){
- fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0);
- fts5NewTransaction((Fts5Table*)pVtab);
- return SQLITE_OK;
-}
-
-/*
-** Implementation of xCommit() method. This is a no-op. The contents of
-** the pending-terms hash-table have already been flushed into the database
-** by fts5SyncMethod().
-*/
-static int fts5CommitMethod(sqlite3_vtab *pVtab){
- UNUSED_PARAM(pVtab); /* Call below is a no-op for NDEBUG builds */
- fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_COMMIT, 0);
- return SQLITE_OK;
-}
-
-/*
-** Implementation of xRollback(). Discard the contents of the pending-terms
-** hash-table. Any changes made to the database are reverted by SQLite.
-*/
-static int fts5RollbackMethod(sqlite3_vtab *pVtab){
- int rc;
- Fts5Table *pTab = (Fts5Table*)pVtab;
- fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0);
- rc = sqlite3Fts5StorageRollback(pTab->pStorage);
- return rc;
-}
-
-static int fts5CsrPoslist(Fts5Cursor*, int, const u8**, int*);
-
-static void *fts5ApiUserData(Fts5Context *pCtx){
- Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- return pCsr->pAux->pUserData;
-}
-
-static int fts5ApiColumnCount(Fts5Context *pCtx){
- Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- return ((Fts5Table*)(pCsr->base.pVtab))->pConfig->nCol;
-}
-
-static int fts5ApiColumnTotalSize(
- Fts5Context *pCtx,
- int iCol,
- sqlite3_int64 *pnToken
-){
- Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
- return sqlite3Fts5StorageSize(pTab->pStorage, iCol, pnToken);
-}
-
-static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){
- Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
- return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow);
-}
-
-static int fts5ApiTokenize(
- Fts5Context *pCtx,
- const char *pText, int nText,
- void *pUserData,
- int (*xToken)(void*, int, const char*, int, int, int)
-){
- Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
- return sqlite3Fts5Tokenize(
- pTab->pConfig, FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
- );
-}
-
-static int fts5ApiPhraseCount(Fts5Context *pCtx){
- Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- return sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
-}
-
-static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
- Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
-}
-
-static int fts5ApiColumnText(
- Fts5Context *pCtx,
- int iCol,
- const char **pz,
- int *pn
-){
- int rc = SQLITE_OK;
- Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){
- *pz = 0;
- *pn = 0;
- }else{
- rc = fts5SeekCursor(pCsr, 0);
- if( rc==SQLITE_OK ){
- *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
- *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
- }
- }
- return rc;
-}
-
-static int fts5CsrPoslist(
- Fts5Cursor *pCsr,
- int iPhrase,
- const u8 **pa,
- int *pn
-){
- Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
- int rc = SQLITE_OK;
- int bLive = (pCsr->pSorter==0);
-
- if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
-
- if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
- Fts5PoslistPopulator *aPopulator;
- int i;
- aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive);
- if( aPopulator==0 ) rc = SQLITE_NOMEM;
- for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){
- int n; const char *z;
- rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n);
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5ExprPopulatePoslists(
- pConfig, pCsr->pExpr, aPopulator, i, z, n
- );
- }
- }
- sqlite3_free(aPopulator);
-
- if( pCsr->pSorter ){
- sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid);
- }
- }
- CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST);
- }
-
- if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
- Fts5Sorter *pSorter = pCsr->pSorter;
- int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
- *pn = pSorter->aIdx[iPhrase] - i1;
- *pa = &pSorter->aPoslist[i1];
- }else{
- *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
- }
-
- return rc;
-}
-
-/*
-** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated
-** correctly for the current view. Return SQLITE_OK if successful, or an
-** SQLite error code otherwise.
-*/
-static int fts5CacheInstArray(Fts5Cursor *pCsr){
- int rc = SQLITE_OK;
- Fts5PoslistReader *aIter; /* One iterator for each phrase */
- int nIter; /* Number of iterators/phrases */
-
- nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
- if( pCsr->aInstIter==0 ){
- int nByte = sizeof(Fts5PoslistReader) * nIter;
- pCsr->aInstIter = (Fts5PoslistReader*)sqlite3Fts5MallocZero(&rc, nByte);
- }
- aIter = pCsr->aInstIter;
-
- if( aIter ){
- int nInst = 0; /* Number instances seen so far */
- int i;
-
- /* Initialize all iterators */
- for(i=0; i<nIter && rc==SQLITE_OK; i++){
- const u8 *a;
- int n;
- rc = fts5CsrPoslist(pCsr, i, &a, &n);
- if( rc==SQLITE_OK ){
- sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
- }
- }
-
- if( rc==SQLITE_OK ){
- while( 1 ){
- int *aInst;
- int iBest = -1;
- for(i=0; i<nIter; i++){
- if( (aIter[i].bEof==0)
- && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos)
- ){
- iBest = i;
- }
- }
- if( iBest<0 ) break;
-
- nInst++;
- if( nInst>=pCsr->nInstAlloc ){
- pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
- aInst = (int*)sqlite3_realloc(
- pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3
- );
- if( aInst ){
- pCsr->aInst = aInst;
- }else{
- rc = SQLITE_NOMEM;
- break;
- }
- }
-
- aInst = &pCsr->aInst[3 * (nInst-1)];
- aInst[0] = iBest;
- aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
- aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
- sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
- }
- }
-
- pCsr->nInstCount = nInst;
- CsrFlagClear(pCsr, FTS5CSR_REQUIRE_INST);
- }
- return rc;
-}
-
-static int fts5ApiInstCount(Fts5Context *pCtx, int *pnInst){
- Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- int rc = SQLITE_OK;
- if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
- || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) ){
- *pnInst = pCsr->nInstCount;
- }
- return rc;
-}
-
-static int fts5ApiInst(
- Fts5Context *pCtx,
- int iIdx,
- int *piPhrase,
- int *piCol,
- int *piOff
-){
- Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- int rc = SQLITE_OK;
- if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
- || SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
- ){
- if( iIdx<0 || iIdx>=pCsr->nInstCount ){
- rc = SQLITE_RANGE;
-#if 0
- }else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){
- *piPhrase = pCsr->aInst[iIdx*3];
- *piCol = pCsr->aInst[iIdx*3 + 2];
- *piOff = -1;
-#endif
- }else{
- *piPhrase = pCsr->aInst[iIdx*3];
- *piCol = pCsr->aInst[iIdx*3 + 1];
- *piOff = pCsr->aInst[iIdx*3 + 2];
- }
- }
- return rc;
-}
-
-static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){
- return fts5CursorRowid((Fts5Cursor*)pCtx);
-}
-
-static int fts5ColumnSizeCb(
- void *pContext, /* Pointer to int */
- int tflags,
- const char *pUnused, /* Buffer containing token */
- int nUnused, /* Size of token in bytes */
- int iUnused1, /* Start offset of token */
- int iUnused2 /* End offset of token */
-){
- int *pCnt = (int*)pContext;
- UNUSED_PARAM2(pUnused, nUnused);
- UNUSED_PARAM2(iUnused1, iUnused2);
- if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){
- (*pCnt)++;
- }
- return SQLITE_OK;
-}
-
-static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){
- Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
- Fts5Config *pConfig = pTab->pConfig;
- int rc = SQLITE_OK;
-
- if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_DOCSIZE) ){
- if( pConfig->bColumnsize ){
- i64 iRowid = fts5CursorRowid(pCsr);
- rc = sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize);
- }else if( pConfig->zContent==0 ){
- int i;
- for(i=0; i<pConfig->nCol; i++){
- if( pConfig->abUnindexed[i]==0 ){
- pCsr->aColumnSize[i] = -1;
- }
- }
- }else{
- int i;
- for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
- if( pConfig->abUnindexed[i]==0 ){
- const char *z; int n;
- void *p = (void*)(&pCsr->aColumnSize[i]);
- pCsr->aColumnSize[i] = 0;
- rc = fts5ApiColumnText(pCtx, i, &z, &n);
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5Tokenize(
- pConfig, FTS5_TOKENIZE_AUX, z, n, p, fts5ColumnSizeCb
- );
- }
- }
- }
- }
- CsrFlagClear(pCsr, FTS5CSR_REQUIRE_DOCSIZE);
- }
- if( iCol<0 ){
- int i;
- *pnToken = 0;
- for(i=0; i<pConfig->nCol; i++){
- *pnToken += pCsr->aColumnSize[i];
- }
- }else if( iCol<pConfig->nCol ){
- *pnToken = pCsr->aColumnSize[iCol];
- }else{
- *pnToken = 0;
- rc = SQLITE_RANGE;
- }
- return rc;
-}
-
-/*
-** Implementation of the xSetAuxdata() method.
-*/
-static int fts5ApiSetAuxdata(
- Fts5Context *pCtx, /* Fts5 context */
- void *pPtr, /* Pointer to save as auxdata */
- void(*xDelete)(void*) /* Destructor for pPtr (or NULL) */
-){
- Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- Fts5Auxdata *pData;
-
- /* Search through the cursors list of Fts5Auxdata objects for one that
- ** corresponds to the currently executing auxiliary function. */
- for(pData=pCsr->pAuxdata; pData; pData=pData->pNext){
- if( pData->pAux==pCsr->pAux ) break;
- }
-
- if( pData ){
- if( pData->xDelete ){
- pData->xDelete(pData->pPtr);
- }
- }else{
- int rc = SQLITE_OK;
- pData = (Fts5Auxdata*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Auxdata));
- if( pData==0 ){
- if( xDelete ) xDelete(pPtr);
- return rc;
- }
- pData->pAux = pCsr->pAux;
- pData->pNext = pCsr->pAuxdata;
- pCsr->pAuxdata = pData;
- }
-
- pData->xDelete = xDelete;
- pData->pPtr = pPtr;
- return SQLITE_OK;
-}
-
-static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){
- Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- Fts5Auxdata *pData;
- void *pRet = 0;
-
- for(pData=pCsr->pAuxdata; pData; pData=pData->pNext){
- if( pData->pAux==pCsr->pAux ) break;
- }
-
- if( pData ){
- pRet = pData->pPtr;
- if( bClear ){
- pData->pPtr = 0;
- pData->xDelete = 0;
- }
- }
-
- return pRet;
-}
-
-static void fts5ApiPhraseNext(
- Fts5Context *pUnused,
- Fts5PhraseIter *pIter,
- int *piCol, int *piOff
-){
- UNUSED_PARAM(pUnused);
- if( pIter->a>=pIter->b ){
- *piCol = -1;
- *piOff = -1;
- }else{
- int iVal;
- pIter->a += fts5GetVarint32(pIter->a, iVal);
- if( iVal==1 ){
- pIter->a += fts5GetVarint32(pIter->a, iVal);
- *piCol = iVal;
- *piOff = 0;
- pIter->a += fts5GetVarint32(pIter->a, iVal);
- }
- *piOff += (iVal-2);
- }
-}
-
-static int fts5ApiPhraseFirst(
- Fts5Context *pCtx,
- int iPhrase,
- Fts5PhraseIter *pIter,
- int *piCol, int *piOff
-){
- Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- int n;
- int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
- if( rc==SQLITE_OK ){
- pIter->b = &pIter->a[n];
- *piCol = 0;
- *piOff = 0;
- fts5ApiPhraseNext(pCtx, pIter, piCol, piOff);
- }
- return rc;
-}
-
-static void fts5ApiPhraseNextColumn(
- Fts5Context *pCtx,
- Fts5PhraseIter *pIter,
- int *piCol
-){
- Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
-
- if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
- if( pIter->a>=pIter->b ){
- *piCol = -1;
- }else{
- int iIncr;
- pIter->a += fts5GetVarint32(&pIter->a[0], iIncr);
- *piCol += (iIncr-2);
- }
- }else{
- while( 1 ){
- int dummy;
- if( pIter->a>=pIter->b ){
- *piCol = -1;
- return;
- }
- if( pIter->a[0]==0x01 ) break;
- pIter->a += fts5GetVarint32(pIter->a, dummy);
- }
- pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
- }
-}
-
-static int fts5ApiPhraseFirstColumn(
- Fts5Context *pCtx,
- int iPhrase,
- Fts5PhraseIter *pIter,
- int *piCol
-){
- int rc = SQLITE_OK;
- Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
-
- if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
- Fts5Sorter *pSorter = pCsr->pSorter;
- int n;
- if( pSorter ){
- int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
- n = pSorter->aIdx[iPhrase] - i1;
- pIter->a = &pSorter->aPoslist[i1];
- }else{
- rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n);
- }
- if( rc==SQLITE_OK ){
- pIter->b = &pIter->a[n];
- *piCol = 0;
- fts5ApiPhraseNextColumn(pCtx, pIter, piCol);
- }
- }else{
- int n;
- rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
- if( rc==SQLITE_OK ){
- pIter->b = &pIter->a[n];
- if( n<=0 ){
- *piCol = -1;
- }else if( pIter->a[0]==0x01 ){
- pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
- }else{
- *piCol = 0;
- }
- }
- }
-
- return rc;
-}
-
-
-static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
- int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
-);
-
-static const Fts5ExtensionApi sFts5Api = {
- 2, /* iVersion */
- fts5ApiUserData,
- fts5ApiColumnCount,
- fts5ApiRowCount,
- fts5ApiColumnTotalSize,
- fts5ApiTokenize,
- fts5ApiPhraseCount,
- fts5ApiPhraseSize,
- fts5ApiInstCount,
- fts5ApiInst,
- fts5ApiRowid,
- fts5ApiColumnText,
- fts5ApiColumnSize,
- fts5ApiQueryPhrase,
- fts5ApiSetAuxdata,
- fts5ApiGetAuxdata,
- fts5ApiPhraseFirst,
- fts5ApiPhraseNext,
- fts5ApiPhraseFirstColumn,
- fts5ApiPhraseNextColumn,
-};
-
-/*
-** Implementation of API function xQueryPhrase().
-*/
-static int fts5ApiQueryPhrase(
- Fts5Context *pCtx,
- int iPhrase,
- void *pUserData,
- int(*xCallback)(const Fts5ExtensionApi*, Fts5Context*, void*)
-){
- Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
- int rc;
- Fts5Cursor *pNew = 0;
-
- rc = fts5OpenMethod(pCsr->base.pVtab, (sqlite3_vtab_cursor**)&pNew);
- if( rc==SQLITE_OK ){
- pNew->ePlan = FTS5_PLAN_MATCH;
- pNew->iFirstRowid = SMALLEST_INT64;
- pNew->iLastRowid = LARGEST_INT64;
- pNew->base.pVtab = (sqlite3_vtab*)pTab;
- rc = sqlite3Fts5ExprClonePhrase(pCsr->pExpr, iPhrase, &pNew->pExpr);
- }
-
- if( rc==SQLITE_OK ){
- for(rc = fts5CursorFirst(pTab, pNew, 0);
- rc==SQLITE_OK && CsrFlagTest(pNew, FTS5CSR_EOF)==0;
- rc = fts5NextMethod((sqlite3_vtab_cursor*)pNew)
- ){
- rc = xCallback(&sFts5Api, (Fts5Context*)pNew, pUserData);
- if( rc!=SQLITE_OK ){
- if( rc==SQLITE_DONE ) rc = SQLITE_OK;
- break;
- }
- }
- }
-
- fts5CloseMethod((sqlite3_vtab_cursor*)pNew);
- return rc;
-}
-
-static void fts5ApiInvoke(
- Fts5Auxiliary *pAux,
- Fts5Cursor *pCsr,
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- assert( pCsr->pAux==0 );
- pCsr->pAux = pAux;
- pAux->xFunc(&sFts5Api, (Fts5Context*)pCsr, context, argc, argv);
- pCsr->pAux = 0;
-}
-
-static Fts5Cursor *fts5CursorFromCsrid(Fts5Global *pGlobal, i64 iCsrId){
- Fts5Cursor *pCsr;
- for(pCsr=pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
- if( pCsr->iCsrId==iCsrId ) break;
- }
- return pCsr;
-}
-
-static void fts5ApiCallback(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
-
- Fts5Auxiliary *pAux;
- Fts5Cursor *pCsr;
- i64 iCsrId;
-
- assert( argc>=1 );
- pAux = (Fts5Auxiliary*)sqlite3_user_data(context);
- iCsrId = sqlite3_value_int64(argv[0]);
-
- pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId);
- if( pCsr==0 ){
- char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId);
- sqlite3_result_error(context, zErr, -1);
- sqlite3_free(zErr);
- }else{
- fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]);
- }
-}
-
-
-/*
-** Given cursor id iId, return a pointer to the corresponding Fts5Index
-** object. Or NULL If the cursor id does not exist.
-**
-** If successful, set *ppConfig to point to the associated config object
-** before returning.
-*/
-static Fts5Index *sqlite3Fts5IndexFromCsrid(
- Fts5Global *pGlobal, /* FTS5 global context for db handle */
- i64 iCsrId, /* Id of cursor to find */
- Fts5Config **ppConfig /* OUT: Configuration object */
-){
- Fts5Cursor *pCsr;
- Fts5Table *pTab;
-
- pCsr = fts5CursorFromCsrid(pGlobal, iCsrId);
- pTab = (Fts5Table*)pCsr->base.pVtab;
- *ppConfig = pTab->pConfig;
-
- return pTab->pIndex;
-}
-
-/*
-** Return a "position-list blob" corresponding to the current position of
-** cursor pCsr via sqlite3_result_blob(). A position-list blob contains
-** the current position-list for each phrase in the query associated with
-** cursor pCsr.
-**
-** A position-list blob begins with (nPhrase-1) varints, where nPhrase is
-** the number of phrases in the query. Following the varints are the
-** concatenated position lists for each phrase, in order.
-**
-** The first varint (if it exists) contains the size of the position list
-** for phrase 0. The second (same disclaimer) contains the size of position
-** list 1. And so on. There is no size field for the final position list,
-** as it can be derived from the total size of the blob.
-*/
-static int fts5PoslistBlob(sqlite3_context *pCtx, Fts5Cursor *pCsr){
- int i;
- int rc = SQLITE_OK;
- int nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
- Fts5Buffer val;
-
- memset(&val, 0, sizeof(Fts5Buffer));
- switch( ((Fts5Table*)(pCsr->base.pVtab))->pConfig->eDetail ){
- case FTS5_DETAIL_FULL:
-
- /* Append the varints */
- for(i=0; i<(nPhrase-1); i++){
- const u8 *dummy;
- int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy);
- sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
- }
-
- /* Append the position lists */
- for(i=0; i<nPhrase; i++){
- const u8 *pPoslist;
- int nPoslist;
- nPoslist = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &pPoslist);
- sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
- }
- break;
-
- case FTS5_DETAIL_COLUMNS:
-
- /* Append the varints */
- for(i=0; rc==SQLITE_OK && i<(nPhrase-1); i++){
- const u8 *dummy;
- int nByte;
- rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &dummy, &nByte);
- sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
- }
-
- /* Append the position lists */
- for(i=0; rc==SQLITE_OK && i<nPhrase; i++){
- const u8 *pPoslist;
- int nPoslist;
- rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, i, &pPoslist, &nPoslist);
- sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
- }
- break;
-
- default:
- break;
- }
-
- sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free);
- return rc;
-}
-
-/*
-** This is the xColumn method, called by SQLite to request a value from
-** the row that the supplied cursor currently points to.
-*/
-static int fts5ColumnMethod(
- sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
- sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
- int iCol /* Index of column to read value from */
-){
- Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
- Fts5Config *pConfig = pTab->pConfig;
- Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
- int rc = SQLITE_OK;
-
- assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
-
- if( pCsr->ePlan==FTS5_PLAN_SPECIAL ){
- if( iCol==pConfig->nCol ){
- sqlite3_result_int64(pCtx, pCsr->iSpecial);
- }
- }else
-
- if( iCol==pConfig->nCol ){
- /* User is requesting the value of the special column with the same name
- ** as the table. Return the cursor integer id number. This value is only
- ** useful in that it may be passed as the first argument to an FTS5
- ** auxiliary function. */
- sqlite3_result_int64(pCtx, pCsr->iCsrId);
- }else if( iCol==pConfig->nCol+1 ){
-
- /* The value of the "rank" column. */
- if( pCsr->ePlan==FTS5_PLAN_SOURCE ){
- fts5PoslistBlob(pCtx, pCsr);
- }else if(
- pCsr->ePlan==FTS5_PLAN_MATCH
- || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
- ){
- if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){
- fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
- }
- }
- }else if( !fts5IsContentless(pTab) ){
- rc = fts5SeekCursor(pCsr, 1);
- if( rc==SQLITE_OK ){
- sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
- }
- }
- return rc;
-}
-
-
-/*
-** This routine implements the xFindFunction method for the FTS3
-** virtual table.
-*/
-static int fts5FindFunctionMethod(
- sqlite3_vtab *pVtab, /* Virtual table handle */
- int nUnused, /* Number of SQL function arguments */
- const char *zName, /* Name of SQL function */
- void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */
- void **ppArg /* OUT: User data for *pxFunc */
-){
- Fts5Table *pTab = (Fts5Table*)pVtab;
- Fts5Auxiliary *pAux;
-
- UNUSED_PARAM(nUnused);
- pAux = fts5FindAuxiliary(pTab, zName);
- if( pAux ){
- *pxFunc = fts5ApiCallback;
- *ppArg = (void*)pAux;
- return 1;
- }
-
- /* No function of the specified name was found. Return 0. */
- return 0;
-}
-
-/*
-** Implementation of FTS5 xRename method. Rename an fts5 table.
-*/
-static int fts5RenameMethod(
- sqlite3_vtab *pVtab, /* Virtual table handle */
- const char *zName /* New name of table */
-){
- Fts5Table *pTab = (Fts5Table*)pVtab;
- return sqlite3Fts5StorageRename(pTab->pStorage, zName);
-}
-
-/*
-** The xSavepoint() method.
-**
-** Flush the contents of the pending-terms table to disk.
-*/
-static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
- Fts5Table *pTab = (Fts5Table*)pVtab;
- UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
- fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
- fts5TripCursors(pTab);
- return sqlite3Fts5StorageSync(pTab->pStorage, 0);
-}
-
-/*
-** The xRelease() method.
-**
-** This is a no-op.
-*/
-static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
- Fts5Table *pTab = (Fts5Table*)pVtab;
- UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
- fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
- fts5TripCursors(pTab);
- return sqlite3Fts5StorageSync(pTab->pStorage, 0);
-}
-
-/*
-** The xRollbackTo() method.
-**
-** Discard the contents of the pending terms table.
-*/
-static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
- Fts5Table *pTab = (Fts5Table*)pVtab;
- UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
- fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
- fts5TripCursors(pTab);
- return sqlite3Fts5StorageRollback(pTab->pStorage);
-}
-
-/*
-** Register a new auxiliary function with global context pGlobal.
-*/
-static int fts5CreateAux(
- fts5_api *pApi, /* Global context (one per db handle) */
- const char *zName, /* Name of new function */
- void *pUserData, /* User data for aux. function */
- fts5_extension_function xFunc, /* Aux. function implementation */
- void(*xDestroy)(void*) /* Destructor for pUserData */
-){
- Fts5Global *pGlobal = (Fts5Global*)pApi;
- int rc = sqlite3_overload_function(pGlobal->db, zName, -1);
- if( rc==SQLITE_OK ){
- Fts5Auxiliary *pAux;
- int nName; /* Size of zName in bytes, including \0 */
- int nByte; /* Bytes of space to allocate */
-
- nName = (int)strlen(zName) + 1;
- nByte = sizeof(Fts5Auxiliary) + nName;
- pAux = (Fts5Auxiliary*)sqlite3_malloc(nByte);
- if( pAux ){
- memset(pAux, 0, nByte);
- pAux->zFunc = (char*)&pAux[1];
- memcpy(pAux->zFunc, zName, nName);
- pAux->pGlobal = pGlobal;
- pAux->pUserData = pUserData;
- pAux->xFunc = xFunc;
- pAux->xDestroy = xDestroy;
- pAux->pNext = pGlobal->pAux;
- pGlobal->pAux = pAux;
- }else{
- rc = SQLITE_NOMEM;
- }
- }
-
- return rc;
-}
-
-/*
-** Register a new tokenizer. This is the implementation of the
-** fts5_api.xCreateTokenizer() method.
-*/
-static int fts5CreateTokenizer(
- fts5_api *pApi, /* Global context (one per db handle) */
- const char *zName, /* Name of new function */
- void *pUserData, /* User data for aux. function */
- fts5_tokenizer *pTokenizer, /* Tokenizer implementation */
- void(*xDestroy)(void*) /* Destructor for pUserData */
-){
- Fts5Global *pGlobal = (Fts5Global*)pApi;
- Fts5TokenizerModule *pNew;
- int nName; /* Size of zName and its \0 terminator */
- int nByte; /* Bytes of space to allocate */
- int rc = SQLITE_OK;
-
- nName = (int)strlen(zName) + 1;
- nByte = sizeof(Fts5TokenizerModule) + nName;
- pNew = (Fts5TokenizerModule*)sqlite3_malloc(nByte);
- if( pNew ){
- memset(pNew, 0, nByte);
- pNew->zName = (char*)&pNew[1];
- memcpy(pNew->zName, zName, nName);
- pNew->pUserData = pUserData;
- pNew->x = *pTokenizer;
- pNew->xDestroy = xDestroy;
- pNew->pNext = pGlobal->pTok;
- pGlobal->pTok = pNew;
- if( pNew->pNext==0 ){
- pGlobal->pDfltTok = pNew;
- }
- }else{
- rc = SQLITE_NOMEM;
- }
-
- return rc;
-}
-
-static Fts5TokenizerModule *fts5LocateTokenizer(
- Fts5Global *pGlobal,
- const char *zName
-){
- Fts5TokenizerModule *pMod = 0;
-
- if( zName==0 ){
- pMod = pGlobal->pDfltTok;
- }else{
- for(pMod=pGlobal->pTok; pMod; pMod=pMod->pNext){
- if( sqlite3_stricmp(zName, pMod->zName)==0 ) break;
- }
- }
-
- return pMod;
-}
-
-/*
-** Find a tokenizer. This is the implementation of the
-** fts5_api.xFindTokenizer() method.
-*/
-static int fts5FindTokenizer(
- fts5_api *pApi, /* Global context (one per db handle) */
- const char *zName, /* Name of new function */
- void **ppUserData,
- fts5_tokenizer *pTokenizer /* Populate this object */
-){
- int rc = SQLITE_OK;
- Fts5TokenizerModule *pMod;
-
- pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName);
- if( pMod ){
- *pTokenizer = pMod->x;
- *ppUserData = pMod->pUserData;
- }else{
- memset(pTokenizer, 0, sizeof(fts5_tokenizer));
- rc = SQLITE_ERROR;
- }
-
- return rc;
-}
-
-static int sqlite3Fts5GetTokenizer(
- Fts5Global *pGlobal,
- const char **azArg,
- int nArg,
- Fts5Tokenizer **ppTok,
- fts5_tokenizer **ppTokApi,
- char **pzErr
-){
- Fts5TokenizerModule *pMod;
- int rc = SQLITE_OK;
-
- pMod = fts5LocateTokenizer(pGlobal, nArg==0 ? 0 : azArg[0]);
- if( pMod==0 ){
- assert( nArg>0 );
- rc = SQLITE_ERROR;
- *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
- }else{
- rc = pMod->x.xCreate(pMod->pUserData, &azArg[1], (nArg?nArg-1:0), ppTok);
- *ppTokApi = &pMod->x;
- if( rc!=SQLITE_OK && pzErr ){
- *pzErr = sqlite3_mprintf("error in tokenizer constructor");
- }
- }
-
- if( rc!=SQLITE_OK ){
- *ppTokApi = 0;
- *ppTok = 0;
- }
-
- return rc;
-}
-
-static void fts5ModuleDestroy(void *pCtx){
- Fts5TokenizerModule *pTok, *pNextTok;
- Fts5Auxiliary *pAux, *pNextAux;
- Fts5Global *pGlobal = (Fts5Global*)pCtx;
-
- for(pAux=pGlobal->pAux; pAux; pAux=pNextAux){
- pNextAux = pAux->pNext;
- if( pAux->xDestroy ) pAux->xDestroy(pAux->pUserData);
- sqlite3_free(pAux);
- }
-
- for(pTok=pGlobal->pTok; pTok; pTok=pNextTok){
- pNextTok = pTok->pNext;
- if( pTok->xDestroy ) pTok->xDestroy(pTok->pUserData);
- sqlite3_free(pTok);
- }
-
- sqlite3_free(pGlobal);
-}
-
-static void fts5Fts5Func(
- sqlite3_context *pCtx, /* Function call context */
- int nArg, /* Number of args */
- sqlite3_value **apUnused /* Function arguments */
-){
- Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx);
- char buf[8];
- UNUSED_PARAM2(nArg, apUnused);
- assert( nArg==0 );
- assert( sizeof(buf)>=sizeof(pGlobal) );
- memcpy(buf, (void*)&pGlobal, sizeof(pGlobal));
- sqlite3_result_blob(pCtx, buf, sizeof(pGlobal), SQLITE_TRANSIENT);
-}
-
-/*
-** Implementation of fts5_source_id() function.
-*/
-static void fts5SourceIdFunc(
- sqlite3_context *pCtx, /* Function call context */
- int nArg, /* Number of args */
- sqlite3_value **apUnused /* Function arguments */
-){
- assert( nArg==0 );
- UNUSED_PARAM2(nArg, apUnused);
- sqlite3_result_text(pCtx, "fts5: 2016-05-18 10:57:30 fc49f556e48970561d7ab6a2f24fdd7d9eb81ff2", -1, SQLITE_TRANSIENT);
-}
-
-static int fts5Init(sqlite3 *db){
- static const sqlite3_module fts5Mod = {
- /* iVersion */ 2,
- /* xCreate */ fts5CreateMethod,
- /* xConnect */ fts5ConnectMethod,
- /* xBestIndex */ fts5BestIndexMethod,
- /* xDisconnect */ fts5DisconnectMethod,
- /* xDestroy */ fts5DestroyMethod,
- /* xOpen */ fts5OpenMethod,
- /* xClose */ fts5CloseMethod,
- /* xFilter */ fts5FilterMethod,
- /* xNext */ fts5NextMethod,
- /* xEof */ fts5EofMethod,
- /* xColumn */ fts5ColumnMethod,
- /* xRowid */ fts5RowidMethod,
- /* xUpdate */ fts5UpdateMethod,
- /* xBegin */ fts5BeginMethod,
- /* xSync */ fts5SyncMethod,
- /* xCommit */ fts5CommitMethod,
- /* xRollback */ fts5RollbackMethod,
- /* xFindFunction */ fts5FindFunctionMethod,
- /* xRename */ fts5RenameMethod,
- /* xSavepoint */ fts5SavepointMethod,
- /* xRelease */ fts5ReleaseMethod,
- /* xRollbackTo */ fts5RollbackToMethod,
- };
-
- int rc;
- Fts5Global *pGlobal = 0;
-
- pGlobal = (Fts5Global*)sqlite3_malloc(sizeof(Fts5Global));
- if( pGlobal==0 ){
- rc = SQLITE_NOMEM;
- }else{
- void *p = (void*)pGlobal;
- memset(pGlobal, 0, sizeof(Fts5Global));
- pGlobal->db = db;
- pGlobal->api.iVersion = 2;
- pGlobal->api.xCreateFunction = fts5CreateAux;
- pGlobal->api.xCreateTokenizer = fts5CreateTokenizer;
- pGlobal->api.xFindTokenizer = fts5FindTokenizer;
- rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy);
- if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db);
- if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db);
- if( rc==SQLITE_OK ) rc = sqlite3Fts5AuxInit(&pGlobal->api);
- if( rc==SQLITE_OK ) rc = sqlite3Fts5TokenizerInit(&pGlobal->api);
- if( rc==SQLITE_OK ) rc = sqlite3Fts5VocabInit(pGlobal, db);
- if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(
- db, "fts5", 0, SQLITE_UTF8, p, fts5Fts5Func, 0, 0
- );
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(
- db, "fts5_source_id", 0, SQLITE_UTF8, p, fts5SourceIdFunc, 0, 0
- );
- }
- }
-
- /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
- ** fts5_test_mi.c is compiled and linked into the executable. And call
- ** its entry point to enable the matchinfo() demo. */
-#ifdef SQLITE_FTS5_ENABLE_TEST_MI
- if( rc==SQLITE_OK ){
- extern int sqlite3Fts5TestRegisterMatchinfo(sqlite3*);
- rc = sqlite3Fts5TestRegisterMatchinfo(db);
- }
-#endif
-
- return rc;
-}
-
-/*
-** The following functions are used to register the module with SQLite. If
-** this module is being built as part of the SQLite core (SQLITE_CORE is
-** defined), then sqlite3_open() will call sqlite3Fts5Init() directly.
-**
-** Or, if this module is being built as a loadable extension,
-** sqlite3Fts5Init() is omitted and the two standard entry points
-** sqlite3_fts_init() and sqlite3_fts5_init() defined instead.
-*/
-#ifndef SQLITE_CORE
-#ifdef _WIN32
-__declspec(dllexport)
-#endif
-SQLITE_API int SQLITE_STDCALL sqlite3_fts_init(
- sqlite3 *db,
- char **pzErrMsg,
- const sqlite3_api_routines *pApi
-){
- SQLITE_EXTENSION_INIT2(pApi);
- (void)pzErrMsg; /* Unused parameter */
- return fts5Init(db);
-}
-
-#ifdef _WIN32
-__declspec(dllexport)
-#endif
-SQLITE_API int SQLITE_STDCALL sqlite3_fts5_init(
- sqlite3 *db,
- char **pzErrMsg,
- const sqlite3_api_routines *pApi
-){
- SQLITE_EXTENSION_INIT2(pApi);
- (void)pzErrMsg; /* Unused parameter */
- return fts5Init(db);
-}
-#else
-SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3 *db){
- return fts5Init(db);
-}
-#endif
-
-/*
-** 2014 May 31
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-*/
-
-
-
-/* #include "fts5Int.h" */
-
-struct Fts5Storage {
- Fts5Config *pConfig;
- Fts5Index *pIndex;
- int bTotalsValid; /* True if nTotalRow/aTotalSize[] are valid */
- i64 nTotalRow; /* Total number of rows in FTS table */
- i64 *aTotalSize; /* Total sizes of each column */
- sqlite3_stmt *aStmt[11];
-};
-
-
-#if FTS5_STMT_SCAN_ASC!=0
-# error "FTS5_STMT_SCAN_ASC mismatch"
-#endif
-#if FTS5_STMT_SCAN_DESC!=1
-# error "FTS5_STMT_SCAN_DESC mismatch"
-#endif
-#if FTS5_STMT_LOOKUP!=2
-# error "FTS5_STMT_LOOKUP mismatch"
-#endif
-
-#define FTS5_STMT_INSERT_CONTENT 3
-#define FTS5_STMT_REPLACE_CONTENT 4
-#define FTS5_STMT_DELETE_CONTENT 5
-#define FTS5_STMT_REPLACE_DOCSIZE 6
-#define FTS5_STMT_DELETE_DOCSIZE 7
-#define FTS5_STMT_LOOKUP_DOCSIZE 8
-#define FTS5_STMT_REPLACE_CONFIG 9
-#define FTS5_STMT_SCAN 10
-
-/*
-** Prepare the two insert statements - Fts5Storage.pInsertContent and
-** Fts5Storage.pInsertDocsize - if they have not already been prepared.
-** Return SQLITE_OK if successful, or an SQLite error code if an error
-** occurs.
-*/
-static int fts5StorageGetStmt(
- Fts5Storage *p, /* Storage handle */
- int eStmt, /* FTS5_STMT_XXX constant */
- sqlite3_stmt **ppStmt, /* OUT: Prepared statement handle */
- char **pzErrMsg /* OUT: Error message (if any) */
-){
- int rc = SQLITE_OK;
-
- /* If there is no %_docsize table, there should be no requests for
- ** statements to operate on it. */
- assert( p->pConfig->bColumnsize || (
- eStmt!=FTS5_STMT_REPLACE_DOCSIZE
- && eStmt!=FTS5_STMT_DELETE_DOCSIZE
- && eStmt!=FTS5_STMT_LOOKUP_DOCSIZE
- ));
-
- assert( eStmt>=0 && eStmt<ArraySize(p->aStmt) );
- if( p->aStmt[eStmt]==0 ){
- const char *azStmt[] = {
- "SELECT %s FROM %s T WHERE T.%Q >= ? AND T.%Q <= ? ORDER BY T.%Q ASC",
- "SELECT %s FROM %s T WHERE T.%Q <= ? AND T.%Q >= ? ORDER BY T.%Q DESC",
- "SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP */
-
- "INSERT INTO %Q.'%q_content' VALUES(%s)", /* INSERT_CONTENT */
- "REPLACE INTO %Q.'%q_content' VALUES(%s)", /* REPLACE_CONTENT */
- "DELETE FROM %Q.'%q_content' WHERE id=?", /* DELETE_CONTENT */
- "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)", /* REPLACE_DOCSIZE */
- "DELETE FROM %Q.'%q_docsize' WHERE id=?", /* DELETE_DOCSIZE */
-
- "SELECT sz FROM %Q.'%q_docsize' WHERE id=?", /* LOOKUP_DOCSIZE */
-
- "REPLACE INTO %Q.'%q_config' VALUES(?,?)", /* REPLACE_CONFIG */
- "SELECT %s FROM %s AS T", /* SCAN */
- };
- Fts5Config *pC = p->pConfig;
- char *zSql = 0;
-
- switch( eStmt ){
- case FTS5_STMT_SCAN:
- zSql = sqlite3_mprintf(azStmt[eStmt],
- pC->zContentExprlist, pC->zContent
- );
- break;
-
- case FTS5_STMT_SCAN_ASC:
- case FTS5_STMT_SCAN_DESC:
- zSql = sqlite3_mprintf(azStmt[eStmt], pC->zContentExprlist,
- pC->zContent, pC->zContentRowid, pC->zContentRowid,
- pC->zContentRowid
- );
- break;
-
- case FTS5_STMT_LOOKUP:
- zSql = sqlite3_mprintf(azStmt[eStmt],
- pC->zContentExprlist, pC->zContent, pC->zContentRowid
- );
- break;
-
- case FTS5_STMT_INSERT_CONTENT:
- case FTS5_STMT_REPLACE_CONTENT: {
- int nCol = pC->nCol + 1;
- char *zBind;
- int i;
-
- zBind = sqlite3_malloc(1 + nCol*2);
- if( zBind ){
- for(i=0; i<nCol; i++){
- zBind[i*2] = '?';
- zBind[i*2 + 1] = ',';
- }
- zBind[i*2-1] = '\0';
- zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName, zBind);
- sqlite3_free(zBind);
- }
- break;
- }
-
- default:
- zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName);
- break;
- }
-
- if( zSql==0 ){
- rc = SQLITE_NOMEM;
- }else{
- rc = sqlite3_prepare_v2(pC->db, zSql, -1, &p->aStmt[eStmt], 0);
- sqlite3_free(zSql);
- if( rc!=SQLITE_OK && pzErrMsg ){
- *pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db));
- }
- }
- }
-
- *ppStmt = p->aStmt[eStmt];
- sqlite3_reset(*ppStmt);
- return rc;
-}
-
-
-static int fts5ExecPrintf(
- sqlite3 *db,
- char **pzErr,
- const char *zFormat,
- ...
-){
- int rc;
- va_list ap; /* ... printf arguments */
- char *zSql;
-
- va_start(ap, zFormat);
- zSql = sqlite3_vmprintf(zFormat, ap);
-
- if( zSql==0 ){
- rc = SQLITE_NOMEM;
- }else{
- rc = sqlite3_exec(db, zSql, 0, 0, pzErr);
- sqlite3_free(zSql);
- }
-
- va_end(ap);
- return rc;
-}
-
-/*
-** Drop all shadow tables. Return SQLITE_OK if successful or an SQLite error
-** code otherwise.
-*/
-static int sqlite3Fts5DropAll(Fts5Config *pConfig){
- int rc = fts5ExecPrintf(pConfig->db, 0,
- "DROP TABLE IF EXISTS %Q.'%q_data';"
- "DROP TABLE IF EXISTS %Q.'%q_idx';"
- "DROP TABLE IF EXISTS %Q.'%q_config';",
- pConfig->zDb, pConfig->zName,
- pConfig->zDb, pConfig->zName,
- pConfig->zDb, pConfig->zName
- );
- if( rc==SQLITE_OK && pConfig->bColumnsize ){
- rc = fts5ExecPrintf(pConfig->db, 0,
- "DROP TABLE IF EXISTS %Q.'%q_docsize';",
- pConfig->zDb, pConfig->zName
- );
- }
- if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
- rc = fts5ExecPrintf(pConfig->db, 0,
- "DROP TABLE IF EXISTS %Q.'%q_content';",
- pConfig->zDb, pConfig->zName
- );
- }
- return rc;
-}
-
-static void fts5StorageRenameOne(
- Fts5Config *pConfig, /* Current FTS5 configuration */
- int *pRc, /* IN/OUT: Error code */
- const char *zTail, /* Tail of table name e.g. "data", "config" */
- const char *zName /* New name of FTS5 table */
-){
- if( *pRc==SQLITE_OK ){
- *pRc = fts5ExecPrintf(pConfig->db, 0,
- "ALTER TABLE %Q.'%q_%s' RENAME TO '%q_%s';",
- pConfig->zDb, pConfig->zName, zTail, zName, zTail
- );
- }
-}
-
-static int sqlite3Fts5StorageRename(Fts5Storage *pStorage, const char *zName){
- Fts5Config *pConfig = pStorage->pConfig;
- int rc = sqlite3Fts5StorageSync(pStorage, 1);
-
- fts5StorageRenameOne(pConfig, &rc, "data", zName);
- fts5StorageRenameOne(pConfig, &rc, "idx", zName);
- fts5StorageRenameOne(pConfig, &rc, "config", zName);
- if( pConfig->bColumnsize ){
- fts5StorageRenameOne(pConfig, &rc, "docsize", zName);
- }
- if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
- fts5StorageRenameOne(pConfig, &rc, "content", zName);
- }
- return rc;
-}
-
-/*
-** Create the shadow table named zPost, with definition zDefn. Return
-** SQLITE_OK if successful, or an SQLite error code otherwise.
-*/
-static int sqlite3Fts5CreateTable(
- Fts5Config *pConfig, /* FTS5 configuration */
- const char *zPost, /* Shadow table to create (e.g. "content") */
- const char *zDefn, /* Columns etc. for shadow table */
- int bWithout, /* True for without rowid */
- char **pzErr /* OUT: Error message */
-){
- int rc;
- char *zErr = 0;
-
- rc = fts5ExecPrintf(pConfig->db, &zErr, "CREATE TABLE %Q.'%q_%q'(%s)%s",
- pConfig->zDb, pConfig->zName, zPost, zDefn, bWithout?" WITHOUT ROWID":""
- );
- if( zErr ){
- *pzErr = sqlite3_mprintf(
- "fts5: error creating shadow table %q_%s: %s",
- pConfig->zName, zPost, zErr
- );
- sqlite3_free(zErr);
- }
-
- return rc;
-}
-
-/*
-** Open a new Fts5Index handle. If the bCreate argument is true, create
-** and initialize the underlying tables
-**
-** If successful, set *pp to point to the new object and return SQLITE_OK.
-** Otherwise, set *pp to NULL and return an SQLite error code.
-*/
-static int sqlite3Fts5StorageOpen(
- Fts5Config *pConfig,
- Fts5Index *pIndex,
- int bCreate,
- Fts5Storage **pp,
- char **pzErr /* OUT: Error message */
-){
- int rc = SQLITE_OK;
- Fts5Storage *p; /* New object */
- int nByte; /* Bytes of space to allocate */
-
- nByte = sizeof(Fts5Storage) /* Fts5Storage object */
- + pConfig->nCol * sizeof(i64); /* Fts5Storage.aTotalSize[] */
- *pp = p = (Fts5Storage*)sqlite3_malloc(nByte);
- if( !p ) return SQLITE_NOMEM;
-
- memset(p, 0, nByte);
- p->aTotalSize = (i64*)&p[1];
- p->pConfig = pConfig;
- p->pIndex = pIndex;
-
- if( bCreate ){
- if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
- int nDefn = 32 + pConfig->nCol*10;
- char *zDefn = sqlite3_malloc(32 + pConfig->nCol * 10);
- if( zDefn==0 ){
- rc = SQLITE_NOMEM;
- }else{
- int i;
- int iOff;
- sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY");
- iOff = (int)strlen(zDefn);
- for(i=0; i<pConfig->nCol; i++){
- sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
- iOff += (int)strlen(&zDefn[iOff]);
- }
- rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr);
- }
- sqlite3_free(zDefn);
- }
-
- if( rc==SQLITE_OK && pConfig->bColumnsize ){
- rc = sqlite3Fts5CreateTable(
- pConfig, "docsize", "id INTEGER PRIMARY KEY, sz BLOB", 0, pzErr
- );
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5CreateTable(
- pConfig, "config", "k PRIMARY KEY, v", 1, pzErr
- );
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5StorageConfigValue(p, "version", 0, FTS5_CURRENT_VERSION);
- }
- }
-
- if( rc ){
- sqlite3Fts5StorageClose(p);
- *pp = 0;
- }
- return rc;
-}
-
-/*
-** Close a handle opened by an earlier call to sqlite3Fts5StorageOpen().
-*/
-static int sqlite3Fts5StorageClose(Fts5Storage *p){
- int rc = SQLITE_OK;
- if( p ){
- int i;
-
- /* Finalize all SQL statements */
- for(i=0; i<ArraySize(p->aStmt); i++){
- sqlite3_finalize(p->aStmt[i]);
- }
-
- sqlite3_free(p);
- }
- return rc;
-}
-
-typedef struct Fts5InsertCtx Fts5InsertCtx;
-struct Fts5InsertCtx {
- Fts5Storage *pStorage;
- int iCol;
- int szCol; /* Size of column value in tokens */
-};
-
-/*
-** Tokenization callback used when inserting tokens into the FTS index.
-*/
-static int fts5StorageInsertCallback(
- void *pContext, /* Pointer to Fts5InsertCtx object */
- int tflags,
- const char *pToken, /* Buffer containing token */
- int nToken, /* Size of token in bytes */
- int iUnused1, /* Start offset of token */
- int iUnused2 /* End offset of token */
-){
- Fts5InsertCtx *pCtx = (Fts5InsertCtx*)pContext;
- Fts5Index *pIdx = pCtx->pStorage->pIndex;
- UNUSED_PARAM2(iUnused1, iUnused2);
- if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
- if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
- pCtx->szCol++;
- }
- return sqlite3Fts5IndexWrite(pIdx, pCtx->iCol, pCtx->szCol-1, pToken, nToken);
-}
-
-/*
-** If a row with rowid iDel is present in the %_content table, add the
-** delete-markers to the FTS index necessary to delete it. Do not actually
-** remove the %_content row at this time though.
-*/
-static int fts5StorageDeleteFromIndex(
- Fts5Storage *p,
- i64 iDel,
- sqlite3_value **apVal
-){
- Fts5Config *pConfig = p->pConfig;
- sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */
- int rc; /* Return code */
- int rc2; /* sqlite3_reset() return code */
- int iCol;
- Fts5InsertCtx ctx;
-
- if( apVal==0 ){
- rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0);
- if( rc!=SQLITE_OK ) return rc;
- sqlite3_bind_int64(pSeek, 1, iDel);
- if( sqlite3_step(pSeek)!=SQLITE_ROW ){
- return sqlite3_reset(pSeek);
- }
- }
-
- ctx.pStorage = p;
- ctx.iCol = -1;
- rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
- for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
- if( pConfig->abUnindexed[iCol-1]==0 ){
- const char *zText;
- int nText;
- if( pSeek ){
- zText = (const char*)sqlite3_column_text(pSeek, iCol);
- nText = sqlite3_column_bytes(pSeek, iCol);
- }else{
- zText = (const char*)sqlite3_value_text(apVal[iCol-1]);
- nText = sqlite3_value_bytes(apVal[iCol-1]);
- }
- ctx.szCol = 0;
- rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
- zText, nText, (void*)&ctx, fts5StorageInsertCallback
- );
- p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
- }
- }
- p->nTotalRow--;
-
- rc2 = sqlite3_reset(pSeek);
- if( rc==SQLITE_OK ) rc = rc2;
- return rc;
-}
-
-
-/*
-** Insert a record into the %_docsize table. Specifically, do:
-**
-** INSERT OR REPLACE INTO %_docsize(id, sz) VALUES(iRowid, pBuf);
-**
-** If there is no %_docsize table (as happens if the columnsize=0 option
-** is specified when the FTS5 table is created), this function is a no-op.
-*/
-static int fts5StorageInsertDocsize(
- Fts5Storage *p, /* Storage module to write to */
- i64 iRowid, /* id value */
- Fts5Buffer *pBuf /* sz value */
-){
- int rc = SQLITE_OK;
- if( p->pConfig->bColumnsize ){
- sqlite3_stmt *pReplace = 0;
- rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0);
- if( rc==SQLITE_OK ){
- sqlite3_bind_int64(pReplace, 1, iRowid);
- sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
- sqlite3_step(pReplace);
- rc = sqlite3_reset(pReplace);
- }
- }
- return rc;
-}
-
-/*
-** Load the contents of the "averages" record from disk into the
-** p->nTotalRow and p->aTotalSize[] variables. If successful, and if
-** argument bCache is true, set the p->bTotalsValid flag to indicate
-** that the contents of aTotalSize[] and nTotalRow are valid until
-** further notice.
-**
-** Return SQLITE_OK if successful, or an SQLite error code if an error
-** occurs.
-*/
-static int fts5StorageLoadTotals(Fts5Storage *p, int bCache){
- int rc = SQLITE_OK;
- if( p->bTotalsValid==0 ){
- rc = sqlite3Fts5IndexGetAverages(p->pIndex, &p->nTotalRow, p->aTotalSize);
- p->bTotalsValid = bCache;
- }
- return rc;
-}
-
-/*
-** Store the current contents of the p->nTotalRow and p->aTotalSize[]
-** variables in the "averages" record on disk.
-**
-** Return SQLITE_OK if successful, or an SQLite error code if an error
-** occurs.
-*/
-static int fts5StorageSaveTotals(Fts5Storage *p){
- int nCol = p->pConfig->nCol;
- int i;
- Fts5Buffer buf;
- int rc = SQLITE_OK;
- memset(&buf, 0, sizeof(buf));
-
- sqlite3Fts5BufferAppendVarint(&rc, &buf, p->nTotalRow);
- for(i=0; i<nCol; i++){
- sqlite3Fts5BufferAppendVarint(&rc, &buf, p->aTotalSize[i]);
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5IndexSetAverages(p->pIndex, buf.p, buf.n);
- }
- sqlite3_free(buf.p);
-
- return rc;
-}
-
-/*
-** Remove a row from the FTS table.
-*/
-static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){
- Fts5Config *pConfig = p->pConfig;
- int rc;
- sqlite3_stmt *pDel = 0;
-
- assert( pConfig->eContent!=FTS5_CONTENT_NORMAL || apVal==0 );
- rc = fts5StorageLoadTotals(p, 1);
-
- /* Delete the index records */
- if( rc==SQLITE_OK ){
- rc = fts5StorageDeleteFromIndex(p, iDel, apVal);
- }
-
- /* Delete the %_docsize record */
- if( rc==SQLITE_OK && pConfig->bColumnsize ){
- rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0);
- if( rc==SQLITE_OK ){
- sqlite3_bind_int64(pDel, 1, iDel);
- sqlite3_step(pDel);
- rc = sqlite3_reset(pDel);
- }
- }
-
- /* Delete the %_content record */
- if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
- if( rc==SQLITE_OK ){
- rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0);
- }
- if( rc==SQLITE_OK ){
- sqlite3_bind_int64(pDel, 1, iDel);
- sqlite3_step(pDel);
- rc = sqlite3_reset(pDel);
- }
- }
-
- /* Write the averages record */
- if( rc==SQLITE_OK ){
- rc = fts5StorageSaveTotals(p);
- }
-
- return rc;
-}
-
-/*
-** Delete all entries in the FTS5 index.
-*/
-static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){
- Fts5Config *pConfig = p->pConfig;
- int rc;
-
- /* Delete the contents of the %_data and %_docsize tables. */
- rc = fts5ExecPrintf(pConfig->db, 0,
- "DELETE FROM %Q.'%q_data';"
- "DELETE FROM %Q.'%q_idx';",
- pConfig->zDb, pConfig->zName,
- pConfig->zDb, pConfig->zName
- );
- if( rc==SQLITE_OK && pConfig->bColumnsize ){
- rc = fts5ExecPrintf(pConfig->db, 0,
- "DELETE FROM %Q.'%q_docsize';",
- pConfig->zDb, pConfig->zName
- );
- }
-
- /* Reinitialize the %_data table. This call creates the initial structure
- ** and averages records. */
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5IndexReinit(p->pIndex);
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5StorageConfigValue(p, "version", 0, FTS5_CURRENT_VERSION);
- }
- return rc;
-}
-
-static int sqlite3Fts5StorageRebuild(Fts5Storage *p){
- Fts5Buffer buf = {0,0,0};
- Fts5Config *pConfig = p->pConfig;
- sqlite3_stmt *pScan = 0;
- Fts5InsertCtx ctx;
- int rc;
-
- memset(&ctx, 0, sizeof(Fts5InsertCtx));
- ctx.pStorage = p;
- rc = sqlite3Fts5StorageDeleteAll(p);
- if( rc==SQLITE_OK ){
- rc = fts5StorageLoadTotals(p, 1);
- }
-
- if( rc==SQLITE_OK ){
- rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0);
- }
-
- while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pScan) ){
- i64 iRowid = sqlite3_column_int64(pScan, 0);
-
- sqlite3Fts5BufferZero(&buf);
- rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
- for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
- ctx.szCol = 0;
- if( pConfig->abUnindexed[ctx.iCol]==0 ){
- rc = sqlite3Fts5Tokenize(pConfig,
- FTS5_TOKENIZE_DOCUMENT,
- (const char*)sqlite3_column_text(pScan, ctx.iCol+1),
- sqlite3_column_bytes(pScan, ctx.iCol+1),
- (void*)&ctx,
- fts5StorageInsertCallback
- );
- }
- sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
- p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
- }
- p->nTotalRow++;
-
- if( rc==SQLITE_OK ){
- rc = fts5StorageInsertDocsize(p, iRowid, &buf);
- }
- }
- sqlite3_free(buf.p);
-
- /* Write the averages record */
- if( rc==SQLITE_OK ){
- rc = fts5StorageSaveTotals(p);
- }
- return rc;
-}
-
-static int sqlite3Fts5StorageOptimize(Fts5Storage *p){
- return sqlite3Fts5IndexOptimize(p->pIndex);
-}
-
-static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge){
- return sqlite3Fts5IndexMerge(p->pIndex, nMerge);
-}
-
-static int sqlite3Fts5StorageReset(Fts5Storage *p){
- return sqlite3Fts5IndexReset(p->pIndex);
-}
-
-/*
-** Allocate a new rowid. This is used for "external content" tables when
-** a NULL value is inserted into the rowid column. The new rowid is allocated
-** by inserting a dummy row into the %_docsize table. The dummy will be
-** overwritten later.
-**
-** If the %_docsize table does not exist, SQLITE_MISMATCH is returned. In
-** this case the user is required to provide a rowid explicitly.
-*/
-static int fts5StorageNewRowid(Fts5Storage *p, i64 *piRowid){
- int rc = SQLITE_MISMATCH;
- if( p->pConfig->bColumnsize ){
- sqlite3_stmt *pReplace = 0;
- rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0);
- if( rc==SQLITE_OK ){
- sqlite3_bind_null(pReplace, 1);
- sqlite3_bind_null(pReplace, 2);
- sqlite3_step(pReplace);
- rc = sqlite3_reset(pReplace);
- }
- if( rc==SQLITE_OK ){
- *piRowid = sqlite3_last_insert_rowid(p->pConfig->db);
- }
- }
- return rc;
-}
-
-/*
-** Insert a new row into the FTS content table.
-*/
-static int sqlite3Fts5StorageContentInsert(
- Fts5Storage *p,
- sqlite3_value **apVal,
- i64 *piRowid
-){
- Fts5Config *pConfig = p->pConfig;
- int rc = SQLITE_OK;
-
- /* Insert the new row into the %_content table. */
- if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){
- if( sqlite3_value_type(apVal[1])==SQLITE_INTEGER ){
- *piRowid = sqlite3_value_int64(apVal[1]);
- }else{
- rc = fts5StorageNewRowid(p, piRowid);
- }
- }else{
- sqlite3_stmt *pInsert = 0; /* Statement to write %_content table */
- int i; /* Counter variable */
- rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0);
- for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
- rc = sqlite3_bind_value(pInsert, i, apVal[i]);
- }
- if( rc==SQLITE_OK ){
- sqlite3_step(pInsert);
- rc = sqlite3_reset(pInsert);
- }
- *piRowid = sqlite3_last_insert_rowid(pConfig->db);
- }
-
- return rc;
-}
-
-/*
-** Insert new entries into the FTS index and %_docsize table.
-*/
-static int sqlite3Fts5StorageIndexInsert(
- Fts5Storage *p,
- sqlite3_value **apVal,
- i64 iRowid
-){
- Fts5Config *pConfig = p->pConfig;
- int rc = SQLITE_OK; /* Return code */
- Fts5InsertCtx ctx; /* Tokenization callback context object */
- Fts5Buffer buf; /* Buffer used to build up %_docsize blob */
-
- memset(&buf, 0, sizeof(Fts5Buffer));
- ctx.pStorage = p;
- rc = fts5StorageLoadTotals(p, 1);
-
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
- }
- for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
- ctx.szCol = 0;
- if( pConfig->abUnindexed[ctx.iCol]==0 ){
- rc = sqlite3Fts5Tokenize(pConfig,
- FTS5_TOKENIZE_DOCUMENT,
- (const char*)sqlite3_value_text(apVal[ctx.iCol+2]),
- sqlite3_value_bytes(apVal[ctx.iCol+2]),
- (void*)&ctx,
- fts5StorageInsertCallback
- );
- }
- sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
- p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
- }
- p->nTotalRow++;
-
- /* Write the %_docsize record */
- if( rc==SQLITE_OK ){
- rc = fts5StorageInsertDocsize(p, iRowid, &buf);
- }
- sqlite3_free(buf.p);
-
- /* Write the averages record */
- if( rc==SQLITE_OK ){
- rc = fts5StorageSaveTotals(p);
- }
-
- return rc;
-}
-
-static int fts5StorageCount(Fts5Storage *p, const char *zSuffix, i64 *pnRow){
- Fts5Config *pConfig = p->pConfig;
- char *zSql;
- int rc;
-
- zSql = sqlite3_mprintf("SELECT count(*) FROM %Q.'%q_%s'",
- pConfig->zDb, pConfig->zName, zSuffix
- );
- if( zSql==0 ){
- rc = SQLITE_NOMEM;
- }else{
- sqlite3_stmt *pCnt = 0;
- rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pCnt, 0);
- if( rc==SQLITE_OK ){
- if( SQLITE_ROW==sqlite3_step(pCnt) ){
- *pnRow = sqlite3_column_int64(pCnt, 0);
- }
- rc = sqlite3_finalize(pCnt);
- }
- }
-
- sqlite3_free(zSql);
- return rc;
-}
-
-/*
-** Context object used by sqlite3Fts5StorageIntegrity().
-*/
-typedef struct Fts5IntegrityCtx Fts5IntegrityCtx;
-struct Fts5IntegrityCtx {
- i64 iRowid;
- int iCol;
- int szCol;
- u64 cksum;
- Fts5Termset *pTermset;
- Fts5Config *pConfig;
-};
-
-
-/*
-** Tokenization callback used by integrity check.
-*/
-static int fts5StorageIntegrityCallback(
- void *pContext, /* Pointer to Fts5IntegrityCtx object */
- int tflags,
- const char *pToken, /* Buffer containing token */
- int nToken, /* Size of token in bytes */
- int iUnused1, /* Start offset of token */
- int iUnused2 /* End offset of token */
-){
- Fts5IntegrityCtx *pCtx = (Fts5IntegrityCtx*)pContext;
- Fts5Termset *pTermset = pCtx->pTermset;
- int bPresent;
- int ii;
- int rc = SQLITE_OK;
- int iPos;
- int iCol;
-
- UNUSED_PARAM2(iUnused1, iUnused2);
- if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
-
- if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
- pCtx->szCol++;
- }
-
- switch( pCtx->pConfig->eDetail ){
- case FTS5_DETAIL_FULL:
- iPos = pCtx->szCol-1;
- iCol = pCtx->iCol;
- break;
-
- case FTS5_DETAIL_COLUMNS:
- iPos = pCtx->iCol;
- iCol = 0;
- break;
-
- default:
- assert( pCtx->pConfig->eDetail==FTS5_DETAIL_NONE );
- iPos = 0;
- iCol = 0;
- break;
- }
-
- rc = sqlite3Fts5TermsetAdd(pTermset, 0, pToken, nToken, &bPresent);
- if( rc==SQLITE_OK && bPresent==0 ){
- pCtx->cksum ^= sqlite3Fts5IndexEntryCksum(
- pCtx->iRowid, iCol, iPos, 0, pToken, nToken
- );
- }
-
- for(ii=0; rc==SQLITE_OK && ii<pCtx->pConfig->nPrefix; ii++){
- const int nChar = pCtx->pConfig->aPrefix[ii];
- int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar);
- if( nByte ){
- rc = sqlite3Fts5TermsetAdd(pTermset, ii+1, pToken, nByte, &bPresent);
- if( bPresent==0 ){
- pCtx->cksum ^= sqlite3Fts5IndexEntryCksum(
- pCtx->iRowid, iCol, iPos, ii+1, pToken, nByte
- );
- }
- }
- }
-
- return rc;
-}
-
-/*
-** Check that the contents of the FTS index match that of the %_content
-** table. Return SQLITE_OK if they do, or SQLITE_CORRUPT if not. Return
-** some other SQLite error code if an error occurs while attempting to
-** determine this.
-*/
-static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
- Fts5Config *pConfig = p->pConfig;
- int rc; /* Return code */
- int *aColSize; /* Array of size pConfig->nCol */
- i64 *aTotalSize; /* Array of size pConfig->nCol */
- Fts5IntegrityCtx ctx;
- sqlite3_stmt *pScan;
-
- memset(&ctx, 0, sizeof(Fts5IntegrityCtx));
- ctx.pConfig = p->pConfig;
- aTotalSize = (i64*)sqlite3_malloc(pConfig->nCol * (sizeof(int)+sizeof(i64)));
- if( !aTotalSize ) return SQLITE_NOMEM;
- aColSize = (int*)&aTotalSize[pConfig->nCol];
- memset(aTotalSize, 0, sizeof(i64) * pConfig->nCol);
-
- /* Generate the expected index checksum based on the contents of the
- ** %_content table. This block stores the checksum in ctx.cksum. */
- rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0);
- if( rc==SQLITE_OK ){
- int rc2;
- while( SQLITE_ROW==sqlite3_step(pScan) ){
- int i;
- ctx.iRowid = sqlite3_column_int64(pScan, 0);
- ctx.szCol = 0;
- if( pConfig->bColumnsize ){
- rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize);
- }
- if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){
- rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
- }
- for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
- if( pConfig->abUnindexed[i] ) continue;
- ctx.iCol = i;
- ctx.szCol = 0;
- if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
- rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5Tokenize(pConfig,
- FTS5_TOKENIZE_DOCUMENT,
- (const char*)sqlite3_column_text(pScan, i+1),
- sqlite3_column_bytes(pScan, i+1),
- (void*)&ctx,
- fts5StorageIntegrityCallback
- );
- }
- if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
- rc = FTS5_CORRUPT;
- }
- aTotalSize[i] += ctx.szCol;
- if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
- sqlite3Fts5TermsetFree(ctx.pTermset);
- ctx.pTermset = 0;
- }
- }
- sqlite3Fts5TermsetFree(ctx.pTermset);
- ctx.pTermset = 0;
-
- if( rc!=SQLITE_OK ) break;
- }
- rc2 = sqlite3_reset(pScan);
- if( rc==SQLITE_OK ) rc = rc2;
- }
-
- /* Test that the "totals" (sometimes called "averages") record looks Ok */
- if( rc==SQLITE_OK ){
- int i;
- rc = fts5StorageLoadTotals(p, 0);
- for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
- if( p->aTotalSize[i]!=aTotalSize[i] ) rc = FTS5_CORRUPT;
- }
- }
-
- /* Check that the %_docsize and %_content tables contain the expected
- ** number of rows. */
- if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
- i64 nRow = 0;
- rc = fts5StorageCount(p, "content", &nRow);
- if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
- }
- if( rc==SQLITE_OK && pConfig->bColumnsize ){
- i64 nRow = 0;
- rc = fts5StorageCount(p, "docsize", &nRow);
- if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
- }
-
- /* Pass the expected checksum down to the FTS index module. It will
- ** verify, amongst other things, that it matches the checksum generated by
- ** inspecting the index itself. */
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5IndexIntegrityCheck(p->pIndex, ctx.cksum);
- }
-
- sqlite3_free(aTotalSize);
- return rc;
-}
-
-/*
-** Obtain an SQLite statement handle that may be used to read data from the
-** %_content table.
-*/
-static int sqlite3Fts5StorageStmt(
- Fts5Storage *p,
- int eStmt,
- sqlite3_stmt **pp,
- char **pzErrMsg
-){
- int rc;
- assert( eStmt==FTS5_STMT_SCAN_ASC
- || eStmt==FTS5_STMT_SCAN_DESC
- || eStmt==FTS5_STMT_LOOKUP
- );
- rc = fts5StorageGetStmt(p, eStmt, pp, pzErrMsg);
- if( rc==SQLITE_OK ){
- assert( p->aStmt[eStmt]==*pp );
- p->aStmt[eStmt] = 0;
- }
- return rc;
-}
-
-/*
-** Release an SQLite statement handle obtained via an earlier call to
-** sqlite3Fts5StorageStmt(). The eStmt parameter passed to this function
-** must match that passed to the sqlite3Fts5StorageStmt() call.
-*/
-static void sqlite3Fts5StorageStmtRelease(
- Fts5Storage *p,
- int eStmt,
- sqlite3_stmt *pStmt
-){
- assert( eStmt==FTS5_STMT_SCAN_ASC
- || eStmt==FTS5_STMT_SCAN_DESC
- || eStmt==FTS5_STMT_LOOKUP
- );
- if( p->aStmt[eStmt]==0 ){
- sqlite3_reset(pStmt);
- p->aStmt[eStmt] = pStmt;
- }else{
- sqlite3_finalize(pStmt);
- }
-}
-
-static int fts5StorageDecodeSizeArray(
- int *aCol, int nCol, /* Array to populate */
- const u8 *aBlob, int nBlob /* Record to read varints from */
-){
- int i;
- int iOff = 0;
- for(i=0; i<nCol; i++){
- if( iOff>=nBlob ) return 1;
- iOff += fts5GetVarint32(&aBlob[iOff], aCol[i]);
- }
- return (iOff!=nBlob);
-}
-
-/*
-** Argument aCol points to an array of integers containing one entry for
-** each table column. This function reads the %_docsize record for the
-** specified rowid and populates aCol[] with the results.
-**
-** An SQLite error code is returned if an error occurs, or SQLITE_OK
-** otherwise.
-*/
-static int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol){
- int nCol = p->pConfig->nCol; /* Number of user columns in table */
- sqlite3_stmt *pLookup = 0; /* Statement to query %_docsize */
- int rc; /* Return Code */
-
- assert( p->pConfig->bColumnsize );
- rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0);
- if( rc==SQLITE_OK ){
- int bCorrupt = 1;
- sqlite3_bind_int64(pLookup, 1, iRowid);
- if( SQLITE_ROW==sqlite3_step(pLookup) ){
- const u8 *aBlob = sqlite3_column_blob(pLookup, 0);
- int nBlob = sqlite3_column_bytes(pLookup, 0);
- if( 0==fts5StorageDecodeSizeArray(aCol, nCol, aBlob, nBlob) ){
- bCorrupt = 0;
- }
- }
- rc = sqlite3_reset(pLookup);
- if( bCorrupt && rc==SQLITE_OK ){
- rc = FTS5_CORRUPT;
- }
- }
-
- return rc;
-}
-
-static int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnToken){
- int rc = fts5StorageLoadTotals(p, 0);
- if( rc==SQLITE_OK ){
- *pnToken = 0;
- if( iCol<0 ){
- int i;
- for(i=0; i<p->pConfig->nCol; i++){
- *pnToken += p->aTotalSize[i];
- }
- }else if( iCol<p->pConfig->nCol ){
- *pnToken = p->aTotalSize[iCol];
- }else{
- rc = SQLITE_RANGE;
- }
- }
- return rc;
-}
-
-static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){
- int rc = fts5StorageLoadTotals(p, 0);
- if( rc==SQLITE_OK ){
- *pnRow = p->nTotalRow;
- }
- return rc;
-}
-
-/*
-** Flush any data currently held in-memory to disk.
-*/
-static int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit){
- if( bCommit && p->bTotalsValid ){
- int rc = fts5StorageSaveTotals(p);
- p->bTotalsValid = 0;
- if( rc!=SQLITE_OK ) return rc;
- }
- return sqlite3Fts5IndexSync(p->pIndex, bCommit);
-}
-
-static int sqlite3Fts5StorageRollback(Fts5Storage *p){
- p->bTotalsValid = 0;
- return sqlite3Fts5IndexRollback(p->pIndex);
-}
-
-static int sqlite3Fts5StorageConfigValue(
- Fts5Storage *p,
- const char *z,
- sqlite3_value *pVal,
- int iVal
-){
- sqlite3_stmt *pReplace = 0;
- int rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_CONFIG, &pReplace, 0);
- if( rc==SQLITE_OK ){
- sqlite3_bind_text(pReplace, 1, z, -1, SQLITE_STATIC);
- if( pVal ){
- sqlite3_bind_value(pReplace, 2, pVal);
- }else{
- sqlite3_bind_int(pReplace, 2, iVal);
- }
- sqlite3_step(pReplace);
- rc = sqlite3_reset(pReplace);
- }
- if( rc==SQLITE_OK && pVal ){
- int iNew = p->pConfig->iCookie + 1;
- rc = sqlite3Fts5IndexSetCookie(p->pIndex, iNew);
- if( rc==SQLITE_OK ){
- p->pConfig->iCookie = iNew;
- }
- }
- return rc;
-}
-
-/*
-** 2014 May 31
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-*/
-
-
-/* #include "fts5Int.h" */
-
-/**************************************************************************
-** Start of ascii tokenizer implementation.
-*/
-
-/*
-** For tokenizers with no "unicode" modifier, the set of token characters
-** is the same as the set of ASCII range alphanumeric characters.
-*/
-static unsigned char aAsciiTokenChar[128] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00..0x0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10..0x1F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20..0x2F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0x30..0x3F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40..0x4F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x50..0x5F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60..0x6F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x70..0x7F */
-};
-
-typedef struct AsciiTokenizer AsciiTokenizer;
-struct AsciiTokenizer {
- unsigned char aTokenChar[128];
-};
-
-static void fts5AsciiAddExceptions(
- AsciiTokenizer *p,
- const char *zArg,
- int bTokenChars
-){
- int i;
- for(i=0; zArg[i]; i++){
- if( (zArg[i] & 0x80)==0 ){
- p->aTokenChar[(int)zArg[i]] = (unsigned char)bTokenChars;
- }
- }
-}
-
-/*
-** Delete a "ascii" tokenizer.
-*/
-static void fts5AsciiDelete(Fts5Tokenizer *p){
- sqlite3_free(p);
-}
-
-/*
-** Create an "ascii" tokenizer.
-*/
-static int fts5AsciiCreate(
- void *pUnused,
- const char **azArg, int nArg,
- Fts5Tokenizer **ppOut
-){
- int rc = SQLITE_OK;
- AsciiTokenizer *p = 0;
- UNUSED_PARAM(pUnused);
- if( nArg%2 ){
- rc = SQLITE_ERROR;
- }else{
- p = sqlite3_malloc(sizeof(AsciiTokenizer));
- if( p==0 ){
- rc = SQLITE_NOMEM;
- }else{
- int i;
- memset(p, 0, sizeof(AsciiTokenizer));
- memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar));
- for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
- const char *zArg = azArg[i+1];
- if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){
- fts5AsciiAddExceptions(p, zArg, 1);
- }else
- if( 0==sqlite3_stricmp(azArg[i], "separators") ){
- fts5AsciiAddExceptions(p, zArg, 0);
- }else{
- rc = SQLITE_ERROR;
- }
- }
- if( rc!=SQLITE_OK ){
- fts5AsciiDelete((Fts5Tokenizer*)p);
- p = 0;
- }
- }
- }
-
- *ppOut = (Fts5Tokenizer*)p;
- return rc;
-}
-
-
-static void asciiFold(char *aOut, const char *aIn, int nByte){
- int i;
- for(i=0; i<nByte; i++){
- char c = aIn[i];
- if( c>='A' && c<='Z' ) c += 32;
- aOut[i] = c;
- }
-}
-
-/*
-** Tokenize some text using the ascii tokenizer.
-*/
-static int fts5AsciiTokenize(
- Fts5Tokenizer *pTokenizer,
- void *pCtx,
- int iUnused,
- const char *pText, int nText,
- int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd)
-){
- AsciiTokenizer *p = (AsciiTokenizer*)pTokenizer;
- int rc = SQLITE_OK;
- int ie;
- int is = 0;
-
- char aFold[64];
- int nFold = sizeof(aFold);
- char *pFold = aFold;
- unsigned char *a = p->aTokenChar;
-
- UNUSED_PARAM(iUnused);
-
- while( is<nText && rc==SQLITE_OK ){
- int nByte;
-
- /* Skip any leading divider characters. */
- while( is<nText && ((pText[is]&0x80)==0 && a[(int)pText[is]]==0) ){
- is++;
- }
- if( is==nText ) break;
-
- /* Count the token characters */
- ie = is+1;
- while( ie<nText && ((pText[ie]&0x80) || a[(int)pText[ie]] ) ){
- ie++;
- }
-
- /* Fold to lower case */
- nByte = ie-is;
- if( nByte>nFold ){
- if( pFold!=aFold ) sqlite3_free(pFold);
- pFold = sqlite3_malloc(nByte*2);
- if( pFold==0 ){
- rc = SQLITE_NOMEM;
- break;
- }
- nFold = nByte*2;
- }
- asciiFold(pFold, &pText[is], nByte);
-
- /* Invoke the token callback */
- rc = xToken(pCtx, 0, pFold, nByte, is, ie);
- is = ie+1;
- }
-
- if( pFold!=aFold ) sqlite3_free(pFold);
- if( rc==SQLITE_DONE ) rc = SQLITE_OK;
- return rc;
-}
-
-/**************************************************************************
-** Start of unicode61 tokenizer implementation.
-*/
-
-
-/*
-** The following two macros - READ_UTF8 and WRITE_UTF8 - have been copied
-** from the sqlite3 source file utf.c. If this file is compiled as part
-** of the amalgamation, they are not required.
-*/
-#ifndef SQLITE_AMALGAMATION
-
-static const unsigned char sqlite3Utf8Trans1[] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
-};
-
-#define READ_UTF8(zIn, zTerm, c) \
- c = *(zIn++); \
- if( c>=0xc0 ){ \
- c = sqlite3Utf8Trans1[c-0xc0]; \
- while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \
- c = (c<<6) + (0x3f & *(zIn++)); \
- } \
- if( c<0x80 \
- || (c&0xFFFFF800)==0xD800 \
- || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \
- }
-
-
-#define WRITE_UTF8(zOut, c) { \
- if( c<0x00080 ){ \
- *zOut++ = (unsigned char)(c&0xFF); \
- } \
- else if( c<0x00800 ){ \
- *zOut++ = 0xC0 + (unsigned char)((c>>6)&0x1F); \
- *zOut++ = 0x80 + (unsigned char)(c & 0x3F); \
- } \
- else if( c<0x10000 ){ \
- *zOut++ = 0xE0 + (unsigned char)((c>>12)&0x0F); \
- *zOut++ = 0x80 + (unsigned char)((c>>6) & 0x3F); \
- *zOut++ = 0x80 + (unsigned char)(c & 0x3F); \
- }else{ \
- *zOut++ = 0xF0 + (unsigned char)((c>>18) & 0x07); \
- *zOut++ = 0x80 + (unsigned char)((c>>12) & 0x3F); \
- *zOut++ = 0x80 + (unsigned char)((c>>6) & 0x3F); \
- *zOut++ = 0x80 + (unsigned char)(c & 0x3F); \
- } \
-}
-
-#endif /* ifndef SQLITE_AMALGAMATION */
-
-typedef struct Unicode61Tokenizer Unicode61Tokenizer;
-struct Unicode61Tokenizer {
- unsigned char aTokenChar[128]; /* ASCII range token characters */
- char *aFold; /* Buffer to fold text into */
- int nFold; /* Size of aFold[] in bytes */
- int bRemoveDiacritic; /* True if remove_diacritics=1 is set */
- int nException;
- int *aiException;
-};
-
-static int fts5UnicodeAddExceptions(
- Unicode61Tokenizer *p, /* Tokenizer object */
- const char *z, /* Characters to treat as exceptions */
- int bTokenChars /* 1 for 'tokenchars', 0 for 'separators' */
-){
- int rc = SQLITE_OK;
- int n = (int)strlen(z);
- int *aNew;
-
- if( n>0 ){
- aNew = (int*)sqlite3_realloc(p->aiException, (n+p->nException)*sizeof(int));
- if( aNew ){
- int nNew = p->nException;
- const unsigned char *zCsr = (const unsigned char*)z;
- const unsigned char *zTerm = (const unsigned char*)&z[n];
- while( zCsr<zTerm ){
- int iCode;
- int bToken;
- READ_UTF8(zCsr, zTerm, iCode);
- if( iCode<128 ){
- p->aTokenChar[iCode] = (unsigned char)bTokenChars;
- }else{
- bToken = sqlite3Fts5UnicodeIsalnum(iCode);
- assert( (bToken==0 || bToken==1) );
- assert( (bTokenChars==0 || bTokenChars==1) );
- if( bToken!=bTokenChars && sqlite3Fts5UnicodeIsdiacritic(iCode)==0 ){
- int i;
- for(i=0; i<nNew; i++){
- if( aNew[i]>iCode ) break;
- }
- memmove(&aNew[i+1], &aNew[i], (nNew-i)*sizeof(int));
- aNew[i] = iCode;
- nNew++;
- }
- }
- }
- p->aiException = aNew;
- p->nException = nNew;
- }else{
- rc = SQLITE_NOMEM;
- }
- }
-
- return rc;
-}
-
-/*
-** Return true if the p->aiException[] array contains the value iCode.
-*/
-static int fts5UnicodeIsException(Unicode61Tokenizer *p, int iCode){
- if( p->nException>0 ){
- int *a = p->aiException;
- int iLo = 0;
- int iHi = p->nException-1;
-
- while( iHi>=iLo ){
- int iTest = (iHi + iLo) / 2;
- if( iCode==a[iTest] ){
- return 1;
- }else if( iCode>a[iTest] ){
- iLo = iTest+1;
- }else{
- iHi = iTest-1;
- }
- }
- }
-
- return 0;
-}
-
-/*
-** Delete a "unicode61" tokenizer.
-*/
-static void fts5UnicodeDelete(Fts5Tokenizer *pTok){
- if( pTok ){
- Unicode61Tokenizer *p = (Unicode61Tokenizer*)pTok;
- sqlite3_free(p->aiException);
- sqlite3_free(p->aFold);
- sqlite3_free(p);
- }
- return;
-}
-
-/*
-** Create a "unicode61" tokenizer.
-*/
-static int fts5UnicodeCreate(
- void *pUnused,
- const char **azArg, int nArg,
- Fts5Tokenizer **ppOut
-){
- int rc = SQLITE_OK; /* Return code */
- Unicode61Tokenizer *p = 0; /* New tokenizer object */
-
- UNUSED_PARAM(pUnused);
-
- if( nArg%2 ){
- rc = SQLITE_ERROR;
- }else{
- p = (Unicode61Tokenizer*)sqlite3_malloc(sizeof(Unicode61Tokenizer));
- if( p ){
- int i;
- memset(p, 0, sizeof(Unicode61Tokenizer));
- memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar));
- p->bRemoveDiacritic = 1;
- p->nFold = 64;
- p->aFold = sqlite3_malloc(p->nFold * sizeof(char));
- if( p->aFold==0 ){
- rc = SQLITE_NOMEM;
- }
- for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
- const char *zArg = azArg[i+1];
- if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
- if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
- rc = SQLITE_ERROR;
- }
- p->bRemoveDiacritic = (zArg[0]=='1');
- }else
- if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){
- rc = fts5UnicodeAddExceptions(p, zArg, 1);
- }else
- if( 0==sqlite3_stricmp(azArg[i], "separators") ){
- rc = fts5UnicodeAddExceptions(p, zArg, 0);
- }else{
- rc = SQLITE_ERROR;
- }
- }
- }else{
- rc = SQLITE_NOMEM;
- }
- if( rc!=SQLITE_OK ){
- fts5UnicodeDelete((Fts5Tokenizer*)p);
- p = 0;
- }
- *ppOut = (Fts5Tokenizer*)p;
- }
- return rc;
-}
-
-/*
-** Return true if, for the purposes of tokenizing with the tokenizer
-** passed as the first argument, codepoint iCode is considered a token
-** character (not a separator).
-*/
-static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){
- assert( (sqlite3Fts5UnicodeIsalnum(iCode) & 0xFFFFFFFE)==0 );
- return sqlite3Fts5UnicodeIsalnum(iCode) ^ fts5UnicodeIsException(p, iCode);
-}
-
-static int fts5UnicodeTokenize(
- Fts5Tokenizer *pTokenizer,
- void *pCtx,
- int iUnused,
- const char *pText, int nText,
- int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd)
-){
- Unicode61Tokenizer *p = (Unicode61Tokenizer*)pTokenizer;
- int rc = SQLITE_OK;
- unsigned char *a = p->aTokenChar;
-
- unsigned char *zTerm = (unsigned char*)&pText[nText];
- unsigned char *zCsr = (unsigned char *)pText;
-
- /* Output buffer */
- char *aFold = p->aFold;
- int nFold = p->nFold;
- const char *pEnd = &aFold[nFold-6];
-
- UNUSED_PARAM(iUnused);
-
- /* Each iteration of this loop gobbles up a contiguous run of separators,
- ** then the next token. */
- while( rc==SQLITE_OK ){
- int iCode; /* non-ASCII codepoint read from input */
- char *zOut = aFold;
- int is;
- int ie;
-
- /* Skip any separator characters. */
- while( 1 ){
- if( zCsr>=zTerm ) goto tokenize_done;
- if( *zCsr & 0x80 ) {
- /* A character outside of the ascii range. Skip past it if it is
- ** a separator character. Or break out of the loop if it is not. */
- is = zCsr - (unsigned char*)pText;
- READ_UTF8(zCsr, zTerm, iCode);
- if( fts5UnicodeIsAlnum(p, iCode) ){
- goto non_ascii_tokenchar;
- }
- }else{
- if( a[*zCsr] ){
- is = zCsr - (unsigned char*)pText;
- goto ascii_tokenchar;
- }
- zCsr++;
- }
- }
-
- /* Run through the tokenchars. Fold them into the output buffer along
- ** the way. */
- while( zCsr<zTerm ){
-
- /* Grow the output buffer so that there is sufficient space to fit the
- ** largest possible utf-8 character. */
- if( zOut>pEnd ){
- aFold = sqlite3_malloc(nFold*2);
- if( aFold==0 ){
- rc = SQLITE_NOMEM;
- goto tokenize_done;
- }
- zOut = &aFold[zOut - p->aFold];
- memcpy(aFold, p->aFold, nFold);
- sqlite3_free(p->aFold);
- p->aFold = aFold;
- p->nFold = nFold = nFold*2;
- pEnd = &aFold[nFold-6];
- }
-
- if( *zCsr & 0x80 ){
- /* An non-ascii-range character. Fold it into the output buffer if
- ** it is a token character, or break out of the loop if it is not. */
- READ_UTF8(zCsr, zTerm, iCode);
- if( fts5UnicodeIsAlnum(p,iCode)||sqlite3Fts5UnicodeIsdiacritic(iCode) ){
- non_ascii_tokenchar:
- iCode = sqlite3Fts5UnicodeFold(iCode, p->bRemoveDiacritic);
- if( iCode ) WRITE_UTF8(zOut, iCode);
- }else{
- break;
- }
- }else if( a[*zCsr]==0 ){
- /* An ascii-range separator character. End of token. */
- break;
- }else{
- ascii_tokenchar:
- if( *zCsr>='A' && *zCsr<='Z' ){
- *zOut++ = *zCsr + 32;
- }else{
- *zOut++ = *zCsr;
- }
- zCsr++;
- }
- ie = zCsr - (unsigned char*)pText;
- }
-
- /* Invoke the token callback */
- rc = xToken(pCtx, 0, aFold, zOut-aFold, is, ie);
- }
-
- tokenize_done:
- if( rc==SQLITE_DONE ) rc = SQLITE_OK;
- return rc;
-}
-
-/**************************************************************************
-** Start of porter stemmer implementation.
-*/
-
-/* Any tokens larger than this (in bytes) are passed through without
-** stemming. */
-#define FTS5_PORTER_MAX_TOKEN 64
-
-typedef struct PorterTokenizer PorterTokenizer;
-struct PorterTokenizer {
- fts5_tokenizer tokenizer; /* Parent tokenizer module */
- Fts5Tokenizer *pTokenizer; /* Parent tokenizer instance */
- char aBuf[FTS5_PORTER_MAX_TOKEN + 64];
-};
-
-/*
-** Delete a "porter" tokenizer.
-*/
-static void fts5PorterDelete(Fts5Tokenizer *pTok){
- if( pTok ){
- PorterTokenizer *p = (PorterTokenizer*)pTok;
- if( p->pTokenizer ){
- p->tokenizer.xDelete(p->pTokenizer);
- }
- sqlite3_free(p);
- }
-}
-
-/*
-** Create a "porter" tokenizer.
-*/
-static int fts5PorterCreate(
- void *pCtx,
- const char **azArg, int nArg,
- Fts5Tokenizer **ppOut
-){
- fts5_api *pApi = (fts5_api*)pCtx;
- int rc = SQLITE_OK;
- PorterTokenizer *pRet;
- void *pUserdata = 0;
- const char *zBase = "unicode61";
-
- if( nArg>0 ){
- zBase = azArg[0];
- }
-
- pRet = (PorterTokenizer*)sqlite3_malloc(sizeof(PorterTokenizer));
- if( pRet ){
- memset(pRet, 0, sizeof(PorterTokenizer));
- rc = pApi->xFindTokenizer(pApi, zBase, &pUserdata, &pRet->tokenizer);
- }else{
- rc = SQLITE_NOMEM;
- }
- if( rc==SQLITE_OK ){
- int nArg2 = (nArg>0 ? nArg-1 : 0);
- const char **azArg2 = (nArg2 ? &azArg[1] : 0);
- rc = pRet->tokenizer.xCreate(pUserdata, azArg2, nArg2, &pRet->pTokenizer);
- }
-
- if( rc!=SQLITE_OK ){
- fts5PorterDelete((Fts5Tokenizer*)pRet);
- pRet = 0;
- }
- *ppOut = (Fts5Tokenizer*)pRet;
- return rc;
-}
-
-typedef struct PorterContext PorterContext;
-struct PorterContext {
- void *pCtx;
- int (*xToken)(void*, int, const char*, int, int, int);
- char *aBuf;
-};
-
-typedef struct PorterRule PorterRule;
-struct PorterRule {
- const char *zSuffix;
- int nSuffix;
- int (*xCond)(char *zStem, int nStem);
- const char *zOutput;
- int nOutput;
-};
-
-#if 0
-static int fts5PorterApply(char *aBuf, int *pnBuf, PorterRule *aRule){
- int ret = -1;
- int nBuf = *pnBuf;
- PorterRule *p;
-
- for(p=aRule; p->zSuffix; p++){
- assert( strlen(p->zSuffix)==p->nSuffix );
- assert( strlen(p->zOutput)==p->nOutput );
- if( nBuf<p->nSuffix ) continue;
- if( 0==memcmp(&aBuf[nBuf - p->nSuffix], p->zSuffix, p->nSuffix) ) break;
- }
-
- if( p->zSuffix ){
- int nStem = nBuf - p->nSuffix;
- if( p->xCond==0 || p->xCond(aBuf, nStem) ){
- memcpy(&aBuf[nStem], p->zOutput, p->nOutput);
- *pnBuf = nStem + p->nOutput;
- ret = p - aRule;
- }
- }
-
- return ret;
-}
-#endif
-
-static int fts5PorterIsVowel(char c, int bYIsVowel){
- return (
- c=='a' || c=='e' || c=='i' || c=='o' || c=='u' || (bYIsVowel && c=='y')
- );
-}
-
-static int fts5PorterGobbleVC(char *zStem, int nStem, int bPrevCons){
- int i;
- int bCons = bPrevCons;
-
- /* Scan for a vowel */
- for(i=0; i<nStem; i++){
- if( 0==(bCons = !fts5PorterIsVowel(zStem[i], bCons)) ) break;
- }
-
- /* Scan for a consonent */
- for(i++; i<nStem; i++){
- if( (bCons = !fts5PorterIsVowel(zStem[i], bCons)) ) return i+1;
- }
- return 0;
-}
-
-/* porter rule condition: (m > 0) */
-static int fts5Porter_MGt0(char *zStem, int nStem){
- return !!fts5PorterGobbleVC(zStem, nStem, 0);
-}
-
-/* porter rule condition: (m > 1) */
-static int fts5Porter_MGt1(char *zStem, int nStem){
- int n;
- n = fts5PorterGobbleVC(zStem, nStem, 0);
- if( n && fts5PorterGobbleVC(&zStem[n], nStem-n, 1) ){
- return 1;
- }
- return 0;
-}
-
-/* porter rule condition: (m = 1) */
-static int fts5Porter_MEq1(char *zStem, int nStem){
- int n;
- n = fts5PorterGobbleVC(zStem, nStem, 0);
- if( n && 0==fts5PorterGobbleVC(&zStem[n], nStem-n, 1) ){
- return 1;
- }
- return 0;
-}
-
-/* porter rule condition: (*o) */
-static int fts5Porter_Ostar(char *zStem, int nStem){
- if( zStem[nStem-1]=='w' || zStem[nStem-1]=='x' || zStem[nStem-1]=='y' ){
- return 0;
- }else{
- int i;
- int mask = 0;
- int bCons = 0;
- for(i=0; i<nStem; i++){
- bCons = !fts5PorterIsVowel(zStem[i], bCons);
- assert( bCons==0 || bCons==1 );
- mask = (mask << 1) + bCons;
- }
- return ((mask & 0x0007)==0x0005);
- }
-}
-
-/* porter rule condition: (m > 1 and (*S or *T)) */
-static int fts5Porter_MGt1_and_S_or_T(char *zStem, int nStem){
- assert( nStem>0 );
- return (zStem[nStem-1]=='s' || zStem[nStem-1]=='t')
- && fts5Porter_MGt1(zStem, nStem);
-}
-
-/* porter rule condition: (*v*) */
-static int fts5Porter_Vowel(char *zStem, int nStem){
- int i;
- for(i=0; i<nStem; i++){
- if( fts5PorterIsVowel(zStem[i], i>0) ){
- return 1;
- }
- }
- return 0;
-}
-
-
-/**************************************************************************
-***************************************************************************
-** GENERATED CODE STARTS HERE (mkportersteps.tcl)
-*/
-
-static int fts5PorterStep4(char *aBuf, int *pnBuf){
- int ret = 0;
- int nBuf = *pnBuf;
- switch( aBuf[nBuf-2] ){
-
- case 'a':
- if( nBuf>2 && 0==memcmp("al", &aBuf[nBuf-2], 2) ){
- if( fts5Porter_MGt1(aBuf, nBuf-2) ){
- *pnBuf = nBuf - 2;
- }
- }
- break;
-
- case 'c':
- if( nBuf>4 && 0==memcmp("ance", &aBuf[nBuf-4], 4) ){
- if( fts5Porter_MGt1(aBuf, nBuf-4) ){
- *pnBuf = nBuf - 4;
- }
- }else if( nBuf>4 && 0==memcmp("ence", &aBuf[nBuf-4], 4) ){
- if( fts5Porter_MGt1(aBuf, nBuf-4) ){
- *pnBuf = nBuf - 4;
- }
- }
- break;
-
- case 'e':
- if( nBuf>2 && 0==memcmp("er", &aBuf[nBuf-2], 2) ){
- if( fts5Porter_MGt1(aBuf, nBuf-2) ){
- *pnBuf = nBuf - 2;
- }
- }
- break;
-
- case 'i':
- if( nBuf>2 && 0==memcmp("ic", &aBuf[nBuf-2], 2) ){
- if( fts5Porter_MGt1(aBuf, nBuf-2) ){
- *pnBuf = nBuf - 2;
- }
- }
- break;
-
- case 'l':
- if( nBuf>4 && 0==memcmp("able", &aBuf[nBuf-4], 4) ){
- if( fts5Porter_MGt1(aBuf, nBuf-4) ){
- *pnBuf = nBuf - 4;
- }
- }else if( nBuf>4 && 0==memcmp("ible", &aBuf[nBuf-4], 4) ){
- if( fts5Porter_MGt1(aBuf, nBuf-4) ){
- *pnBuf = nBuf - 4;
- }
- }
- break;
-
- case 'n':
- if( nBuf>3 && 0==memcmp("ant", &aBuf[nBuf-3], 3) ){
- if( fts5Porter_MGt1(aBuf, nBuf-3) ){
- *pnBuf = nBuf - 3;
- }
- }else if( nBuf>5 && 0==memcmp("ement", &aBuf[nBuf-5], 5) ){
- if( fts5Porter_MGt1(aBuf, nBuf-5) ){
- *pnBuf = nBuf - 5;
- }
- }else if( nBuf>4 && 0==memcmp("ment", &aBuf[nBuf-4], 4) ){
- if( fts5Porter_MGt1(aBuf, nBuf-4) ){
- *pnBuf = nBuf - 4;
- }
- }else if( nBuf>3 && 0==memcmp("ent", &aBuf[nBuf-3], 3) ){
- if( fts5Porter_MGt1(aBuf, nBuf-3) ){
- *pnBuf = nBuf - 3;
- }
- }
- break;
-
- case 'o':
- if( nBuf>3 && 0==memcmp("ion", &aBuf[nBuf-3], 3) ){
- if( fts5Porter_MGt1_and_S_or_T(aBuf, nBuf-3) ){
- *pnBuf = nBuf - 3;
- }
- }else if( nBuf>2 && 0==memcmp("ou", &aBuf[nBuf-2], 2) ){
- if( fts5Porter_MGt1(aBuf, nBuf-2) ){
- *pnBuf = nBuf - 2;
- }
- }
- break;
-
- case 's':
- if( nBuf>3 && 0==memcmp("ism", &aBuf[nBuf-3], 3) ){
- if( fts5Porter_MGt1(aBuf, nBuf-3) ){
- *pnBuf = nBuf - 3;
- }
- }
- break;
-
- case 't':
- if( nBuf>3 && 0==memcmp("ate", &aBuf[nBuf-3], 3) ){
- if( fts5Porter_MGt1(aBuf, nBuf-3) ){
- *pnBuf = nBuf - 3;
- }
- }else if( nBuf>3 && 0==memcmp("iti", &aBuf[nBuf-3], 3) ){
- if( fts5Porter_MGt1(aBuf, nBuf-3) ){
- *pnBuf = nBuf - 3;
- }
- }
- break;
-
- case 'u':
- if( nBuf>3 && 0==memcmp("ous", &aBuf[nBuf-3], 3) ){
- if( fts5Porter_MGt1(aBuf, nBuf-3) ){
- *pnBuf = nBuf - 3;
- }
- }
- break;
-
- case 'v':
- if( nBuf>3 && 0==memcmp("ive", &aBuf[nBuf-3], 3) ){
- if( fts5Porter_MGt1(aBuf, nBuf-3) ){
- *pnBuf = nBuf - 3;
- }
- }
- break;
-
- case 'z':
- if( nBuf>3 && 0==memcmp("ize", &aBuf[nBuf-3], 3) ){
- if( fts5Porter_MGt1(aBuf, nBuf-3) ){
- *pnBuf = nBuf - 3;
- }
- }
- break;
-
- }
- return ret;
-}
-
-
-static int fts5PorterStep1B2(char *aBuf, int *pnBuf){
- int ret = 0;
- int nBuf = *pnBuf;
- switch( aBuf[nBuf-2] ){
-
- case 'a':
- if( nBuf>2 && 0==memcmp("at", &aBuf[nBuf-2], 2) ){
- memcpy(&aBuf[nBuf-2], "ate", 3);
- *pnBuf = nBuf - 2 + 3;
- ret = 1;
- }
- break;
-
- case 'b':
- if( nBuf>2 && 0==memcmp("bl", &aBuf[nBuf-2], 2) ){
- memcpy(&aBuf[nBuf-2], "ble", 3);
- *pnBuf = nBuf - 2 + 3;
- ret = 1;
- }
- break;
-
- case 'i':
- if( nBuf>2 && 0==memcmp("iz", &aBuf[nBuf-2], 2) ){
- memcpy(&aBuf[nBuf-2], "ize", 3);
- *pnBuf = nBuf - 2 + 3;
- ret = 1;
- }
- break;
-
- }
- return ret;
-}
-
-
-static int fts5PorterStep2(char *aBuf, int *pnBuf){
- int ret = 0;
- int nBuf = *pnBuf;
- switch( aBuf[nBuf-2] ){
-
- case 'a':
- if( nBuf>7 && 0==memcmp("ational", &aBuf[nBuf-7], 7) ){
- if( fts5Porter_MGt0(aBuf, nBuf-7) ){
- memcpy(&aBuf[nBuf-7], "ate", 3);
- *pnBuf = nBuf - 7 + 3;
- }
- }else if( nBuf>6 && 0==memcmp("tional", &aBuf[nBuf-6], 6) ){
- if( fts5Porter_MGt0(aBuf, nBuf-6) ){
- memcpy(&aBuf[nBuf-6], "tion", 4);
- *pnBuf = nBuf - 6 + 4;
- }
- }
- break;
-
- case 'c':
- if( nBuf>4 && 0==memcmp("enci", &aBuf[nBuf-4], 4) ){
- if( fts5Porter_MGt0(aBuf, nBuf-4) ){
- memcpy(&aBuf[nBuf-4], "ence", 4);
- *pnBuf = nBuf - 4 + 4;
- }
- }else if( nBuf>4 && 0==memcmp("anci", &aBuf[nBuf-4], 4) ){
- if( fts5Porter_MGt0(aBuf, nBuf-4) ){
- memcpy(&aBuf[nBuf-4], "ance", 4);
- *pnBuf = nBuf - 4 + 4;
- }
- }
- break;
-
- case 'e':
- if( nBuf>4 && 0==memcmp("izer", &aBuf[nBuf-4], 4) ){
- if( fts5Porter_MGt0(aBuf, nBuf-4) ){
- memcpy(&aBuf[nBuf-4], "ize", 3);
- *pnBuf = nBuf - 4 + 3;
- }
- }
- break;
-
- case 'g':
- if( nBuf>4 && 0==memcmp("logi", &aBuf[nBuf-4], 4) ){
- if( fts5Porter_MGt0(aBuf, nBuf-4) ){
- memcpy(&aBuf[nBuf-4], "log", 3);
- *pnBuf = nBuf - 4 + 3;
- }
- }
- break;
-
- case 'l':
- if( nBuf>3 && 0==memcmp("bli", &aBuf[nBuf-3], 3) ){
- if( fts5Porter_MGt0(aBuf, nBuf-3) ){
- memcpy(&aBuf[nBuf-3], "ble", 3);
- *pnBuf = nBuf - 3 + 3;
- }
- }else if( nBuf>4 && 0==memcmp("alli", &aBuf[nBuf-4], 4) ){
- if( fts5Porter_MGt0(aBuf, nBuf-4) ){
- memcpy(&aBuf[nBuf-4], "al", 2);
- *pnBuf = nBuf - 4 + 2;
- }
- }else if( nBuf>5 && 0==memcmp("entli", &aBuf[nBuf-5], 5) ){
- if( fts5Porter_MGt0(aBuf, nBuf-5) ){
- memcpy(&aBuf[nBuf-5], "ent", 3);
- *pnBuf = nBuf - 5 + 3;
- }
- }else if( nBuf>3 && 0==memcmp("eli", &aBuf[nBuf-3], 3) ){
- if( fts5Porter_MGt0(aBuf, nBuf-3) ){
- memcpy(&aBuf[nBuf-3], "e", 1);
- *pnBuf = nBuf - 3 + 1;
- }
- }else if( nBuf>5 && 0==memcmp("ousli", &aBuf[nBuf-5], 5) ){
- if( fts5Porter_MGt0(aBuf, nBuf-5) ){
- memcpy(&aBuf[nBuf-5], "ous", 3);
- *pnBuf = nBuf - 5 + 3;
- }
- }
- break;
-
- case 'o':
- if( nBuf>7 && 0==memcmp("ization", &aBuf[nBuf-7], 7) ){
- if( fts5Porter_MGt0(aBuf, nBuf-7) ){
- memcpy(&aBuf[nBuf-7], "ize", 3);
- *pnBuf = nBuf - 7 + 3;
- }
- }else if( nBuf>5 && 0==memcmp("ation", &aBuf[nBuf-5], 5) ){
- if( fts5Porter_MGt0(aBuf, nBuf-5) ){
- memcpy(&aBuf[nBuf-5], "ate", 3);
- *pnBuf = nBuf - 5 + 3;
- }
- }else if( nBuf>4 && 0==memcmp("ator", &aBuf[nBuf-4], 4) ){
- if( fts5Porter_MGt0(aBuf, nBuf-4) ){
- memcpy(&aBuf[nBuf-4], "ate", 3);
- *pnBuf = nBuf - 4 + 3;
- }
- }
- break;
-
- case 's':
- if( nBuf>5 && 0==memcmp("alism", &aBuf[nBuf-5], 5) ){
- if( fts5Porter_MGt0(aBuf, nBuf-5) ){
- memcpy(&aBuf[nBuf-5], "al", 2);
- *pnBuf = nBuf - 5 + 2;
- }
- }else if( nBuf>7 && 0==memcmp("iveness", &aBuf[nBuf-7], 7) ){
- if( fts5Porter_MGt0(aBuf, nBuf-7) ){
- memcpy(&aBuf[nBuf-7], "ive", 3);
- *pnBuf = nBuf - 7 + 3;
- }
- }else if( nBuf>7 && 0==memcmp("fulness", &aBuf[nBuf-7], 7) ){
- if( fts5Porter_MGt0(aBuf, nBuf-7) ){
- memcpy(&aBuf[nBuf-7], "ful", 3);
- *pnBuf = nBuf - 7 + 3;
- }
- }else if( nBuf>7 && 0==memcmp("ousness", &aBuf[nBuf-7], 7) ){
- if( fts5Porter_MGt0(aBuf, nBuf-7) ){
- memcpy(&aBuf[nBuf-7], "ous", 3);
- *pnBuf = nBuf - 7 + 3;
- }
- }
- break;
-
- case 't':
- if( nBuf>5 && 0==memcmp("aliti", &aBuf[nBuf-5], 5) ){
- if( fts5Porter_MGt0(aBuf, nBuf-5) ){
- memcpy(&aBuf[nBuf-5], "al", 2);
- *pnBuf = nBuf - 5 + 2;
- }
- }else if( nBuf>5 && 0==memcmp("iviti", &aBuf[nBuf-5], 5) ){
- if( fts5Porter_MGt0(aBuf, nBuf-5) ){
- memcpy(&aBuf[nBuf-5], "ive", 3);
- *pnBuf = nBuf - 5 + 3;
- }
- }else if( nBuf>6 && 0==memcmp("biliti", &aBuf[nBuf-6], 6) ){
- if( fts5Porter_MGt0(aBuf, nBuf-6) ){
- memcpy(&aBuf[nBuf-6], "ble", 3);
- *pnBuf = nBuf - 6 + 3;
- }
- }
- break;
-
- }
- return ret;
-}
-
-
-static int fts5PorterStep3(char *aBuf, int *pnBuf){
- int ret = 0;
- int nBuf = *pnBuf;
- switch( aBuf[nBuf-2] ){
-
- case 'a':
- if( nBuf>4 && 0==memcmp("ical", &aBuf[nBuf-4], 4) ){
- if( fts5Porter_MGt0(aBuf, nBuf-4) ){
- memcpy(&aBuf[nBuf-4], "ic", 2);
- *pnBuf = nBuf - 4 + 2;
- }
- }
- break;
-
- case 's':
- if( nBuf>4 && 0==memcmp("ness", &aBuf[nBuf-4], 4) ){
- if( fts5Porter_MGt0(aBuf, nBuf-4) ){
- *pnBuf = nBuf - 4;
- }
- }
- break;
-
- case 't':
- if( nBuf>5 && 0==memcmp("icate", &aBuf[nBuf-5], 5) ){
- if( fts5Porter_MGt0(aBuf, nBuf-5) ){
- memcpy(&aBuf[nBuf-5], "ic", 2);
- *pnBuf = nBuf - 5 + 2;
- }
- }else if( nBuf>5 && 0==memcmp("iciti", &aBuf[nBuf-5], 5) ){
- if( fts5Porter_MGt0(aBuf, nBuf-5) ){
- memcpy(&aBuf[nBuf-5], "ic", 2);
- *pnBuf = nBuf - 5 + 2;
- }
- }
- break;
-
- case 'u':
- if( nBuf>3 && 0==memcmp("ful", &aBuf[nBuf-3], 3) ){
- if( fts5Porter_MGt0(aBuf, nBuf-3) ){
- *pnBuf = nBuf - 3;
- }
- }
- break;
-
- case 'v':
- if( nBuf>5 && 0==memcmp("ative", &aBuf[nBuf-5], 5) ){
- if( fts5Porter_MGt0(aBuf, nBuf-5) ){
- *pnBuf = nBuf - 5;
- }
- }
- break;
-
- case 'z':
- if( nBuf>5 && 0==memcmp("alize", &aBuf[nBuf-5], 5) ){
- if( fts5Porter_MGt0(aBuf, nBuf-5) ){
- memcpy(&aBuf[nBuf-5], "al", 2);
- *pnBuf = nBuf - 5 + 2;
- }
- }
- break;
-
- }
- return ret;
-}
-
-
-static int fts5PorterStep1B(char *aBuf, int *pnBuf){
- int ret = 0;
- int nBuf = *pnBuf;
- switch( aBuf[nBuf-2] ){
-
- case 'e':
- if( nBuf>3 && 0==memcmp("eed", &aBuf[nBuf-3], 3) ){
- if( fts5Porter_MGt0(aBuf, nBuf-3) ){
- memcpy(&aBuf[nBuf-3], "ee", 2);
- *pnBuf = nBuf - 3 + 2;
- }
- }else if( nBuf>2 && 0==memcmp("ed", &aBuf[nBuf-2], 2) ){
- if( fts5Porter_Vowel(aBuf, nBuf-2) ){
- *pnBuf = nBuf - 2;
- ret = 1;
- }
- }
- break;
-
- case 'n':
- if( nBuf>3 && 0==memcmp("ing", &aBuf[nBuf-3], 3) ){
- if( fts5Porter_Vowel(aBuf, nBuf-3) ){
- *pnBuf = nBuf - 3;
- ret = 1;
- }
- }
- break;
-
- }
- return ret;
-}
-
-/*
-** GENERATED CODE ENDS HERE (mkportersteps.tcl)
-***************************************************************************
-**************************************************************************/
-
-static void fts5PorterStep1A(char *aBuf, int *pnBuf){
- int nBuf = *pnBuf;
- if( aBuf[nBuf-1]=='s' ){
- if( aBuf[nBuf-2]=='e' ){
- if( (nBuf>4 && aBuf[nBuf-4]=='s' && aBuf[nBuf-3]=='s')
- || (nBuf>3 && aBuf[nBuf-3]=='i' )
- ){
- *pnBuf = nBuf-2;
- }else{
- *pnBuf = nBuf-1;
- }
- }
- else if( aBuf[nBuf-2]!='s' ){
- *pnBuf = nBuf-1;
- }
- }
-}
-
-static int fts5PorterCb(
- void *pCtx,
- int tflags,
- const char *pToken,
- int nToken,
- int iStart,
- int iEnd
-){
- PorterContext *p = (PorterContext*)pCtx;
-
- char *aBuf;
- int nBuf;
-
- if( nToken>FTS5_PORTER_MAX_TOKEN || nToken<3 ) goto pass_through;
- aBuf = p->aBuf;
- nBuf = nToken;
- memcpy(aBuf, pToken, nBuf);
-
- /* Step 1. */
- fts5PorterStep1A(aBuf, &nBuf);
- if( fts5PorterStep1B(aBuf, &nBuf) ){
- if( fts5PorterStep1B2(aBuf, &nBuf)==0 ){
- char c = aBuf[nBuf-1];
- if( fts5PorterIsVowel(c, 0)==0
- && c!='l' && c!='s' && c!='z' && c==aBuf[nBuf-2]
- ){
- nBuf--;
- }else if( fts5Porter_MEq1(aBuf, nBuf) && fts5Porter_Ostar(aBuf, nBuf) ){
- aBuf[nBuf++] = 'e';
- }
- }
- }
-
- /* Step 1C. */
- if( aBuf[nBuf-1]=='y' && fts5Porter_Vowel(aBuf, nBuf-1) ){
- aBuf[nBuf-1] = 'i';
- }
-
- /* Steps 2 through 4. */
- fts5PorterStep2(aBuf, &nBuf);
- fts5PorterStep3(aBuf, &nBuf);
- fts5PorterStep4(aBuf, &nBuf);
-
- /* Step 5a. */
- assert( nBuf>0 );
- if( aBuf[nBuf-1]=='e' ){
- if( fts5Porter_MGt1(aBuf, nBuf-1)
- || (fts5Porter_MEq1(aBuf, nBuf-1) && !fts5Porter_Ostar(aBuf, nBuf-1))
- ){
- nBuf--;
- }
- }
-
- /* Step 5b. */
- if( nBuf>1 && aBuf[nBuf-1]=='l'
- && aBuf[nBuf-2]=='l' && fts5Porter_MGt1(aBuf, nBuf-1)
- ){
- nBuf--;
- }
-
- return p->xToken(p->pCtx, tflags, aBuf, nBuf, iStart, iEnd);
-
- pass_through:
- return p->xToken(p->pCtx, tflags, pToken, nToken, iStart, iEnd);
-}
-
-/*
-** Tokenize using the porter tokenizer.
-*/
-static int fts5PorterTokenize(
- Fts5Tokenizer *pTokenizer,
- void *pCtx,
- int flags,
- const char *pText, int nText,
- int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd)
-){
- PorterTokenizer *p = (PorterTokenizer*)pTokenizer;
- PorterContext sCtx;
- sCtx.xToken = xToken;
- sCtx.pCtx = pCtx;
- sCtx.aBuf = p->aBuf;
- return p->tokenizer.xTokenize(
- p->pTokenizer, (void*)&sCtx, flags, pText, nText, fts5PorterCb
- );
-}
-
-/*
-** Register all built-in tokenizers with FTS5.
-*/
-static int sqlite3Fts5TokenizerInit(fts5_api *pApi){
- struct BuiltinTokenizer {
- const char *zName;
- fts5_tokenizer x;
- } aBuiltin[] = {
- { "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}},
- { "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }},
- { "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }},
- };
-
- int rc = SQLITE_OK; /* Return code */
- int i; /* To iterate through builtin functions */
-
- for(i=0; rc==SQLITE_OK && i<ArraySize(aBuiltin); i++){
- rc = pApi->xCreateTokenizer(pApi,
- aBuiltin[i].zName,
- (void*)pApi,
- &aBuiltin[i].x,
- 0
- );
- }
-
- return rc;
-}
-
-
-
-/*
-** 2012 May 25
-**
-** 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.
-**
-******************************************************************************
-*/
-
-/*
-** DO NOT EDIT THIS MACHINE GENERATED FILE.
-*/
-
-
-/* #include <assert.h> */
-
-/*
-** Return true if the argument corresponds to a unicode codepoint
-** classified as either a letter or a number. Otherwise false.
-**
-** The results are undefined if the value passed to this function
-** is less than zero.
-*/
-static int sqlite3Fts5UnicodeIsalnum(int c){
- /* Each unsigned integer in the following array corresponds to a contiguous
- ** range of unicode codepoints that are not either letters or numbers (i.e.
- ** codepoints for which this function should return 0).
- **
- ** The most significant 22 bits in each 32-bit value contain the first
- ** codepoint in the range. The least significant 10 bits are used to store
- ** the size of the range (always at least 1). In other words, the value
- ** ((C<<22) + N) represents a range of N codepoints starting with codepoint
- ** C. It is not possible to represent a range larger than 1023 codepoints
- ** using this format.
- */
- static const unsigned int aEntry[] = {
- 0x00000030, 0x0000E807, 0x00016C06, 0x0001EC2F, 0x0002AC07,
- 0x0002D001, 0x0002D803, 0x0002EC01, 0x0002FC01, 0x00035C01,
- 0x0003DC01, 0x000B0804, 0x000B480E, 0x000B9407, 0x000BB401,
- 0x000BBC81, 0x000DD401, 0x000DF801, 0x000E1002, 0x000E1C01,
- 0x000FD801, 0x00120808, 0x00156806, 0x00162402, 0x00163C01,
- 0x00164437, 0x0017CC02, 0x00180005, 0x00181816, 0x00187802,
- 0x00192C15, 0x0019A804, 0x0019C001, 0x001B5001, 0x001B580F,
- 0x001B9C07, 0x001BF402, 0x001C000E, 0x001C3C01, 0x001C4401,
- 0x001CC01B, 0x001E980B, 0x001FAC09, 0x001FD804, 0x00205804,
- 0x00206C09, 0x00209403, 0x0020A405, 0x0020C00F, 0x00216403,
- 0x00217801, 0x0023901B, 0x00240004, 0x0024E803, 0x0024F812,
- 0x00254407, 0x00258804, 0x0025C001, 0x00260403, 0x0026F001,
- 0x0026F807, 0x00271C02, 0x00272C03, 0x00275C01, 0x00278802,
- 0x0027C802, 0x0027E802, 0x00280403, 0x0028F001, 0x0028F805,
- 0x00291C02, 0x00292C03, 0x00294401, 0x0029C002, 0x0029D401,
- 0x002A0403, 0x002AF001, 0x002AF808, 0x002B1C03, 0x002B2C03,
- 0x002B8802, 0x002BC002, 0x002C0403, 0x002CF001, 0x002CF807,
- 0x002D1C02, 0x002D2C03, 0x002D5802, 0x002D8802, 0x002DC001,
- 0x002E0801, 0x002EF805, 0x002F1803, 0x002F2804, 0x002F5C01,
- 0x002FCC08, 0x00300403, 0x0030F807, 0x00311803, 0x00312804,
- 0x00315402, 0x00318802, 0x0031FC01, 0x00320802, 0x0032F001,
- 0x0032F807, 0x00331803, 0x00332804, 0x00335402, 0x00338802,
- 0x00340802, 0x0034F807, 0x00351803, 0x00352804, 0x00355C01,
- 0x00358802, 0x0035E401, 0x00360802, 0x00372801, 0x00373C06,
- 0x00375801, 0x00376008, 0x0037C803, 0x0038C401, 0x0038D007,
- 0x0038FC01, 0x00391C09, 0x00396802, 0x003AC401, 0x003AD006,
- 0x003AEC02, 0x003B2006, 0x003C041F, 0x003CD00C, 0x003DC417,
- 0x003E340B, 0x003E6424, 0x003EF80F, 0x003F380D, 0x0040AC14,
- 0x00412806, 0x00415804, 0x00417803, 0x00418803, 0x00419C07,
- 0x0041C404, 0x0042080C, 0x00423C01, 0x00426806, 0x0043EC01,
- 0x004D740C, 0x004E400A, 0x00500001, 0x0059B402, 0x005A0001,
- 0x005A6C02, 0x005BAC03, 0x005C4803, 0x005CC805, 0x005D4802,
- 0x005DC802, 0x005ED023, 0x005F6004, 0x005F7401, 0x0060000F,
- 0x0062A401, 0x0064800C, 0x0064C00C, 0x00650001, 0x00651002,
- 0x0066C011, 0x00672002, 0x00677822, 0x00685C05, 0x00687802,
- 0x0069540A, 0x0069801D, 0x0069FC01, 0x006A8007, 0x006AA006,
- 0x006C0005, 0x006CD011, 0x006D6823, 0x006E0003, 0x006E840D,
- 0x006F980E, 0x006FF004, 0x00709014, 0x0070EC05, 0x0071F802,
- 0x00730008, 0x00734019, 0x0073B401, 0x0073C803, 0x00770027,
- 0x0077F004, 0x007EF401, 0x007EFC03, 0x007F3403, 0x007F7403,
- 0x007FB403, 0x007FF402, 0x00800065, 0x0081A806, 0x0081E805,
- 0x00822805, 0x0082801A, 0x00834021, 0x00840002, 0x00840C04,
- 0x00842002, 0x00845001, 0x00845803, 0x00847806, 0x00849401,
- 0x00849C01, 0x0084A401, 0x0084B801, 0x0084E802, 0x00850005,
- 0x00852804, 0x00853C01, 0x00864264, 0x00900027, 0x0091000B,
- 0x0092704E, 0x00940200, 0x009C0475, 0x009E53B9, 0x00AD400A,
- 0x00B39406, 0x00B3BC03, 0x00B3E404, 0x00B3F802, 0x00B5C001,
- 0x00B5FC01, 0x00B7804F, 0x00B8C00C, 0x00BA001A, 0x00BA6C59,
- 0x00BC00D6, 0x00BFC00C, 0x00C00005, 0x00C02019, 0x00C0A807,
- 0x00C0D802, 0x00C0F403, 0x00C26404, 0x00C28001, 0x00C3EC01,
- 0x00C64002, 0x00C6580A, 0x00C70024, 0x00C8001F, 0x00C8A81E,
- 0x00C94001, 0x00C98020, 0x00CA2827, 0x00CB003F, 0x00CC0100,
- 0x01370040, 0x02924037, 0x0293F802, 0x02983403, 0x0299BC10,
- 0x029A7C01, 0x029BC008, 0x029C0017, 0x029C8002, 0x029E2402,
- 0x02A00801, 0x02A01801, 0x02A02C01, 0x02A08C09, 0x02A0D804,
- 0x02A1D004, 0x02A20002, 0x02A2D011, 0x02A33802, 0x02A38012,
- 0x02A3E003, 0x02A4980A, 0x02A51C0D, 0x02A57C01, 0x02A60004,
- 0x02A6CC1B, 0x02A77802, 0x02A8A40E, 0x02A90C01, 0x02A93002,
- 0x02A97004, 0x02A9DC03, 0x02A9EC01, 0x02AAC001, 0x02AAC803,
- 0x02AADC02, 0x02AAF802, 0x02AB0401, 0x02AB7802, 0x02ABAC07,
- 0x02ABD402, 0x02AF8C0B, 0x03600001, 0x036DFC02, 0x036FFC02,
- 0x037FFC01, 0x03EC7801, 0x03ECA401, 0x03EEC810, 0x03F4F802,
- 0x03F7F002, 0x03F8001A, 0x03F88007, 0x03F8C023, 0x03F95013,
- 0x03F9A004, 0x03FBFC01, 0x03FC040F, 0x03FC6807, 0x03FCEC06,
- 0x03FD6C0B, 0x03FF8007, 0x03FFA007, 0x03FFE405, 0x04040003,
- 0x0404DC09, 0x0405E411, 0x0406400C, 0x0407402E, 0x040E7C01,
- 0x040F4001, 0x04215C01, 0x04247C01, 0x0424FC01, 0x04280403,
- 0x04281402, 0x04283004, 0x0428E003, 0x0428FC01, 0x04294009,
- 0x0429FC01, 0x042CE407, 0x04400003, 0x0440E016, 0x04420003,
- 0x0442C012, 0x04440003, 0x04449C0E, 0x04450004, 0x04460003,
- 0x0446CC0E, 0x04471404, 0x045AAC0D, 0x0491C004, 0x05BD442E,
- 0x05BE3C04, 0x074000F6, 0x07440027, 0x0744A4B5, 0x07480046,
- 0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01, 0x075C5401,
- 0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401, 0x075EA401,
- 0x075F0C01, 0x07BBC002, 0x07C0002C, 0x07C0C064, 0x07C2800F,
- 0x07C2C40E, 0x07C3040F, 0x07C3440F, 0x07C4401F, 0x07C4C03C,
- 0x07C5C02B, 0x07C7981D, 0x07C8402B, 0x07C90009, 0x07C94002,
- 0x07CC0021, 0x07CCC006, 0x07CCDC46, 0x07CE0014, 0x07CE8025,
- 0x07CF1805, 0x07CF8011, 0x07D0003F, 0x07D10001, 0x07D108B6,
- 0x07D3E404, 0x07D4003E, 0x07D50004, 0x07D54018, 0x07D7EC46,
- 0x07D9140B, 0x07DA0046, 0x07DC0074, 0x38000401, 0x38008060,
- 0x380400F0,
- };
- static const unsigned int aAscii[4] = {
- 0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001,
- };
-
- if( (unsigned int)c<128 ){
- return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
- }else if( (unsigned int)c<(1<<22) ){
- unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
- int iRes = 0;
- int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
- int iLo = 0;
- while( iHi>=iLo ){
- int iTest = (iHi + iLo) / 2;
- if( key >= aEntry[iTest] ){
- iRes = iTest;
- iLo = iTest+1;
- }else{
- iHi = iTest-1;
- }
- }
- assert( aEntry[0]<key );
- assert( key>=aEntry[iRes] );
- return (((unsigned int)c) >= ((aEntry[iRes]>>10) + (aEntry[iRes]&0x3FF)));
- }
- return 1;
-}
-
-
-/*
-** If the argument is a codepoint corresponding to a lowercase letter
-** in the ASCII range with a diacritic added, return the codepoint
-** of the ASCII letter only. For example, if passed 235 - "LATIN
-** SMALL LETTER E WITH DIAERESIS" - return 65 ("LATIN SMALL LETTER
-** E"). The resuls of passing a codepoint that corresponds to an
-** uppercase letter are undefined.
-*/
-static int fts5_remove_diacritic(int c){
- unsigned short aDia[] = {
- 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995,
- 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286,
- 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732,
- 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336,
- 3456, 3696, 3712, 3728, 3744, 3896, 3912, 3928,
- 3968, 4008, 4040, 4106, 4138, 4170, 4202, 4234,
- 4266, 4296, 4312, 4344, 4408, 4424, 4472, 4504,
- 6148, 6198, 6264, 6280, 6360, 6429, 6505, 6529,
- 61448, 61468, 61534, 61592, 61642, 61688, 61704, 61726,
- 61784, 61800, 61836, 61880, 61914, 61948, 61998, 62122,
- 62154, 62200, 62218, 62302, 62364, 62442, 62478, 62536,
- 62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730,
- 62924, 63050, 63082, 63274, 63390,
- };
- char aChar[] = {
- '\0', 'a', 'c', 'e', 'i', 'n', 'o', 'u', 'y', 'y', 'a', 'c',
- 'd', 'e', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'o', 'r',
- 's', 't', 'u', 'u', 'w', 'y', 'z', 'o', 'u', 'a', 'i', 'o',
- 'u', 'g', 'k', 'o', 'j', 'g', 'n', 'a', 'e', 'i', 'o', 'r',
- 'u', 's', 't', 'h', 'a', 'e', 'o', 'y', '\0', '\0', '\0', '\0',
- '\0', '\0', '\0', '\0', 'a', 'b', 'd', 'd', 'e', 'f', 'g', 'h',
- 'h', 'i', 'k', 'l', 'l', 'm', 'n', 'p', 'r', 'r', 's', 't',
- 'u', 'v', 'w', 'w', 'x', 'y', 'z', 'h', 't', 'w', 'y', 'a',
- 'e', 'i', 'o', 'u', 'y',
- };
-
- unsigned int key = (((unsigned int)c)<<3) | 0x00000007;
- int iRes = 0;
- int iHi = sizeof(aDia)/sizeof(aDia[0]) - 1;
- int iLo = 0;
- while( iHi>=iLo ){
- int iTest = (iHi + iLo) / 2;
- if( key >= aDia[iTest] ){
- iRes = iTest;
- iLo = iTest+1;
- }else{
- iHi = iTest-1;
- }
- }
- assert( key>=aDia[iRes] );
- return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]);
-}
-
-
-/*
-** Return true if the argument interpreted as a unicode codepoint
-** is a diacritical modifier character.
-*/
-static int sqlite3Fts5UnicodeIsdiacritic(int c){
- unsigned int mask0 = 0x08029FDF;
- unsigned int mask1 = 0x000361F8;
- if( c<768 || c>817 ) return 0;
- return (c < 768+32) ?
- (mask0 & (1 << (c-768))) :
- (mask1 & (1 << (c-768-32)));
-}
-
-
-/*
-** Interpret the argument as a unicode codepoint. If the codepoint
-** is an upper case character that has a lower case equivalent,
-** return the codepoint corresponding to the lower case version.
-** Otherwise, return a copy of the argument.
-**
-** The results are undefined if the value passed to this function
-** is less than zero.
-*/
-static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){
- /* Each entry in the following array defines a rule for folding a range
- ** of codepoints to lower case. The rule applies to a range of nRange
- ** codepoints starting at codepoint iCode.
- **
- ** If the least significant bit in flags is clear, then the rule applies
- ** to all nRange codepoints (i.e. all nRange codepoints are upper case and
- ** need to be folded). Or, if it is set, then the rule only applies to
- ** every second codepoint in the range, starting with codepoint C.
- **
- ** The 7 most significant bits in flags are an index into the aiOff[]
- ** array. If a specific codepoint C does require folding, then its lower
- ** case equivalent is ((C + aiOff[flags>>1]) & 0xFFFF).
- **
- ** The contents of this array are generated by parsing the CaseFolding.txt
- ** file distributed as part of the "Unicode Character Database". See
- ** http://www.unicode.org for details.
- */
- static const struct TableEntry {
- unsigned short iCode;
- unsigned char flags;
- unsigned char nRange;
- } aEntry[] = {
- {65, 14, 26}, {181, 64, 1}, {192, 14, 23},
- {216, 14, 7}, {256, 1, 48}, {306, 1, 6},
- {313, 1, 16}, {330, 1, 46}, {376, 116, 1},
- {377, 1, 6}, {383, 104, 1}, {385, 50, 1},
- {386, 1, 4}, {390, 44, 1}, {391, 0, 1},
- {393, 42, 2}, {395, 0, 1}, {398, 32, 1},
- {399, 38, 1}, {400, 40, 1}, {401, 0, 1},
- {403, 42, 1}, {404, 46, 1}, {406, 52, 1},
- {407, 48, 1}, {408, 0, 1}, {412, 52, 1},
- {413, 54, 1}, {415, 56, 1}, {416, 1, 6},
- {422, 60, 1}, {423, 0, 1}, {425, 60, 1},
- {428, 0, 1}, {430, 60, 1}, {431, 0, 1},
- {433, 58, 2}, {435, 1, 4}, {439, 62, 1},
- {440, 0, 1}, {444, 0, 1}, {452, 2, 1},
- {453, 0, 1}, {455, 2, 1}, {456, 0, 1},
- {458, 2, 1}, {459, 1, 18}, {478, 1, 18},
- {497, 2, 1}, {498, 1, 4}, {502, 122, 1},
- {503, 134, 1}, {504, 1, 40}, {544, 110, 1},
- {546, 1, 18}, {570, 70, 1}, {571, 0, 1},
- {573, 108, 1}, {574, 68, 1}, {577, 0, 1},
- {579, 106, 1}, {580, 28, 1}, {581, 30, 1},
- {582, 1, 10}, {837, 36, 1}, {880, 1, 4},
- {886, 0, 1}, {902, 18, 1}, {904, 16, 3},
- {908, 26, 1}, {910, 24, 2}, {913, 14, 17},
- {931, 14, 9}, {962, 0, 1}, {975, 4, 1},
- {976, 140, 1}, {977, 142, 1}, {981, 146, 1},
- {982, 144, 1}, {984, 1, 24}, {1008, 136, 1},
- {1009, 138, 1}, {1012, 130, 1}, {1013, 128, 1},
- {1015, 0, 1}, {1017, 152, 1}, {1018, 0, 1},
- {1021, 110, 3}, {1024, 34, 16}, {1040, 14, 32},
- {1120, 1, 34}, {1162, 1, 54}, {1216, 6, 1},
- {1217, 1, 14}, {1232, 1, 88}, {1329, 22, 38},
- {4256, 66, 38}, {4295, 66, 1}, {4301, 66, 1},
- {7680, 1, 150}, {7835, 132, 1}, {7838, 96, 1},
- {7840, 1, 96}, {7944, 150, 8}, {7960, 150, 6},
- {7976, 150, 8}, {7992, 150, 8}, {8008, 150, 6},
- {8025, 151, 8}, {8040, 150, 8}, {8072, 150, 8},
- {8088, 150, 8}, {8104, 150, 8}, {8120, 150, 2},
- {8122, 126, 2}, {8124, 148, 1}, {8126, 100, 1},
- {8136, 124, 4}, {8140, 148, 1}, {8152, 150, 2},
- {8154, 120, 2}, {8168, 150, 2}, {8170, 118, 2},
- {8172, 152, 1}, {8184, 112, 2}, {8186, 114, 2},
- {8188, 148, 1}, {8486, 98, 1}, {8490, 92, 1},
- {8491, 94, 1}, {8498, 12, 1}, {8544, 8, 16},
- {8579, 0, 1}, {9398, 10, 26}, {11264, 22, 47},
- {11360, 0, 1}, {11362, 88, 1}, {11363, 102, 1},
- {11364, 90, 1}, {11367, 1, 6}, {11373, 84, 1},
- {11374, 86, 1}, {11375, 80, 1}, {11376, 82, 1},
- {11378, 0, 1}, {11381, 0, 1}, {11390, 78, 2},
- {11392, 1, 100}, {11499, 1, 4}, {11506, 0, 1},
- {42560, 1, 46}, {42624, 1, 24}, {42786, 1, 14},
- {42802, 1, 62}, {42873, 1, 4}, {42877, 76, 1},
- {42878, 1, 10}, {42891, 0, 1}, {42893, 74, 1},
- {42896, 1, 4}, {42912, 1, 10}, {42922, 72, 1},
- {65313, 14, 26},
- };
- static const unsigned short aiOff[] = {
- 1, 2, 8, 15, 16, 26, 28, 32,
- 37, 38, 40, 48, 63, 64, 69, 71,
- 79, 80, 116, 202, 203, 205, 206, 207,
- 209, 210, 211, 213, 214, 217, 218, 219,
- 775, 7264, 10792, 10795, 23228, 23256, 30204, 54721,
- 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274,
- 57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406,
- 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462,
- 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511,
- 65514, 65521, 65527, 65528, 65529,
- };
-
- int ret = c;
-
- assert( sizeof(unsigned short)==2 && sizeof(unsigned char)==1 );
-
- if( c<128 ){
- if( c>='A' && c<='Z' ) ret = c + ('a' - 'A');
- }else if( c<65536 ){
- const struct TableEntry *p;
- int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
- int iLo = 0;
- int iRes = -1;
-
- assert( c>aEntry[0].iCode );
- while( iHi>=iLo ){
- int iTest = (iHi + iLo) / 2;
- int cmp = (c - aEntry[iTest].iCode);
- if( cmp>=0 ){
- iRes = iTest;
- iLo = iTest+1;
- }else{
- iHi = iTest-1;
- }
- }
-
- assert( iRes>=0 && c>=aEntry[iRes].iCode );
- p = &aEntry[iRes];
- if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){
- ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF;
- assert( ret>0 );
- }
-
- if( bRemoveDiacritic ) ret = fts5_remove_diacritic(ret);
- }
-
- else if( c>=66560 && c<66600 ){
- ret = c + 40;
- }
-
- return ret;
-}
-
-/*
-** 2015 May 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.
-**
-******************************************************************************
-**
-** Routines for varint serialization and deserialization.
-*/
-
-
-/* #include "fts5Int.h" */
-
-/*
-** This is a copy of the sqlite3GetVarint32() routine from the SQLite core.
-** Except, this version does handle the single byte case that the core
-** version depends on being handled before its function is called.
-*/
-static int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v){
- u32 a,b;
-
- /* The 1-byte case. Overwhelmingly the most common. */
- a = *p;
- /* a: p0 (unmasked) */
- if (!(a&0x80))
- {
- /* Values between 0 and 127 */
- *v = a;
- return 1;
- }
-
- /* The 2-byte case */
- p++;
- b = *p;
- /* b: p1 (unmasked) */
- if (!(b&0x80))
- {
- /* Values between 128 and 16383 */
- a &= 0x7f;
- a = a<<7;
- *v = a | b;
- return 2;
- }
-
- /* The 3-byte case */
- p++;
- a = a<<14;
- a |= *p;
- /* a: p0<<14 | p2 (unmasked) */
- if (!(a&0x80))
- {
- /* Values between 16384 and 2097151 */
- a &= (0x7f<<14)|(0x7f);
- b &= 0x7f;
- b = b<<7;
- *v = a | b;
- return 3;
- }
-
- /* A 32-bit varint is used to store size information in btrees.
- ** Objects are rarely larger than 2MiB limit of a 3-byte varint.
- ** A 3-byte varint is sufficient, for example, to record the size
- ** of a 1048569-byte BLOB or string.
- **
- ** We only unroll the first 1-, 2-, and 3- byte cases. The very
- ** rare larger cases can be handled by the slower 64-bit varint
- ** routine.
- */
- {
- u64 v64;
- u8 n;
- p -= 2;
- n = sqlite3Fts5GetVarint(p, &v64);
- *v = (u32)v64;
- assert( n>3 && n<=9 );
- return n;
- }
-}
-
-
-/*
-** Bitmasks used by sqlite3GetVarint(). These precomputed constants
-** are defined here rather than simply putting the constant expressions
-** inline in order to work around bugs in the RVT compiler.
-**
-** SLOT_2_0 A mask for (0x7f<<14) | 0x7f
-**
-** SLOT_4_2_0 A mask for (0x7f<<28) | SLOT_2_0
-*/
-#define SLOT_2_0 0x001fc07f
-#define SLOT_4_2_0 0xf01fc07f
-
-/*
-** Read a 64-bit variable-length integer from memory starting at p[0].
-** Return the number of bytes read. The value is stored in *v.
-*/
-static u8 sqlite3Fts5GetVarint(const unsigned char *p, u64 *v){
- u32 a,b,s;
-
- a = *p;
- /* a: p0 (unmasked) */
- if (!(a&0x80))
- {
- *v = a;
- return 1;
- }
-
- p++;
- b = *p;
- /* b: p1 (unmasked) */
- if (!(b&0x80))
- {
- a &= 0x7f;
- a = a<<7;
- a |= b;
- *v = a;
- return 2;
- }
-
- /* Verify that constants are precomputed correctly */
- assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) );
- assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) );
-
- p++;
- a = a<<14;
- a |= *p;
- /* a: p0<<14 | p2 (unmasked) */
- if (!(a&0x80))
- {
- a &= SLOT_2_0;
- b &= 0x7f;
- b = b<<7;
- a |= b;
- *v = a;
- return 3;
- }
-
- /* CSE1 from below */
- a &= SLOT_2_0;
- p++;
- b = b<<14;
- b |= *p;
- /* b: p1<<14 | p3 (unmasked) */
- if (!(b&0x80))
- {
- b &= SLOT_2_0;
- /* moved CSE1 up */
- /* a &= (0x7f<<14)|(0x7f); */
- a = a<<7;
- a |= b;
- *v = a;
- return 4;
- }
-
- /* a: p0<<14 | p2 (masked) */
- /* b: p1<<14 | p3 (unmasked) */
- /* 1:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
- /* moved CSE1 up */
- /* a &= (0x7f<<14)|(0x7f); */
- b &= SLOT_2_0;
- s = a;
- /* s: p0<<14 | p2 (masked) */
-
- p++;
- a = a<<14;
- a |= *p;
- /* a: p0<<28 | p2<<14 | p4 (unmasked) */
- if (!(a&0x80))
- {
- /* we can skip these cause they were (effectively) done above in calc'ing s */
- /* a &= (0x7f<<28)|(0x7f<<14)|(0x7f); */
- /* b &= (0x7f<<14)|(0x7f); */
- b = b<<7;
- a |= b;
- s = s>>18;
- *v = ((u64)s)<<32 | a;
- return 5;
- }
-
- /* 2:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
- s = s<<7;
- s |= b;
- /* s: p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
-
- p++;
- b = b<<14;
- b |= *p;
- /* b: p1<<28 | p3<<14 | p5 (unmasked) */
- if (!(b&0x80))
- {
- /* we can skip this cause it was (effectively) done above in calc'ing s */
- /* b &= (0x7f<<28)|(0x7f<<14)|(0x7f); */
- a &= SLOT_2_0;
- a = a<<7;
- a |= b;
- s = s>>18;
- *v = ((u64)s)<<32 | a;
- return 6;
- }
-
- p++;
- a = a<<14;
- a |= *p;
- /* a: p2<<28 | p4<<14 | p6 (unmasked) */
- if (!(a&0x80))
- {
- a &= SLOT_4_2_0;
- b &= SLOT_2_0;
- b = b<<7;
- a |= b;
- s = s>>11;
- *v = ((u64)s)<<32 | a;
- return 7;
- }
-
- /* CSE2 from below */
- a &= SLOT_2_0;
- p++;
- b = b<<14;
- b |= *p;
- /* b: p3<<28 | p5<<14 | p7 (unmasked) */
- if (!(b&0x80))
- {
- b &= SLOT_4_2_0;
- /* moved CSE2 up */
- /* a &= (0x7f<<14)|(0x7f); */
- a = a<<7;
- a |= b;
- s = s>>4;
- *v = ((u64)s)<<32 | a;
- return 8;
- }
-
- p++;
- a = a<<15;
- a |= *p;
- /* a: p4<<29 | p6<<15 | p8 (unmasked) */
-
- /* moved CSE2 up */
- /* a &= (0x7f<<29)|(0x7f<<15)|(0xff); */
- b &= SLOT_2_0;
- b = b<<8;
- a |= b;
-
- s = s<<4;
- b = p[-4];
- b &= 0x7f;
- b = b>>3;
- s |= b;
-
- *v = ((u64)s)<<32 | a;
-
- return 9;
-}
-
-/*
-** The variable-length integer encoding is as follows:
-**
-** KEY:
-** A = 0xxxxxxx 7 bits of data and one flag bit
-** B = 1xxxxxxx 7 bits of data and one flag bit
-** C = xxxxxxxx 8 bits of data
-**
-** 7 bits - A
-** 14 bits - BA
-** 21 bits - BBA
-** 28 bits - BBBA
-** 35 bits - BBBBA
-** 42 bits - BBBBBA
-** 49 bits - BBBBBBA
-** 56 bits - BBBBBBBA
-** 64 bits - BBBBBBBBC
-*/
-
-#ifdef SQLITE_NOINLINE
-# define FTS5_NOINLINE SQLITE_NOINLINE
-#else
-# define FTS5_NOINLINE
-#endif
-
-/*
-** Write a 64-bit variable-length integer to memory starting at p[0].
-** The length of data write will be between 1 and 9 bytes. The number
-** of bytes written is returned.
-**
-** A variable-length integer consists of the lower 7 bits of each byte
-** for all bytes that have the 8th bit set and one byte with the 8th
-** bit clear. Except, if we get to the 9th byte, it stores the full
-** 8 bits and is the last byte.
-*/
-static int FTS5_NOINLINE fts5PutVarint64(unsigned char *p, u64 v){
- int i, j, n;
- u8 buf[10];
- if( v & (((u64)0xff000000)<<32) ){
- p[8] = (u8)v;
- v >>= 8;
- for(i=7; i>=0; i--){
- p[i] = (u8)((v & 0x7f) | 0x80);
- v >>= 7;
- }
- return 9;
- }
- n = 0;
- do{
- buf[n++] = (u8)((v & 0x7f) | 0x80);
- v >>= 7;
- }while( v!=0 );
- buf[0] &= 0x7f;
- assert( n<=9 );
- for(i=0, j=n-1; j>=0; j--, i++){
- p[i] = buf[j];
- }
- return n;
-}
-
-static int sqlite3Fts5PutVarint(unsigned char *p, u64 v){
- if( v<=0x7f ){
- p[0] = v&0x7f;
- return 1;
- }
- if( v<=0x3fff ){
- p[0] = ((v>>7)&0x7f)|0x80;
- p[1] = v&0x7f;
- return 2;
- }
- return fts5PutVarint64(p,v);
-}
-
-
-static int sqlite3Fts5GetVarintLen(u32 iVal){
-#if 0
- if( iVal<(1 << 7 ) ) return 1;
-#endif
- assert( iVal>=(1 << 7) );
- if( iVal<(1 << 14) ) return 2;
- if( iVal<(1 << 21) ) return 3;
- if( iVal<(1 << 28) ) return 4;
- return 5;
-}
-
-
-/*
-** 2015 May 08
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This is an SQLite virtual table module implementing direct access to an
-** existing FTS5 index. The module may create several different types of
-** tables:
-**
-** col:
-** CREATE TABLE vocab(term, col, doc, cnt, PRIMARY KEY(term, col));
-**
-** One row for each term/column combination. The value of $doc is set to
-** the number of fts5 rows that contain at least one instance of term
-** $term within column $col. Field $cnt is set to the total number of
-** instances of term $term in column $col (in any row of the fts5 table).
-**
-** row:
-** CREATE TABLE vocab(term, doc, cnt, PRIMARY KEY(term));
-**
-** One row for each term in the database. The value of $doc is set to
-** the number of fts5 rows that contain at least one instance of term
-** $term. Field $cnt is set to the total number of instances of term
-** $term in the database.
-*/
-
-
-/* #include "fts5Int.h" */
-
-
-typedef struct Fts5VocabTable Fts5VocabTable;
-typedef struct Fts5VocabCursor Fts5VocabCursor;
-
-struct Fts5VocabTable {
- sqlite3_vtab base;
- char *zFts5Tbl; /* Name of fts5 table */
- char *zFts5Db; /* Db containing fts5 table */
- sqlite3 *db; /* Database handle */
- Fts5Global *pGlobal; /* FTS5 global object for this database */
- int eType; /* FTS5_VOCAB_COL or ROW */
-};
-
-struct Fts5VocabCursor {
- sqlite3_vtab_cursor base;
- sqlite3_stmt *pStmt; /* Statement holding lock on pIndex */
- Fts5Index *pIndex; /* Associated FTS5 index */
-
- int bEof; /* True if this cursor is at EOF */
- Fts5IndexIter *pIter; /* Term/rowid iterator object */
-
- int nLeTerm; /* Size of zLeTerm in bytes */
- char *zLeTerm; /* (term <= $zLeTerm) paramater, or NULL */
-
- /* These are used by 'col' tables only */
- Fts5Config *pConfig; /* Fts5 table configuration */
- int iCol;
- i64 *aCnt;
- i64 *aDoc;
-
- /* Output values used by 'row' and 'col' tables */
- i64 rowid; /* This table's current rowid value */
- Fts5Buffer term; /* Current value of 'term' column */
-};
-
-#define FTS5_VOCAB_COL 0
-#define FTS5_VOCAB_ROW 1
-
-#define FTS5_VOCAB_COL_SCHEMA "term, col, doc, cnt"
-#define FTS5_VOCAB_ROW_SCHEMA "term, doc, cnt"
-
-/*
-** Bits for the mask used as the idxNum value by xBestIndex/xFilter.
-*/
-#define FTS5_VOCAB_TERM_EQ 0x01
-#define FTS5_VOCAB_TERM_GE 0x02
-#define FTS5_VOCAB_TERM_LE 0x04
-
-
-/*
-** Translate a string containing an fts5vocab table type to an
-** FTS5_VOCAB_XXX constant. If successful, set *peType to the output
-** value and return SQLITE_OK. Otherwise, set *pzErr to an error message
-** and return SQLITE_ERROR.
-*/
-static int fts5VocabTableType(const char *zType, char **pzErr, int *peType){
- int rc = SQLITE_OK;
- char *zCopy = sqlite3Fts5Strndup(&rc, zType, -1);
- if( rc==SQLITE_OK ){
- sqlite3Fts5Dequote(zCopy);
- if( sqlite3_stricmp(zCopy, "col")==0 ){
- *peType = FTS5_VOCAB_COL;
- }else
-
- if( sqlite3_stricmp(zCopy, "row")==0 ){
- *peType = FTS5_VOCAB_ROW;
- }else
- {
- *pzErr = sqlite3_mprintf("fts5vocab: unknown table type: %Q", zCopy);
- rc = SQLITE_ERROR;
- }
- sqlite3_free(zCopy);
- }
-
- return rc;
-}
-
-
-/*
-** The xDisconnect() virtual table method.
-*/
-static int fts5VocabDisconnectMethod(sqlite3_vtab *pVtab){
- Fts5VocabTable *pTab = (Fts5VocabTable*)pVtab;
- sqlite3_free(pTab);
- return SQLITE_OK;
-}
-
-/*
-** The xDestroy() virtual table method.
-*/
-static int fts5VocabDestroyMethod(sqlite3_vtab *pVtab){
- Fts5VocabTable *pTab = (Fts5VocabTable*)pVtab;
- sqlite3_free(pTab);
- return SQLITE_OK;
-}
-
-/*
-** This function is the implementation of both the xConnect and xCreate
-** methods of the FTS3 virtual table.
-**
-** The argv[] array contains the following:
-**
-** argv[0] -> module name ("fts5vocab")
-** argv[1] -> database name
-** argv[2] -> table name
-**
-** then:
-**
-** argv[3] -> name of fts5 table
-** argv[4] -> type of fts5vocab table
-**
-** or, for tables in the TEMP schema only.
-**
-** argv[3] -> name of fts5 tables database
-** argv[4] -> name of fts5 table
-** argv[5] -> type of fts5vocab table
-*/
-static int fts5VocabInitVtab(
- sqlite3 *db, /* The SQLite database connection */
- void *pAux, /* Pointer to Fts5Global object */
- int argc, /* Number of elements in argv array */
- const char * const *argv, /* xCreate/xConnect argument array */
- sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */
- char **pzErr /* Write any error message here */
-){
- const char *azSchema[] = {
- "CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA ")",
- "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA ")"
- };
-
- Fts5VocabTable *pRet = 0;
- int rc = SQLITE_OK; /* Return code */
- int bDb;
-
- bDb = (argc==6 && strlen(argv[1])==4 && memcmp("temp", argv[1], 4)==0);
-
- if( argc!=5 && bDb==0 ){
- *pzErr = sqlite3_mprintf("wrong number of vtable arguments");
- rc = SQLITE_ERROR;
- }else{
- int nByte; /* Bytes of space to allocate */
- const char *zDb = bDb ? argv[3] : argv[1];
- const char *zTab = bDb ? argv[4] : argv[3];
- const char *zType = bDb ? argv[5] : argv[4];
- int nDb = (int)strlen(zDb)+1;
- int nTab = (int)strlen(zTab)+1;
- int eType = 0;
-
- rc = fts5VocabTableType(zType, pzErr, &eType);
- if( rc==SQLITE_OK ){
- assert( eType>=0 && eType<ArraySize(azSchema) );
- rc = sqlite3_declare_vtab(db, azSchema[eType]);
- }
-
- nByte = sizeof(Fts5VocabTable) + nDb + nTab;
- pRet = sqlite3Fts5MallocZero(&rc, nByte);
- if( pRet ){
- pRet->pGlobal = (Fts5Global*)pAux;
- pRet->eType = eType;
- pRet->db = db;
- pRet->zFts5Tbl = (char*)&pRet[1];
- pRet->zFts5Db = &pRet->zFts5Tbl[nTab];
- memcpy(pRet->zFts5Tbl, zTab, nTab);
- memcpy(pRet->zFts5Db, zDb, nDb);
- sqlite3Fts5Dequote(pRet->zFts5Tbl);
- sqlite3Fts5Dequote(pRet->zFts5Db);
- }
- }
-
- *ppVTab = (sqlite3_vtab*)pRet;
- return rc;
-}
-
-
-/*
-** The xConnect() and xCreate() methods for the virtual table. All the
-** work is done in function fts5VocabInitVtab().
-*/
-static int fts5VocabConnectMethod(
- sqlite3 *db, /* Database connection */
- void *pAux, /* Pointer to tokenizer hash table */
- int argc, /* Number of elements in argv array */
- const char * const *argv, /* xCreate/xConnect argument array */
- sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
- char **pzErr /* OUT: sqlite3_malloc'd error message */
-){
- return fts5VocabInitVtab(db, pAux, argc, argv, ppVtab, pzErr);
-}
-static int fts5VocabCreateMethod(
- sqlite3 *db, /* Database connection */
- void *pAux, /* Pointer to tokenizer hash table */
- int argc, /* Number of elements in argv array */
- const char * const *argv, /* xCreate/xConnect argument array */
- sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */
- char **pzErr /* OUT: sqlite3_malloc'd error message */
-){
- return fts5VocabInitVtab(db, pAux, argc, argv, ppVtab, pzErr);
-}
-
-/*
-** Implementation of the xBestIndex method.
-*/
-static int fts5VocabBestIndexMethod(
- sqlite3_vtab *pUnused,
- sqlite3_index_info *pInfo
-){
- int i;
- int iTermEq = -1;
- int iTermGe = -1;
- int iTermLe = -1;
- int idxNum = 0;
- int nArg = 0;
-
- UNUSED_PARAM(pUnused);
-
- for(i=0; i<pInfo->nConstraint; i++){
- struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
- if( p->usable==0 ) continue;
- if( p->iColumn==0 ){ /* term column */
- if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ) iTermEq = i;
- if( p->op==SQLITE_INDEX_CONSTRAINT_LE ) iTermLe = i;
- if( p->op==SQLITE_INDEX_CONSTRAINT_LT ) iTermLe = i;
- if( p->op==SQLITE_INDEX_CONSTRAINT_GE ) iTermGe = i;
- if( p->op==SQLITE_INDEX_CONSTRAINT_GT ) iTermGe = i;
- }
- }
-
- if( iTermEq>=0 ){
- idxNum |= FTS5_VOCAB_TERM_EQ;
- pInfo->aConstraintUsage[iTermEq].argvIndex = ++nArg;
- pInfo->estimatedCost = 100;
- }else{
- pInfo->estimatedCost = 1000000;
- if( iTermGe>=0 ){
- idxNum |= FTS5_VOCAB_TERM_GE;
- pInfo->aConstraintUsage[iTermGe].argvIndex = ++nArg;
- pInfo->estimatedCost = pInfo->estimatedCost / 2;
- }
- if( iTermLe>=0 ){
- idxNum |= FTS5_VOCAB_TERM_LE;
- pInfo->aConstraintUsage[iTermLe].argvIndex = ++nArg;
- pInfo->estimatedCost = pInfo->estimatedCost / 2;
- }
- }
-
- pInfo->idxNum = idxNum;
-
- return SQLITE_OK;
-}
-
-/*
-** Implementation of xOpen method.
-*/
-static int fts5VocabOpenMethod(
- sqlite3_vtab *pVTab,
- sqlite3_vtab_cursor **ppCsr
-){
- Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab;
- Fts5Index *pIndex = 0;
- Fts5Config *pConfig = 0;
- Fts5VocabCursor *pCsr = 0;
- int rc = SQLITE_OK;
- sqlite3_stmt *pStmt = 0;
- char *zSql = 0;
-
- zSql = sqlite3Fts5Mprintf(&rc,
- "SELECT t.%Q FROM %Q.%Q AS t WHERE t.%Q MATCH '*id'",
- pTab->zFts5Tbl, pTab->zFts5Db, pTab->zFts5Tbl, pTab->zFts5Tbl
- );
- if( zSql ){
- rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0);
- }
- sqlite3_free(zSql);
- assert( rc==SQLITE_OK || pStmt==0 );
- if( rc==SQLITE_ERROR ) rc = SQLITE_OK;
-
- if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
- i64 iId = sqlite3_column_int64(pStmt, 0);
- pIndex = sqlite3Fts5IndexFromCsrid(pTab->pGlobal, iId, &pConfig);
- }
-
- if( rc==SQLITE_OK && pIndex==0 ){
- rc = sqlite3_finalize(pStmt);
- pStmt = 0;
- if( rc==SQLITE_OK ){
- pVTab->zErrMsg = sqlite3_mprintf(
- "no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl
- );
- rc = SQLITE_ERROR;
- }
- }
-
- if( rc==SQLITE_OK ){
- int nByte = pConfig->nCol * sizeof(i64) * 2 + sizeof(Fts5VocabCursor);
- pCsr = (Fts5VocabCursor*)sqlite3Fts5MallocZero(&rc, nByte);
- }
-
- if( pCsr ){
- pCsr->pIndex = pIndex;
- pCsr->pStmt = pStmt;
- pCsr->pConfig = pConfig;
- pCsr->aCnt = (i64*)&pCsr[1];
- pCsr->aDoc = &pCsr->aCnt[pConfig->nCol];
- }else{
- sqlite3_finalize(pStmt);
- }
-
- *ppCsr = (sqlite3_vtab_cursor*)pCsr;
- return rc;
-}
-
-static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
- pCsr->rowid = 0;
- sqlite3Fts5IterClose(pCsr->pIter);
- pCsr->pIter = 0;
- sqlite3_free(pCsr->zLeTerm);
- pCsr->nLeTerm = -1;
- pCsr->zLeTerm = 0;
-}
-
-/*
-** Close the cursor. For additional information see the documentation
-** on the xClose method of the virtual table interface.
-*/
-static int fts5VocabCloseMethod(sqlite3_vtab_cursor *pCursor){
- Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
- fts5VocabResetCursor(pCsr);
- sqlite3Fts5BufferFree(&pCsr->term);
- sqlite3_finalize(pCsr->pStmt);
- sqlite3_free(pCsr);
- return SQLITE_OK;
-}
-
-
-/*
-** Advance the cursor to the next row in the table.
-*/
-static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
- Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
- Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab;
- int rc = SQLITE_OK;
- int nCol = pCsr->pConfig->nCol;
-
- pCsr->rowid++;
-
- if( pTab->eType==FTS5_VOCAB_COL ){
- for(pCsr->iCol++; pCsr->iCol<nCol; pCsr->iCol++){
- if( pCsr->aDoc[pCsr->iCol] ) break;
- }
- }
-
- if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=nCol ){
- if( sqlite3Fts5IterEof(pCsr->pIter) ){
- pCsr->bEof = 1;
- }else{
- const char *zTerm;
- int nTerm;
-
- zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
- if( pCsr->nLeTerm>=0 ){
- int nCmp = MIN(nTerm, pCsr->nLeTerm);
- int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp);
- if( bCmp<0 || (bCmp==0 && pCsr->nLeTerm<nTerm) ){
- pCsr->bEof = 1;
- return SQLITE_OK;
- }
- }
-
- sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm);
- memset(pCsr->aCnt, 0, nCol * sizeof(i64));
- memset(pCsr->aDoc, 0, nCol * sizeof(i64));
- pCsr->iCol = 0;
-
- assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW );
- while( rc==SQLITE_OK ){
- const u8 *pPos; int nPos; /* Position list */
- i64 iPos = 0; /* 64-bit position read from poslist */
- int iOff = 0; /* Current offset within position list */
-
- pPos = pCsr->pIter->pData;
- nPos = pCsr->pIter->nData;
- switch( pCsr->pConfig->eDetail ){
- case FTS5_DETAIL_FULL:
- pPos = pCsr->pIter->pData;
- nPos = pCsr->pIter->nData;
- if( pTab->eType==FTS5_VOCAB_ROW ){
- while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
- pCsr->aCnt[0]++;
- }
- pCsr->aDoc[0]++;
- }else{
- int iCol = -1;
- while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
- int ii = FTS5_POS2COLUMN(iPos);
- pCsr->aCnt[ii]++;
- if( iCol!=ii ){
- if( ii>=nCol ){
- rc = FTS5_CORRUPT;
- break;
- }
- pCsr->aDoc[ii]++;
- iCol = ii;
- }
- }
- }
- break;
-
- case FTS5_DETAIL_COLUMNS:
- if( pTab->eType==FTS5_VOCAB_ROW ){
- pCsr->aDoc[0]++;
- }else{
- while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff,&iPos) ){
- assert_nc( iPos>=0 && iPos<nCol );
- if( iPos>=nCol ){
- rc = FTS5_CORRUPT;
- break;
- }
- pCsr->aDoc[iPos]++;
- }
- }
- break;
-
- default:
- assert( pCsr->pConfig->eDetail==FTS5_DETAIL_NONE );
- pCsr->aDoc[0]++;
- break;
- }
-
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5IterNextScan(pCsr->pIter);
- }
-
- if( rc==SQLITE_OK ){
- zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
- if( nTerm!=pCsr->term.n || memcmp(zTerm, pCsr->term.p, nTerm) ){
- break;
- }
- if( sqlite3Fts5IterEof(pCsr->pIter) ) break;
- }
- }
- }
- }
-
- if( rc==SQLITE_OK && pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){
- while( pCsr->aDoc[pCsr->iCol]==0 ) pCsr->iCol++;
- assert( pCsr->iCol<pCsr->pConfig->nCol );
- }
- return rc;
-}
-
-/*
-** This is the xFilter implementation for the virtual table.
-*/
-static int fts5VocabFilterMethod(
- sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */
- int idxNum, /* Strategy index */
- const char *zUnused, /* Unused */
- int nUnused, /* Number of elements in apVal */
- sqlite3_value **apVal /* Arguments for the indexing scheme */
-){
- Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
- int rc = SQLITE_OK;
-
- int iVal = 0;
- int f = FTS5INDEX_QUERY_SCAN;
- const char *zTerm = 0;
- int nTerm = 0;
-
- sqlite3_value *pEq = 0;
- sqlite3_value *pGe = 0;
- sqlite3_value *pLe = 0;
-
- UNUSED_PARAM2(zUnused, nUnused);
-
- fts5VocabResetCursor(pCsr);
- if( idxNum & FTS5_VOCAB_TERM_EQ ) pEq = apVal[iVal++];
- if( idxNum & FTS5_VOCAB_TERM_GE ) pGe = apVal[iVal++];
- if( idxNum & FTS5_VOCAB_TERM_LE ) pLe = apVal[iVal++];
-
- if( pEq ){
- zTerm = (const char *)sqlite3_value_text(pEq);
- nTerm = sqlite3_value_bytes(pEq);
- f = 0;
- }else{
- if( pGe ){
- zTerm = (const char *)sqlite3_value_text(pGe);
- nTerm = sqlite3_value_bytes(pGe);
- }
- if( pLe ){
- const char *zCopy = (const char *)sqlite3_value_text(pLe);
- pCsr->nLeTerm = sqlite3_value_bytes(pLe);
- pCsr->zLeTerm = sqlite3_malloc(pCsr->nLeTerm+1);
- if( pCsr->zLeTerm==0 ){
- rc = SQLITE_NOMEM;
- }else{
- memcpy(pCsr->zLeTerm, zCopy, pCsr->nLeTerm+1);
- }
- }
- }
-
-
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5IndexQuery(pCsr->pIndex, zTerm, nTerm, f, 0, &pCsr->pIter);
- }
- if( rc==SQLITE_OK ){
- rc = fts5VocabNextMethod(pCursor);
- }
-
- return rc;
-}
-
-/*
-** This is the xEof method of the virtual table. SQLite calls this
-** routine to find out if it has reached the end of a result set.
-*/
-static int fts5VocabEofMethod(sqlite3_vtab_cursor *pCursor){
- Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
- return pCsr->bEof;
-}
-
-static int fts5VocabColumnMethod(
- sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */
- sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
- int iCol /* Index of column to read value from */
-){
- Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
- int eDetail = pCsr->pConfig->eDetail;
- int eType = ((Fts5VocabTable*)(pCursor->pVtab))->eType;
- i64 iVal = 0;
-
- if( iCol==0 ){
- sqlite3_result_text(
- pCtx, (const char*)pCsr->term.p, pCsr->term.n, SQLITE_TRANSIENT
- );
- }else if( eType==FTS5_VOCAB_COL ){
- assert( iCol==1 || iCol==2 || iCol==3 );
- if( iCol==1 ){
- if( eDetail!=FTS5_DETAIL_NONE ){
- const char *z = pCsr->pConfig->azCol[pCsr->iCol];
- sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
- }
- }else if( iCol==2 ){
- iVal = pCsr->aDoc[pCsr->iCol];
- }else{
- iVal = pCsr->aCnt[pCsr->iCol];
- }
- }else{
- assert( iCol==1 || iCol==2 );
- if( iCol==1 ){
- iVal = pCsr->aDoc[0];
- }else{
- iVal = pCsr->aCnt[0];
- }
- }
-
- if( iVal>0 ) sqlite3_result_int64(pCtx, iVal);
- return SQLITE_OK;
-}
-
-/*
-** This is the xRowid method. The SQLite core calls this routine to
-** retrieve the rowid for the current row of the result set. The
-** rowid should be written to *pRowid.
-*/
-static int fts5VocabRowidMethod(
- sqlite3_vtab_cursor *pCursor,
- sqlite_int64 *pRowid
-){
- Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
- *pRowid = pCsr->rowid;
- return SQLITE_OK;
-}
-
-static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){
- static const sqlite3_module fts5Vocab = {
- /* iVersion */ 2,
- /* xCreate */ fts5VocabCreateMethod,
- /* xConnect */ fts5VocabConnectMethod,
- /* xBestIndex */ fts5VocabBestIndexMethod,
- /* xDisconnect */ fts5VocabDisconnectMethod,
- /* xDestroy */ fts5VocabDestroyMethod,
- /* xOpen */ fts5VocabOpenMethod,
- /* xClose */ fts5VocabCloseMethod,
- /* xFilter */ fts5VocabFilterMethod,
- /* xNext */ fts5VocabNextMethod,
- /* xEof */ fts5VocabEofMethod,
- /* xColumn */ fts5VocabColumnMethod,
- /* xRowid */ fts5VocabRowidMethod,
- /* xUpdate */ 0,
- /* xBegin */ 0,
- /* xSync */ 0,
- /* xCommit */ 0,
- /* xRollback */ 0,
- /* xFindFunction */ 0,
- /* xRename */ 0,
- /* xSavepoint */ 0,
- /* xRelease */ 0,
- /* xRollbackTo */ 0,
- };
- void *p = (void*)pGlobal;
-
- return sqlite3_create_module_v2(db, "fts5vocab", &fts5Vocab, p, 0);
-}
-
-
-
-
-
-#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */
-
-/************** End of fts5.c ************************************************/
diff --git a/ext/sqlite3/libsqlite/sqlite3.h b/ext/sqlite3/libsqlite/sqlite3.h
index 313b5ec3cd..d43b63c107 100644
--- a/ext/sqlite3/libsqlite/sqlite3.h
+++ b/ext/sqlite3/libsqlite/sqlite3.h
@@ -23,7 +23,7 @@
**
** The official C-language API documentation for SQLite is derived
** from comments in this file. This file is the authoritative source
-** on how SQLite interfaces are supposed to operate.
+** on how SQLite interfaces are suppose to operate.
**
** The name of this file under configuration management is "sqlite.h.in".
** The makefile makes some minor changes to this file (such as inserting
@@ -111,9 +111,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.13.0"
-#define SQLITE_VERSION_NUMBER 3013000
-#define SQLITE_SOURCE_ID "2016-05-18 10:57:30 fc49f556e48970561d7ab6a2f24fdd7d9eb81ff2"
+#define SQLITE_VERSION "3.8.10.2"
+#define SQLITE_VERSION_NUMBER 3008010
+#define SQLITE_SOURCE_ID "2015-05-20 18:17:19 2ef4f3a5b1d1d0c4338f8243d40a2452cc1f7fe4"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -124,7 +124,7 @@ extern "C" {
** but are associated with the library instead of the header file. ^(Cautious
** programmers might include assert() statements in their application to
** verify that values returned by these interfaces match the macros in
-** the header, and thus ensure that the application is
+** the header, and thus insure that the application is
** compiled with matching library and header files.
**
** <blockquote><pre>
@@ -347,7 +347,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** from [sqlite3_malloc()] and passed back through the 5th parameter.
** To avoid memory leaks, the application should invoke [sqlite3_free()]
** on error message strings returned through the 5th parameter of
-** sqlite3_exec() after the error message string is no longer needed.
+** of sqlite3_exec() after the error message string is no longer needed.
** ^If the 5th parameter to sqlite3_exec() is not NULL and no errors
** occur, then sqlite3_exec() sets the pointer in its 5th parameter to
** NULL before returning.
@@ -374,7 +374,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** Restrictions:
**
** <ul>
-** <li> The application must ensure that the 1st parameter to sqlite3_exec()
+** <li> The application must insure that the 1st parameter to sqlite3_exec()
** is a valid and open [database connection].
** <li> The application must not close the [database connection] specified by
** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
@@ -477,8 +477,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8))
#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25<<8))
#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8))
-#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8))
-#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
@@ -794,13 +792,8 @@ struct sqlite3_io_methods {
** <li>[[SQLITE_FCNTL_FILE_POINTER]]
** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer
** to the [sqlite3_file] object associated with a particular database
-** connection. See also [SQLITE_FCNTL_JOURNAL_POINTER].
-**
-** <li>[[SQLITE_FCNTL_JOURNAL_POINTER]]
-** The [SQLITE_FCNTL_JOURNAL_POINTER] opcode is used to obtain a pointer
-** to the [sqlite3_file] object associated with the journal file (either
-** the [rollback journal] or the [write-ahead log]) for a particular database
-** connection. See also [SQLITE_FCNTL_FILE_POINTER].
+** connection. See the [sqlite3_file_control()] documentation for
+** additional information.
**
** <li>[[SQLITE_FCNTL_SYNC_OMITTED]]
** No longer in use.
@@ -887,15 +880,6 @@ struct sqlite3_io_methods {
** pointer in case this file-control is not implemented. This file-control
** is intended for diagnostic use only.
**
-** <li>[[SQLITE_FCNTL_VFS_POINTER]]
-** ^The [SQLITE_FCNTL_VFS_POINTER] opcode finds a pointer to the top-level
-** [VFSes] currently in use. ^(The argument X in
-** sqlite3_file_control(db,SQLITE_FCNTL_VFS_POINTER,X) must be
-** of type "[sqlite3_vfs] **". This opcodes will set *X
-** to a pointer to the top-level VFS.)^
-** ^When there are multiple VFS shims in the stack, this opcode finds the
-** upper-most shim only.
-**
** <li>[[SQLITE_FCNTL_PRAGMA]]
** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA]
** file control is sent to the open [sqlite3_file] object corresponding
@@ -979,14 +963,6 @@ struct sqlite3_io_methods {
** circumstances in order to fix a problem with priority inversion.
** Applications should <em>not</em> use this file-control.
**
-** <li>[[SQLITE_FCNTL_ZIPVFS]]
-** The [SQLITE_FCNTL_ZIPVFS] opcode is implemented by zipvfs only. All other
-** VFS should return SQLITE_NOTFOUND for this opcode.
-**
-** <li>[[SQLITE_FCNTL_RBU]]
-** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by
-** the RBU extension only. All other VFS should return SQLITE_NOTFOUND for
-** this opcode.
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@@ -1012,10 +988,6 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_COMMIT_PHASETWO 22
#define SQLITE_FCNTL_WIN32_SET_HANDLE 23
#define SQLITE_FCNTL_WAL_BLOCK 24
-#define SQLITE_FCNTL_ZIPVFS 25
-#define SQLITE_FCNTL_RBU 26
-#define SQLITE_FCNTL_VFS_POINTER 27
-#define SQLITE_FCNTL_JOURNAL_POINTER 28
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -1228,7 +1200,7 @@ struct sqlite3_vfs {
const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName);
/*
** The methods above are in versions 1 through 3 of the sqlite_vfs object.
- ** New fields may be appended in future versions. The iVersion
+ ** New fields may be appended in figure versions. The iVersion
** value will increment whenever this happens.
*/
};
@@ -1384,11 +1356,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
** applications and so this routine is usually not necessary. It is
** provided to support rare applications with unusual needs.
**
-** <b>The sqlite3_config() interface is not threadsafe. The application
-** must ensure that no other SQLite interfaces are invoked by other
-** threads while sqlite3_config() is running.</b>
-**
-** The sqlite3_config() interface
+** The sqlite3_config() interface is not threadsafe. The application
+** must insure that no other SQLite interfaces are invoked by other
+** threads while sqlite3_config() is running. Furthermore, sqlite3_config()
** may only be invoked prior to library initialization using
** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()].
** ^If sqlite3_config() is called after [sqlite3_initialize()] and before
@@ -1615,34 +1585,29 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
-** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool
+** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a static memory buffer
** that SQLite can use for the database page cache with the default page
** cache implementation.
-** This configuration option is a no-op if an application-define page
-** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2].
+** This configuration should not be used if an application-define page
+** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]
+** configuration option.
** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
-** 8-byte aligned memory (pMem), the size of each page cache line (sz),
-** and the number of cache lines (N).
+** 8-byte aligned
+** memory, the size of each page buffer (sz), and the number of pages (N).
** The sz argument should be the size of the largest database page
** (a power of two between 512 and 65536) plus some extra bytes for each
** page header. ^The number of extra bytes needed by the page header
-** can be determined using [SQLITE_CONFIG_PCACHE_HDRSZ].
+** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option
+** to [sqlite3_config()].
** ^It is harmless, apart from the wasted memory,
-** for the sz parameter to be larger than necessary. The pMem
-** argument must be either a NULL pointer or a pointer to an 8-byte
-** aligned block of memory of at least sz*N bytes, otherwise
-** subsequent behavior is undefined.
-** ^When pMem is not NULL, SQLite will strive to use the memory provided
-** to satisfy page cache needs, falling back to [sqlite3_malloc()] if
-** a page cache line is larger than sz bytes or if all of the pMem buffer
-** is exhausted.
-** ^If pMem is NULL and N is non-zero, then each database connection
-** does an initial bulk allocation for page cache memory
-** from [sqlite3_malloc()] sufficient for N cache lines if N is positive or
-** of -1024*N bytes if N is negative, . ^If additional
-** page cache memory is needed beyond what is provided by the initial
-** allocation, then SQLite goes to [sqlite3_malloc()] separately for each
-** additional cache line. </dd>
+** for the sz parameter to be larger than necessary. The first
+** argument should pointer to an 8-byte aligned block of memory that
+** is at least sz*N bytes of memory, otherwise subsequent behavior is
+** undefined.
+** ^SQLite will use the memory provided by the first argument to satisfy its
+** memory needs for the first N pages that it adds to cache. ^If additional
+** page cache memory is needed beyond what is provided by this option, then
+** SQLite goes to [sqlite3_malloc()] for the additional storage space.</dd>
**
** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer
@@ -1820,20 +1785,6 @@ struct sqlite3_mem_methods {
** is enabled (using the [PRAGMA threads] command) and the amount of content
** to be sorted exceeds the page size times the minimum of the
** [PRAGMA cache_size] setting and this value.
-**
-** [[SQLITE_CONFIG_STMTJRNL_SPILL]]
-** <dt>SQLITE_CONFIG_STMTJRNL_SPILL
-** <dd>^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which
-** becomes the [statement journal] spill-to-disk threshold.
-** [Statement journals] are held in memory until their size (in bytes)
-** exceeds this threshold, at which point they are written to disk.
-** Or if the threshold is -1, statement journals are always held
-** exclusively in memory.
-** Since many statement journals never become large, setting the spill
-** threshold to a value such as 64KiB can greatly reduce the amount of
-** I/O required to support statement rollback.
-** The default value for this setting is controlled by the
-** [SQLITE_STMTJRNL_SPILL] compile-time option.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -1861,7 +1812,6 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
-#define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -1919,43 +1869,11 @@ struct sqlite3_mem_methods {
** following this call. The second parameter may be a NULL pointer, in
** which case the trigger setting is not reported back. </dd>
**
-** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
-** <dd> ^This option is used to enable or disable the two-argument
-** version of the [fts3_tokenizer()] function which is part of the
-** [FTS3] full-text search engine extension.
-** There should be two additional arguments.
-** The first argument is an integer which is 0 to disable fts3_tokenizer() or
-** positive to enable fts3_tokenizer() or negative to leave the setting
-** unchanged.
-** The second parameter is a pointer to an integer into which
-** is written 0 or 1 to indicate whether fts3_tokenizer is disabled or enabled
-** following this call. The second parameter may be a NULL pointer, in
-** which case the new setting is not reported back. </dd>
-**
-** <dt>SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION</dt>
-** <dd> ^This option is used to enable or disable the [sqlite3_load_extension()]
-** interface independently of the [load_extension()] SQL function.
-** The [sqlite3_enable_load_extension()] API enables or disables both the
-** C-API [sqlite3_load_extension()] and the SQL function [load_extension()].
-** There should be two additional arguments.
-** When the first argument to this interface is 1, then only the C-API is
-** enabled and the SQL function remains disabled. If the first argment to
-** this interface is 0, then both the C-API and the SQL function are disabled.
-** If the first argument is -1, then no changes are made to state of either the
-** C-API or the SQL function.
-** The second parameter is a pointer to an integer into which
-** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface
-** is disabled or enabled following this call. The second parameter may
-** be a NULL pointer, in which case the new setting is not reported back.
-** </dd>
-**
** </dl>
*/
-#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
-#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
-#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
-#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */
-#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */
+#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
+#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
/*
@@ -3445,8 +3363,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
**
** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the
** [prepared statement] S has been stepped at least once using
-** [sqlite3_step(S)] but has neither run to completion (returned
-** [SQLITE_DONE] from [sqlite3_step(S)]) nor
+** [sqlite3_step(S)] but has not run to completion and/or has not
** been reset using [sqlite3_reset(S)]. ^The sqlite3_stmt_busy(S)
** interface returns false if S is a NULL pointer. If S is not a
** NULL pointer and is not a pointer to a valid [prepared statement]
@@ -3473,9 +3390,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*);
** Some interfaces require a protected sqlite3_value. Other interfaces
** will accept either a protected or an unprotected sqlite3_value.
** Every interface that accepts sqlite3_value arguments specifies
-** whether or not it requires a protected sqlite3_value. The
-** [sqlite3_value_dup()] interface can be used to construct a new
-** protected sqlite3_value from an unprotected sqlite3_value.
+** whether or not it requires a protected sqlite3_value.
**
** The terms "protected" and "unprotected" refer to whether or not
** a mutex is held. An internal mutex is held for a protected
@@ -3635,7 +3550,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(sqlite3_stmt*, int, const char
void(*)(void*), unsigned char encoding);
SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64);
/*
** CAPI3REF: Number Of SQL Parameters
@@ -3699,7 +3613,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*,
**
** See also: [sqlite3_bind_blob|sqlite3_bind()],
** [sqlite3_bind_parameter_count()], and
-** [sqlite3_bind_parameter_name()].
+** [sqlite3_bind_parameter_index()].
*/
SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
@@ -3979,6 +3893,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
** KEYWORDS: {column access functions}
** METHOD: sqlite3_stmt
**
+** These routines form the "result set" interface.
+**
** ^These routines return information about a single column of the current
** result row of a query. ^In every case the first argument is a pointer
** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*]
@@ -4038,14 +3954,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
** even empty strings, are always zero-terminated. ^The return
** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
**
-** <b>Warning:</b> ^The object returned by [sqlite3_column_value()] is an
-** [unprotected sqlite3_value] object. In a multithreaded environment,
-** an unprotected sqlite3_value object may only be used safely with
-** [sqlite3_bind_value()] and [sqlite3_result_value()].
+** ^The object returned by [sqlite3_column_value()] is an
+** [unprotected sqlite3_value] object. An unprotected sqlite3_value object
+** may only be used with [sqlite3_bind_value()] and [sqlite3_result_value()].
** If the [unprotected sqlite3_value] object returned by
** [sqlite3_column_value()] is used in any other way, including calls
** to routines like [sqlite3_value_int()], [sqlite3_value_text()],
-** or [sqlite3_value_bytes()], the behavior is not threadsafe.
+** or [sqlite3_value_bytes()], then the behavior is undefined.
**
** These routines attempt to convert the value where appropriate. ^For
** example, if the internal representation is FLOAT and a text result
@@ -4076,6 +3991,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
** </table>
** </blockquote>)^
**
+** The table above makes reference to standard C library functions atoi()
+** and atof(). SQLite does not really use these functions. It has its
+** own equivalent internal routines. The atoi() and atof() names are
+** 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
** calls to sqlite3_column_blob(), sqlite3_column_text(), and/or
** sqlite3_column_text16() may be invalidated.
@@ -4100,7 +4021,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
** 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 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>
@@ -4120,7 +4041,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
** ^The pointers returned are valid until a type conversion occurs as
** described above, or until [sqlite3_step()] or [sqlite3_reset()] or
** [sqlite3_finalize()] is called. ^The memory space used to hold strings
-** and BLOBs is freed automatically. Do <em>not</em> pass the pointers returned
+** and BLOBs is freed automatically. Do <b>not</b> pass the pointers returned
** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
** [sqlite3_free()].
**
@@ -4370,12 +4291,12 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
#endif
/*
-** CAPI3REF: Obtaining SQL Values
+** CAPI3REF: Obtaining SQL Function Parameter Values
** METHOD: sqlite3_value
**
** The C-language implementation of SQL functions and aggregates uses
** this set of interface routines to access the parameter values on
-** the function or aggregate.
+** the function or aggregate.
**
** The xFunc (for scalar functions) or xStep (for aggregates) parameters
** to [sqlite3_create_function()] and [sqlite3_create_function16()]
@@ -4429,39 +4350,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value*);
SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
/*
-** CAPI3REF: Finding The Subtype Of SQL Values
-** METHOD: sqlite3_value
-**
-** The sqlite3_value_subtype(V) function returns the subtype for
-** an [application-defined SQL function] argument V. The subtype
-** information can be used to pass a limited amount of context from
-** one SQL function to another. Use the [sqlite3_result_subtype()]
-** routine to set the subtype for the return value of an SQL function.
-**
-** SQLite makes no use of subtype itself. It merely passes the subtype
-** from the result of one [application-defined SQL function] into the
-** input of another.
-*/
-SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*);
-
-/*
-** CAPI3REF: Copy And Free SQL Values
-** METHOD: sqlite3_value
-**
-** ^The sqlite3_value_dup(V) interface makes a copy of the [sqlite3_value]
-** object D and returns a pointer to that copy. ^The [sqlite3_value] returned
-** is a [protected sqlite3_value] object even if the input is not.
-** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a
-** memory allocation fails.
-**
-** ^The sqlite3_value_free(V) interface frees an [sqlite3_value] object
-** previously obtained from [sqlite3_value_dup()]. ^If V is a NULL pointer
-** then sqlite3_value_free(V) is a harmless no-op.
-*/
-SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value*);
-SQLITE_API void SQLITE_STDCALL sqlite3_value_free(sqlite3_value*);
-
-/*
** CAPI3REF: Obtain Aggregate Function Context
** METHOD: sqlite3_context
**
@@ -4624,9 +4512,9 @@ typedef void (*sqlite3_destructor_type)(void*);
** to by the second parameter and which is N bytes long where N is the
** third parameter.
**
-** ^The sqlite3_result_zeroblob(C,N) and sqlite3_result_zeroblob64(C,N)
-** interfaces set the result of the application-defined function to be
-** a BLOB containing all zero bytes and N bytes in size.
+** ^The sqlite3_result_zeroblob() interfaces set the result of
+** the application-defined function to be a BLOB containing all zero
+** bytes and N bytes in size, where N is the value of the 2nd parameter.
**
** ^The sqlite3_result_double() interface sets the result from
** an application-defined function to be a floating point value specified
@@ -4708,7 +4596,7 @@ typedef void (*sqlite3_destructor_type)(void*);
** from [sqlite3_malloc()] before it returns.
**
** ^The sqlite3_result_value() interface sets the result of
-** the application-defined function to be a copy of the
+** the application-defined function to be a copy the
** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The
** sqlite3_result_value() interface makes a copy of the [sqlite3_value]
** so that the [sqlite3_value] specified in the parameter may change or
@@ -4741,22 +4629,6 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(sqlite3_context*, const v
SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context*, sqlite3_value*);
SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context*, int n);
-SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
-
-
-/*
-** CAPI3REF: Setting The Subtype Of An SQL Function
-** METHOD: sqlite3_context
-**
-** The sqlite3_result_subtype(C,T) function causes the subtype of
-** the result from the [application-defined SQL function] with
-** [sqlite3_context] C to be the value T. Only the lower 8 bits
-** of the subtype T are preserved in current versions of SQLite;
-** higher order bits are discarded.
-** The number of subtype bytes preserved by SQLite might increase
-** in future releases of SQLite.
-*/
-SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned int);
/*
** CAPI3REF: Define New Collating Sequences
@@ -5205,7 +5077,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
** ^The sqlite3_update_hook() interface registers a callback function
** with the [database connection] identified by the first argument
** to be invoked whenever a row is updated, inserted or deleted in
-** a [rowid table].
+** a rowid table.
** ^Any callback set by a previous call to this function
** for the same database connection is overridden.
**
@@ -5244,8 +5116,8 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
** on the same [database connection] D, or NULL for
** the first call on D.
**
-** See also the [sqlite3_commit_hook()], [sqlite3_rollback_hook()],
-** and [sqlite3_preupdate_hook()] interfaces.
+** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()]
+** interfaces.
*/
SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
sqlite3*,
@@ -5492,18 +5364,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
** should free this memory by calling [sqlite3_free()].
**
** ^Extension loading must be enabled using
-** [sqlite3_enable_load_extension()] or
-** [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],1,NULL)
-** prior to calling this API,
+** [sqlite3_enable_load_extension()] prior to calling this API,
** otherwise an error will be returned.
**
-** <b>Security warning:</b> It is recommended that the
-** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this
-** interface. The use of the [sqlite3_enable_load_extension()] interface
-** should be avoided. This will keep the SQL function [load_extension()]
-** disabled and prevent SQL injections from giving attackers
-** access to extension loading capabilities.
-**
** See also the [load_extension() SQL function].
*/
SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
@@ -5526,17 +5389,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
** ^Call the sqlite3_enable_load_extension() routine with onoff==1
** to turn extension loading on and call it with onoff==0 to turn
** it back off again.
-**
-** ^This interface enables or disables both the C-API
-** [sqlite3_load_extension()] and the SQL function [load_extension()].
-** Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..)
-** to enable or disable only the C-API.
-**
-** <b>Security warning:</b> It is recommended that extension loading
-** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method
-** rather than this interface, so the [load_extension()] SQL function
-** remains disabled. This will prevent SQL injections from giving attackers
-** access to extension loading capabilities.
*/
SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff);
@@ -5698,17 +5550,6 @@ struct sqlite3_module {
** ^Information about the ORDER BY clause is stored in aOrderBy[].
** ^Each term of aOrderBy records a column of the ORDER BY clause.
**
-** The colUsed field indicates which columns of the virtual table may be
-** required by the current scan. Virtual table columns are numbered from
-** zero in the order in which they appear within the CREATE TABLE statement
-** passed to sqlite3_declare_vtab(). For the first 63 columns (columns 0-62),
-** the corresponding bit is set within the colUsed mask if the column may be
-** required by SQLite. If the table has at least 64 columns and any column
-** to the right of the first 63 is required, then bit 63 of colUsed is also
-** set. In other words, column iCol may be required if the expression
-** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to
-** non-zero.
-**
** The [xBestIndex] method must fill aConstraintUsage[] with information
** about what parameters to pass to xFilter. ^If argvIndex>0 then
** the right-hand side of the corresponding aConstraint[] is evaluated
@@ -5734,37 +5575,19 @@ struct sqlite3_module {
** ^The estimatedRows value is an estimate of the number of rows that
** will be returned by the strategy.
**
-** The xBestIndex method may optionally populate the idxFlags field with a
-** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag -
-** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite
-** assumes that the strategy may visit at most one row.
-**
-** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
-** SQLite also assumes that if a call to the xUpdate() method is made as
-** part of the same statement to delete or update a virtual table row and the
-** implementation returns SQLITE_CONSTRAINT, then there is no need to rollback
-** any database changes. In other words, if the xUpdate() returns
-** SQLITE_CONSTRAINT, the database contents must be exactly as they were
-** before xUpdate was called. By contrast, if SQLITE_INDEX_SCAN_UNIQUE is not
-** set and xUpdate returns SQLITE_CONSTRAINT, any database changes made by
-** the xUpdate method are automatically rolled back by SQLite.
-**
** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
** structure for SQLite version 3.8.2. If a virtual table extension is
** used with an SQLite version earlier than 3.8.2, the results of attempting
** to read or write the estimatedRows field are undefined (but are likely
** to included crashing the application). The estimatedRows field should
** therefore only be used if [sqlite3_libversion_number()] returns a
-** value greater than or equal to 3008002. Similarly, the idxFlags field
-** was added for version 3.9.0. It may therefore only be used if
-** sqlite3_libversion_number() returns a value greater than or equal to
-** 3009000.
+** value greater than or equal to 3008002.
*/
struct sqlite3_index_info {
/* Inputs */
int nConstraint; /* Number of entries in aConstraint */
struct sqlite3_index_constraint {
- int iColumn; /* Column constrained. -1 for ROWID */
+ int iColumn; /* Column on left-hand side of constraint */
unsigned char op; /* Constraint operator */
unsigned char usable; /* True if this constraint is usable */
int iTermOffset; /* Used internally - xBestIndex should ignore */
@@ -5786,18 +5609,9 @@ struct sqlite3_index_info {
double estimatedCost; /* Estimated cost of using this index */
/* Fields below are only available in SQLite 3.8.2 and later */
sqlite3_int64 estimatedRows; /* Estimated number of rows returned */
- /* Fields below are only available in SQLite 3.9.0 and later */
- int idxFlags; /* Mask of SQLITE_INDEX_SCAN_* flags */
- /* Fields below are only available in SQLite 3.10.0 and later */
- sqlite3_uint64 colUsed; /* Input: Mask of columns used by statement */
};
/*
-** CAPI3REF: Virtual Table Scan Flags
-*/
-#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */
-
-/*
** CAPI3REF: Virtual Table Constraint Operator Codes
**
** These macros defined the allowed values for the
@@ -5805,15 +5619,12 @@ struct sqlite3_index_info {
** an operator that is part of a constraint term in the wHERE clause of
** a query that uses a [virtual table].
*/
-#define SQLITE_INDEX_CONSTRAINT_EQ 2
-#define SQLITE_INDEX_CONSTRAINT_GT 4
-#define SQLITE_INDEX_CONSTRAINT_LE 8
-#define SQLITE_INDEX_CONSTRAINT_LT 16
-#define SQLITE_INDEX_CONSTRAINT_GE 32
-#define SQLITE_INDEX_CONSTRAINT_MATCH 64
-#define SQLITE_INDEX_CONSTRAINT_LIKE 65
-#define SQLITE_INDEX_CONSTRAINT_GLOB 66
-#define SQLITE_INDEX_CONSTRAINT_REGEXP 67
+#define SQLITE_INDEX_CONSTRAINT_EQ 2
+#define SQLITE_INDEX_CONSTRAINT_GT 4
+#define SQLITE_INDEX_CONSTRAINT_LE 8
+#define SQLITE_INDEX_CONSTRAINT_LT 16
+#define SQLITE_INDEX_CONSTRAINT_GE 32
+#define SQLITE_INDEX_CONSTRAINT_MATCH 64
/*
** CAPI3REF: Register A Virtual Table Implementation
@@ -6061,7 +5872,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
**
** ^This function sets the database handle error code and message.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
+SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
/*
** CAPI3REF: Close A BLOB Handle
@@ -6257,9 +6068,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
** <li> SQLITE_MUTEX_STATIC_APP1
** <li> SQLITE_MUTEX_STATIC_APP2
** <li> SQLITE_MUTEX_STATIC_APP3
-** <li> SQLITE_MUTEX_STATIC_VFS1
-** <li> SQLITE_MUTEX_STATIC_VFS2
-** <li> SQLITE_MUTEX_STATIC_VFS3
** </ul>
**
** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
@@ -6461,9 +6269,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */
#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */
#define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */
-#define SQLITE_MUTEX_STATIC_VFS1 11 /* For use by built-in VFS */
-#define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */
-#define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */
/*
** CAPI3REF: Retrieve the mutex for a database connection
@@ -6677,8 +6482,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
** The value written into the *pCurrent parameter is undefined.</dd>)^
**
** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
-** <dd>The *pHighwater parameter records the deepest parser stack.
-** The *pCurrent value is undefined. The *pHighwater value is only
+** <dd>This parameter records the deepest parser stack. It is only
** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^
** </dl>
**
@@ -7175,7 +6979,7 @@ typedef struct sqlite3_backup sqlite3_backup;
** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
** an error.
**
-** ^A call to sqlite3_backup_init() will fail, returning NULL, if
+** ^A call to sqlite3_backup_init() will fail, returning SQLITE_ERROR, if
** there is already a read or read-write transaction open on the
** destination database.
**
@@ -7464,44 +7268,19 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *, const char *, int);
/*
** CAPI3REF: String Globbing
*
-** ^The [sqlite3_strglob(P,X)] interface returns zero if and only if
-** string X matches the [GLOB] pattern P.
-** ^The definition of [GLOB] pattern matching used in
+** ^The [sqlite3_strglob(P,X)] interface returns zero if string X matches
+** the glob pattern P, and it returns non-zero if string X does not match
+** the glob pattern P. ^The definition of glob pattern matching used in
** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the
-** SQL dialect understood by SQLite. ^The [sqlite3_strglob(P,X)] function
-** is case sensitive.
+** SQL dialect used by SQLite. ^The sqlite3_strglob(P,X) function is case
+** sensitive.
**
** Note that this routine returns zero on a match and non-zero if the strings
** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
-**
-** See also: [sqlite3_strlike()].
*/
SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zStr);
/*
-** CAPI3REF: String LIKE Matching
-*
-** ^The [sqlite3_strlike(P,X,E)] interface returns zero if and only if
-** string X matches the [LIKE] pattern P with escape character E.
-** ^The definition of [LIKE] pattern matching used in
-** [sqlite3_strlike(P,X,E)] is the same as for the "X LIKE P ESCAPE E"
-** operator in the SQL dialect understood by SQLite. ^For "X LIKE P" without
-** the ESCAPE clause, set the E parameter of [sqlite3_strlike(P,X,E)] to 0.
-** ^As with the LIKE operator, the [sqlite3_strlike(P,X,E)] function is case
-** insensitive - equivalent upper and lower case ASCII characters match
-** one another.
-**
-** ^The [sqlite3_strlike(P,X,E)] function matches Unicode characters, though
-** only ASCII characters are case folded.
-**
-** Note that this routine returns zero on a match and non-zero if the strings
-** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
-**
-** See also: [sqlite3_strglob()].
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc);
-
-/*
** CAPI3REF: Error Logging Interface
**
** ^The [sqlite3_log()] interface writes a message into the [error log]
@@ -7556,7 +7335,7 @@ SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...)
** previously registered write-ahead log callback. ^Note that the
** [sqlite3_wal_autocheckpoint()] interface and the
** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
-** overwrite any prior [sqlite3_wal_hook()] settings.
+** those overwrite any prior [sqlite3_wal_hook()] settings.
*/
SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
sqlite3*,
@@ -7903,7 +7682,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *);
**
** See also: [sqlite3_stmt_scanstatus_reset()]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
+SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_stmt_scanstatus(
sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
int idx, /* Index of loop to report on */
int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
@@ -7919,279 +7698,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
** This API is only available if the library is built with pre-processor
** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
-
-/*
-** CAPI3REF: Flush caches to disk mid-transaction
-**
-** ^If a write-transaction is open on [database connection] D when the
-** [sqlite3_db_cacheflush(D)] interface invoked, any dirty
-** pages in the pager-cache that are not currently in use are written out
-** to disk. A dirty page may be in use if a database cursor created by an
-** active SQL statement is reading from it, or if it is page 1 of a database
-** file (page 1 is always "in use"). ^The [sqlite3_db_cacheflush(D)]
-** interface flushes caches for all schemas - "main", "temp", and
-** any [attached] databases.
-**
-** ^If this function needs to obtain extra database locks before dirty pages
-** can be flushed to disk, it does so. ^If those locks cannot be obtained
-** immediately and there is a busy-handler callback configured, it is invoked
-** in the usual manner. ^If the required lock still cannot be obtained, then
-** the database is skipped and an attempt made to flush any dirty pages
-** belonging to the next (if any) database. ^If any databases are skipped
-** because locks cannot be obtained, but no other error occurs, this
-** function returns SQLITE_BUSY.
-**
-** ^If any other error occurs while flushing dirty pages to disk (for
-** example an IO error or out-of-memory condition), then processing is
-** abandoned and an SQLite [error code] is returned to the caller immediately.
-**
-** ^Otherwise, if no error occurs, [sqlite3_db_cacheflush()] returns SQLITE_OK.
-**
-** ^This function does not set the database handle error code or message
-** returned by the [sqlite3_errcode()] and [sqlite3_errmsg()] functions.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3_db_cacheflush(sqlite3*);
-
-/*
-** CAPI3REF: The pre-update hook.
-**
-** ^These interfaces are only available if SQLite is compiled using the
-** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option.
-**
-** ^The [sqlite3_preupdate_hook()] interface registers a callback function
-** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation
-** on a [rowid table].
-** ^At most one preupdate hook may be registered at a time on a single
-** [database connection]; each call to [sqlite3_preupdate_hook()] overrides
-** the previous setting.
-** ^The preupdate hook is disabled by invoking [sqlite3_preupdate_hook()]
-** with a NULL pointer as the second parameter.
-** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as
-** the first parameter to callbacks.
-**
-** ^The preupdate hook only fires for changes to [rowid tables]; the preupdate
-** hook is not invoked for changes to [virtual tables] or [WITHOUT ROWID]
-** tables.
-**
-** ^The second parameter to the preupdate callback is a pointer to
-** the [database connection] that registered the preupdate hook.
-** ^The third parameter to the preupdate callback is one of the constants
-** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to indentify the
-** kind of update operation that is about to occur.
-** ^(The fourth parameter to the preupdate callback is the name of the
-** database within the database connection that is being modified. This
-** will be "main" for the main database or "temp" for TEMP tables or
-** the name given after the AS keyword in the [ATTACH] statement for attached
-** databases.)^
-** ^The fifth parameter to the preupdate callback is the name of the
-** table that is being modified.
-** ^The sixth parameter to the preupdate callback is the initial [rowid] of the
-** row being changes for SQLITE_UPDATE and SQLITE_DELETE changes and is
-** undefined for SQLITE_INSERT changes.
-** ^The seventh parameter to the preupdate callback is the final [rowid] of
-** the row being changed for SQLITE_UPDATE and SQLITE_INSERT changes and is
-** undefined for SQLITE_DELETE changes.
-**
-** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
-** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
-** provide additional information about a preupdate event. These routines
-** may only be called from within a preupdate callback. Invoking any of
-** these routines from outside of a preupdate callback or with a
-** [database connection] pointer that is different from the one supplied
-** to the preupdate callback results in undefined and probably undesirable
-** behavior.
-**
-** ^The [sqlite3_preupdate_count(D)] interface returns the number of columns
-** in the row that is being inserted, updated, or deleted.
-**
-** ^The [sqlite3_preupdate_old(D,N,P)] interface writes into P a pointer to
-** a [protected sqlite3_value] that contains the value of the Nth column of
-** the table row before it is updated. The N parameter must be between 0
-** and one less than the number of columns or the behavior will be
-** undefined. This must only be used within SQLITE_UPDATE and SQLITE_DELETE
-** preupdate callbacks; if it is used by an SQLITE_INSERT callback then the
-** behavior is undefined. The [sqlite3_value] that P points to
-** will be destroyed when the preupdate callback returns.
-**
-** ^The [sqlite3_preupdate_new(D,N,P)] interface writes into P a pointer to
-** a [protected sqlite3_value] that contains the value of the Nth column of
-** the table row after it is updated. The N parameter must be between 0
-** and one less than the number of columns or the behavior will be
-** undefined. This must only be used within SQLITE_INSERT and SQLITE_UPDATE
-** preupdate callbacks; if it is used by an SQLITE_DELETE callback then the
-** behavior is undefined. The [sqlite3_value] that P points to
-** will be destroyed when the preupdate callback returns.
-**
-** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate
-** callback was invoked as a result of a direct insert, update, or delete
-** operation; or 1 for inserts, updates, or deletes invoked by top-level
-** triggers; or 2 for changes resulting from triggers called by top-level
-** triggers; and so forth.
-**
-** See also: [sqlite3_update_hook()]
-*/
-SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_preupdate_hook(
- sqlite3 *db,
- void(*xPreUpdate)(
- void *pCtx, /* Copy of third arg to preupdate_hook() */
- sqlite3 *db, /* Database handle */
- int op, /* SQLITE_UPDATE, DELETE or INSERT */
- char const *zDb, /* Database name */
- char const *zName, /* Table name */
- sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */
- sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */
- ),
- void*
-);
-SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
-SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_preupdate_count(sqlite3 *);
-SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_preupdate_depth(sqlite3 *);
-SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
-
-/*
-** CAPI3REF: Low-level system error code
-**
-** ^Attempt to return the underlying operating system error code or error
-** number that caused the most recent I/O error or failure to open a file.
-** The return value is OS-dependent. For example, on unix systems, after
-** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be
-** called to get back the underlying "errno" that caused the problem, such
-** as ENOSPC, EAUTH, EISDIR, and so forth.
-*/
-SQLITE_API int SQLITE_STDCALL sqlite3_system_errno(sqlite3*);
-
-/*
-** CAPI3REF: Database Snapshot
-** KEYWORDS: {snapshot}
-** EXPERIMENTAL
-**
-** An instance of the snapshot object records the state of a [WAL mode]
-** database for some specific point in history.
-**
-** In [WAL mode], multiple [database connections] that are open on the
-** same database file can each be reading a different historical version
-** of the database file. When a [database connection] begins a read
-** transaction, that connection sees an unchanging copy of the database
-** as it existed for the point in time when the transaction first started.
-** Subsequent changes to the database from other connections are not seen
-** by the reader until a new read transaction is started.
-**
-** The sqlite3_snapshot object records state information about an historical
-** version of the database file so that it is possible to later open a new read
-** transaction that sees that historical version of the database rather than
-** the most recent version.
-**
-** The constructor for this object is [sqlite3_snapshot_get()]. The
-** [sqlite3_snapshot_open()] method causes a fresh read transaction to refer
-** to an historical snapshot (if possible). The destructor for
-** sqlite3_snapshot objects is [sqlite3_snapshot_free()].
-*/
-typedef struct sqlite3_snapshot sqlite3_snapshot;
-
-/*
-** CAPI3REF: Record A Database Snapshot
-** EXPERIMENTAL
-**
-** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a
-** new [sqlite3_snapshot] object that records the current state of
-** schema S in database connection D. ^On success, the
-** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
-** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
-** ^If schema S of [database connection] D is not a [WAL mode] database
-** that is in a read transaction, then [sqlite3_snapshot_get(D,S,P)]
-** leaves the *P value unchanged and returns an appropriate [error code].
-**
-** The [sqlite3_snapshot] object returned from a successful call to
-** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()]
-** to avoid a memory leak.
-**
-** The [sqlite3_snapshot_get()] interface is only available when the
-** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
-*/
-SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_get(
- sqlite3 *db,
- const char *zSchema,
- sqlite3_snapshot **ppSnapshot
-);
-
-/*
-** CAPI3REF: Start a read transaction on an historical snapshot
-** EXPERIMENTAL
-**
-** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a
-** read transaction for schema S of
-** [database connection] D such that the read transaction
-** refers to historical [snapshot] P, rather than the most
-** recent change to the database.
-** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success
-** or an appropriate [error code] if it fails.
-**
-** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be
-** the first operation following the [BEGIN] that takes the schema S
-** out of [autocommit mode].
-** ^In other words, schema S must not currently be in
-** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the
-** database connection D must be out of [autocommit mode].
-** ^A [snapshot] will fail to open if it has been overwritten by a
-** [checkpoint].
-** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the
-** database connection D does not know that the database file for
-** schema S is in [WAL mode]. A database connection might not know
-** that the database file is in [WAL mode] if there has been no prior
-** I/O on that database connection, or if the database entered [WAL mode]
-** after the most recent I/O on the database connection.)^
-** (Hint: Run "[PRAGMA application_id]" against a newly opened
-** database connection in order to make it ready to use snapshots.)
-**
-** The [sqlite3_snapshot_open()] interface is only available when the
-** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
-*/
-SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_open(
- sqlite3 *db,
- const char *zSchema,
- sqlite3_snapshot *pSnapshot
-);
-
-/*
-** CAPI3REF: Destroy a snapshot
-** EXPERIMENTAL
-**
-** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P.
-** The application must eventually free every [sqlite3_snapshot] object
-** using this routine to avoid a memory leak.
-**
-** The [sqlite3_snapshot_free()] interface is only available when the
-** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
-*/
-SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_snapshot_free(sqlite3_snapshot*);
+SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
-/*
-** CAPI3REF: Compare the ages of two snapshot handles.
-** EXPERIMENTAL
-**
-** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages
-** of two valid snapshot handles.
-**
-** If the two snapshot handles are not associated with the same database
-** file, the result of the comparison is undefined.
-**
-** Additionally, the result of the comparison is only valid if both of the
-** snapshot handles were obtained by calling sqlite3_snapshot_get() since the
-** last time the wal file was deleted. The wal file is deleted when the
-** database is changed back to rollback mode or when the number of database
-** clients drops to zero. If either snapshot handle was obtained before the
-** wal file was last deleted, the value returned by this function
-** is undefined.
-**
-** Otherwise, this API returns a negative value if P1 refers to an older
-** snapshot than P2, zero if the two handles refer to the same database
-** snapshot, and a positive value if P1 is a newer snapshot than P2.
-*/
-SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_cmp(
- sqlite3_snapshot *p1,
- sqlite3_snapshot *p2
-);
/*
** Undo the hack that converts floating point types to integer for
@@ -8206,7 +7714,6 @@ SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_cmp(
#endif
#endif /* _SQLITE3_H_ */
-/******** Begin file sqlite3rtree.h *********/
/*
** 2010 August 30
**
@@ -8306,8 +7813,6 @@ struct sqlite3_rtree_query_info {
int eParentWithin; /* Visibility of parent node */
int eWithin; /* OUT: Visiblity */
sqlite3_rtree_dbl rScore; /* OUT: Write the score here */
- /* The following fields are only available in 3.8.11 and later */
- sqlite3_value **apSqlParam; /* Original SQL values of parameters */
};
/*
@@ -8324,1865 +7829,3 @@ struct sqlite3_rtree_query_info {
#endif /* ifndef _SQLITE3RTREE_H_ */
-/******** End of sqlite3rtree.h *********/
-/******** Begin file sqlite3session.h *********/
-
-#if !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION)
-#define __SQLITESESSION_H_ 1
-
-/*
-** Make sure we can call this stuff from C++.
-*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/*
-** CAPI3REF: Session Object Handle
-*/
-typedef struct sqlite3_session sqlite3_session;
-
-/*
-** CAPI3REF: Changeset Iterator Handle
-*/
-typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
-
-/*
-** CAPI3REF: Create A New Session Object
-**
-** Create a new session object attached to database handle db. If successful,
-** a pointer to the new object is written to *ppSession and SQLITE_OK is
-** returned. If an error occurs, *ppSession is set to NULL and an SQLite
-** error code (e.g. SQLITE_NOMEM) is returned.
-**
-** It is possible to create multiple session objects attached to a single
-** database handle.
-**
-** Session objects created using this function should be deleted using the
-** [sqlite3session_delete()] function before the database handle that they
-** are attached to is itself closed. If the database handle is closed before
-** the session object is deleted, then the results of calling any session
-** module function, including [sqlite3session_delete()] on the session object
-** are undefined.
-**
-** Because the session module uses the [sqlite3_preupdate_hook()] API, it
-** is not possible for an application to register a pre-update hook on a
-** database handle that has one or more session objects attached. Nor is
-** it possible to create a session object attached to a database handle for
-** which a pre-update hook is already defined. The results of attempting
-** either of these things are undefined.
-**
-** The session object will be used to create changesets for tables in
-** database zDb, where zDb is either "main", or "temp", or the name of an
-** attached database. It is not an error if database zDb is not attached
-** to the database when the session object is created.
-*/
-int sqlite3session_create(
- sqlite3 *db, /* Database handle */
- const char *zDb, /* Name of db (e.g. "main") */
- sqlite3_session **ppSession /* OUT: New session object */
-);
-
-/*
-** CAPI3REF: Delete A Session Object
-**
-** Delete a session object previously allocated using
-** [sqlite3session_create()]. Once a session object has been deleted, the
-** results of attempting to use pSession with any other session module
-** function are undefined.
-**
-** Session objects must be deleted before the database handle to which they
-** are attached is closed. Refer to the documentation for
-** [sqlite3session_create()] for details.
-*/
-void sqlite3session_delete(sqlite3_session *pSession);
-
-
-/*
-** CAPI3REF: Enable Or Disable A Session Object
-**
-** Enable or disable the recording of changes by a session object. When
-** enabled, a session object records changes made to the database. When
-** disabled - it does not. A newly created session object is enabled.
-** Refer to the documentation for [sqlite3session_changeset()] for further
-** details regarding how enabling and disabling a session object affects
-** the eventual changesets.
-**
-** Passing zero to this function disables the session. Passing a value
-** greater than zero enables it. Passing a value less than zero is a
-** no-op, and may be used to query the current state of the session.
-**
-** The return value indicates the final state of the session object: 0 if
-** the session is disabled, or 1 if it is enabled.
-*/
-int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
-
-/*
-** CAPI3REF: Set Or Clear the Indirect Change Flag
-**
-** Each change recorded by a session object is marked as either direct or
-** indirect. A change is marked as indirect if either:
-**
-** <ul>
-** <li> The session object "indirect" flag is set when the change is
-** made, or
-** <li> The change is made by an SQL trigger or foreign key action
-** instead of directly as a result of a users SQL statement.
-** </ul>
-**
-** If a single row is affected by more than one operation within a session,
-** then the change is considered indirect if all operations meet the criteria
-** for an indirect change above, or direct otherwise.
-**
-** This function is used to set, clear or query the session object indirect
-** flag. If the second argument passed to this function is zero, then the
-** indirect flag is cleared. If it is greater than zero, the indirect flag
-** is set. Passing a value less than zero does not modify the current value
-** of the indirect flag, and may be used to query the current state of the
-** indirect flag for the specified session object.
-**
-** The return value indicates the final state of the indirect flag: 0 if
-** it is clear, or 1 if it is set.
-*/
-int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect);
-
-/*
-** CAPI3REF: Attach A Table To A Session Object
-**
-** If argument zTab is not NULL, then it is the name of a table to attach
-** to the session object passed as the first argument. All subsequent changes
-** made to the table while the session object is enabled will be recorded. See
-** documentation for [sqlite3session_changeset()] for further details.
-**
-** Or, if argument zTab is NULL, then changes are recorded for all tables
-** in the database. If additional tables are added to the database (by
-** executing "CREATE TABLE" statements) after this call is made, changes for
-** the new tables are also recorded.
-**
-** Changes can only be recorded for tables that have a PRIMARY KEY explicitly
-** defined as part of their CREATE TABLE statement. It does not matter if the
-** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY
-** KEY may consist of a single column, or may be a composite key.
-**
-** It is not an error if the named table does not exist in the database. Nor
-** is it an error if the named table does not have a PRIMARY KEY. However,
-** no changes will be recorded in either of these scenarios.
-**
-** Changes are not recorded for individual rows that have NULL values stored
-** in one or more of their PRIMARY KEY columns.
-**
-** SQLITE_OK is returned if the call completes without error. Or, if an error
-** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
-*/
-int sqlite3session_attach(
- sqlite3_session *pSession, /* Session object */
- const char *zTab /* Table name */
-);
-
-/*
-** CAPI3REF: Set a table filter on a Session Object.
-**
-** The second argument (xFilter) is the "filter callback". For changes to rows
-** in tables that are not attached to the Session oject, the filter is called
-** to determine whether changes to the table's rows should be tracked or not.
-** If xFilter returns 0, changes is not tracked. Note that once a table is
-** attached, xFilter will not be called again.
-*/
-void sqlite3session_table_filter(
- sqlite3_session *pSession, /* Session object */
- int(*xFilter)(
- void *pCtx, /* Copy of third arg to _filter_table() */
- const char *zTab /* Table name */
- ),
- void *pCtx /* First argument passed to xFilter */
-);
-
-/*
-** CAPI3REF: Generate A Changeset From A Session Object
-**
-** Obtain a changeset containing changes to the tables attached to the
-** session object passed as the first argument. If successful,
-** set *ppChangeset to point to a buffer containing the changeset
-** and *pnChangeset to the size of the changeset in bytes before returning
-** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to
-** zero and return an SQLite error code.
-**
-** A changeset consists of zero or more INSERT, UPDATE and/or DELETE changes,
-** each representing a change to a single row of an attached table. An INSERT
-** change contains the values of each field of a new database row. A DELETE
-** contains the original values of each field of a deleted database row. An
-** UPDATE change contains the original values of each field of an updated
-** database row along with the updated values for each updated non-primary-key
-** column. It is not possible for an UPDATE change to represent a change that
-** modifies the values of primary key columns. If such a change is made, it
-** is represented in a changeset as a DELETE followed by an INSERT.
-**
-** Changes are not recorded for rows that have NULL values stored in one or
-** more of their PRIMARY KEY columns. If such a row is inserted or deleted,
-** no corresponding change is present in the changesets returned by this
-** function. If an existing row with one or more NULL values stored in
-** PRIMARY KEY columns is updated so that all PRIMARY KEY columns are non-NULL,
-** only an INSERT is appears in the changeset. Similarly, if an existing row
-** with non-NULL PRIMARY KEY values is updated so that one or more of its
-** PRIMARY KEY columns are set to NULL, the resulting changeset contains a
-** DELETE change only.
-**
-** The contents of a changeset may be traversed using an iterator created
-** using the [sqlite3changeset_start()] API. A changeset may be applied to
-** a database with a compatible schema using the [sqlite3changeset_apply()]
-** API.
-**
-** Within a changeset generated by this function, all changes related to a
-** single table are grouped together. In other words, when iterating through
-** a changeset or when applying a changeset to a database, all changes related
-** to a single table are processed before moving on to the next table. Tables
-** are sorted in the same order in which they were attached (or auto-attached)
-** to the sqlite3_session object. The order in which the changes related to
-** a single table are stored is undefined.
-**
-** Following a successful call to this function, it is the responsibility of
-** the caller to eventually free the buffer that *ppChangeset points to using
-** [sqlite3_free()].
-**
-** <h3>Changeset Generation</h3>
-**
-** Once a table has been attached to a session object, the session object
-** records the primary key values of all new rows inserted into the table.
-** It also records the original primary key and other column values of any
-** deleted or updated rows. For each unique primary key value, data is only
-** recorded once - the first time a row with said primary key is inserted,
-** updated or deleted in the lifetime of the session.
-**
-** There is one exception to the previous paragraph: when a row is inserted,
-** updated or deleted, if one or more of its primary key columns contain a
-** NULL value, no record of the change is made.
-**
-** The session object therefore accumulates two types of records - those
-** that consist of primary key values only (created when the user inserts
-** a new record) and those that consist of the primary key values and the
-** original values of other table columns (created when the users deletes
-** or updates a record).
-**
-** When this function is called, the requested changeset is created using
-** both the accumulated records and the current contents of the database
-** file. Specifically:
-**
-** <ul>
-** <li> For each record generated by an insert, the database is queried
-** for a row with a matching primary key. If one is found, an INSERT
-** change is added to the changeset. If no such row is found, no change
-** is added to the changeset.
-**
-** <li> For each record generated by an update or delete, the database is
-** queried for a row with a matching primary key. If such a row is
-** found and one or more of the non-primary key fields have been
-** modified from their original values, an UPDATE change is added to
-** the changeset. Or, if no such row is found in the table, a DELETE
-** change is added to the changeset. If there is a row with a matching
-** primary key in the database, but all fields contain their original
-** values, no change is added to the changeset.
-** </ul>
-**
-** This means, amongst other things, that if a row is inserted and then later
-** deleted while a session object is active, neither the insert nor the delete
-** will be present in the changeset. Or if a row is deleted and then later a
-** row with the same primary key values inserted while a session object is
-** active, the resulting changeset will contain an UPDATE change instead of
-** a DELETE and an INSERT.
-**
-** When a session object is disabled (see the [sqlite3session_enable()] API),
-** it does not accumulate records when rows are inserted, updated or deleted.
-** This may appear to have some counter-intuitive effects if a single row
-** is written to more than once during a session. For example, if a row
-** is inserted while a session object is enabled, then later deleted while
-** the same session object is disabled, no INSERT record will appear in the
-** changeset, even though the delete took place while the session was disabled.
-** Or, if one field of a row is updated while a session is disabled, and
-** another field of the same row is updated while the session is enabled, the
-** resulting changeset will contain an UPDATE change that updates both fields.
-*/
-int sqlite3session_changeset(
- sqlite3_session *pSession, /* Session object */
- int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */
- void **ppChangeset /* OUT: Buffer containing changeset */
-);
-
-/*
-** CAPI3REF: Load The Difference Between Tables Into A Session
-**
-** If it is not already attached to the session object passed as the first
-** argument, this function attaches table zTbl in the same manner as the
-** [sqlite3session_attach()] function. If zTbl does not exist, or if it
-** does not have a primary key, this function is a no-op (but does not return
-** an error).
-**
-** Argument zFromDb must be the name of a database ("main", "temp" etc.)
-** attached to the same database handle as the session object that contains
-** a table compatible with the table attached to the session by this function.
-** A table is considered compatible if it:
-**
-** <ul>
-** <li> Has the same name,
-** <li> Has the same set of columns declared in the same order, and
-** <li> Has the same PRIMARY KEY definition.
-** </ul>
-**
-** If the tables are not compatible, SQLITE_SCHEMA is returned. If the tables
-** are compatible but do not have any PRIMARY KEY columns, it is not an error
-** but no changes are added to the session object. As with other session
-** APIs, tables without PRIMARY KEYs are simply ignored.
-**
-** This function adds a set of changes to the session object that could be
-** used to update the table in database zFrom (call this the "from-table")
-** so that its content is the same as the table attached to the session
-** object (call this the "to-table"). Specifically:
-**
-** <ul>
-** <li> For each row (primary key) that exists in the to-table but not in
-** the from-table, an INSERT record is added to the session object.
-**
-** <li> For each row (primary key) that exists in the to-table but not in
-** the from-table, a DELETE record is added to the session object.
-**
-** <li> For each row (primary key) that exists in both tables, but features
-** different in each, an UPDATE record is added to the session.
-** </ul>
-**
-** To clarify, if this function is called and then a changeset constructed
-** using [sqlite3session_changeset()], then after applying that changeset to
-** database zFrom the contents of the two compatible tables would be
-** identical.
-**
-** It an error if database zFrom does not exist or does not contain the
-** required compatible table.
-**
-** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite
-** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
-** may be set to point to a buffer containing an English language error
-** message. It is the responsibility of the caller to free this buffer using
-** sqlite3_free().
-*/
-int sqlite3session_diff(
- sqlite3_session *pSession,
- const char *zFromDb,
- const char *zTbl,
- char **pzErrMsg
-);
-
-
-/*
-** CAPI3REF: Generate A Patchset From A Session Object
-**
-** The differences between a patchset and a changeset are that:
-**
-** <ul>
-** <li> DELETE records consist of the primary key fields only. The
-** original values of other fields are omitted.
-** <li> The original values of any modified fields are omitted from
-** UPDATE records.
-** </ul>
-**
-** A patchset blob may be used with up to date versions of all
-** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(),
-** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly,
-** attempting to use a patchset blob with old versions of the
-** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error.
-**
-** Because the non-primary key "old.*" fields are omitted, no
-** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset
-** is passed to the sqlite3changeset_apply() API. Other conflict types work
-** in the same way as for changesets.
-**
-** Changes within a patchset are ordered in the same way as for changesets
-** generated by the sqlite3session_changeset() function (i.e. all changes for
-** a single table are grouped together, tables appear in the order in which
-** they were attached to the session object).
-*/
-int sqlite3session_patchset(
- sqlite3_session *pSession, /* Session object */
- int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */
- void **ppPatchset /* OUT: Buffer containing changeset */
-);
-
-/*
-** CAPI3REF: Test if a changeset has recorded any changes.
-**
-** Return non-zero if no changes to attached tables have been recorded by
-** the session object passed as the first argument. Otherwise, if one or
-** more changes have been recorded, return zero.
-**
-** Even if this function returns zero, it is possible that calling
-** [sqlite3session_changeset()] on the session handle may still return a
-** changeset that contains no changes. This can happen when a row in
-** an attached table is modified and then later on the original values
-** are restored. However, if this function returns non-zero, then it is
-** guaranteed that a call to sqlite3session_changeset() will return a
-** changeset containing zero changes.
-*/
-int sqlite3session_isempty(sqlite3_session *pSession);
-
-/*
-** CAPI3REF: Create An Iterator To Traverse A Changeset
-**
-** Create an iterator used to iterate through the contents of a changeset.
-** If successful, *pp is set to point to the iterator handle and SQLITE_OK
-** is returned. Otherwise, if an error occurs, *pp is set to zero and an
-** SQLite error code is returned.
-**
-** The following functions can be used to advance and query a changeset
-** iterator created by this function:
-**
-** <ul>
-** <li> [sqlite3changeset_next()]
-** <li> [sqlite3changeset_op()]
-** <li> [sqlite3changeset_new()]
-** <li> [sqlite3changeset_old()]
-** </ul>
-**
-** It is the responsibility of the caller to eventually destroy the iterator
-** by passing it to [sqlite3changeset_finalize()]. The buffer containing the
-** changeset (pChangeset) must remain valid until after the iterator is
-** destroyed.
-**
-** Assuming the changeset blob was created by one of the
-** [sqlite3session_changeset()], [sqlite3changeset_concat()] or
-** [sqlite3changeset_invert()] functions, all changes within the changeset
-** that apply to a single table are grouped together. This means that when
-** an application iterates through a changeset using an iterator created by
-** this function, all changes that relate to a single table are visted
-** consecutively. There is no chance that the iterator will visit a change
-** the applies to table X, then one for table Y, and then later on visit
-** another change for table X.
-*/
-int sqlite3changeset_start(
- sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */
- int nChangeset, /* Size of changeset blob in bytes */
- void *pChangeset /* Pointer to blob containing changeset */
-);
-
-
-/*
-** CAPI3REF: Advance A Changeset Iterator
-**
-** This function may only be used with iterators created by function
-** [sqlite3changeset_start()]. If it is called on an iterator passed to
-** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE
-** is returned and the call has no effect.
-**
-** Immediately after an iterator is created by sqlite3changeset_start(), it
-** does not point to any change in the changeset. Assuming the changeset
-** is not empty, the first call to this function advances the iterator to
-** point to the first change in the changeset. Each subsequent call advances
-** the iterator to point to the next change in the changeset (if any). If
-** no error occurs and the iterator points to a valid change after a call
-** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned.
-** Otherwise, if all changes in the changeset have already been visited,
-** SQLITE_DONE is returned.
-**
-** If an error occurs, an SQLite error code is returned. Possible error
-** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or
-** SQLITE_NOMEM.
-*/
-int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
-
-/*
-** CAPI3REF: Obtain The Current Operation From A Changeset Iterator
-**
-** The pIter argument passed to this function may either be an iterator
-** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
-** created by [sqlite3changeset_start()]. In the latter case, the most recent
-** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this
-** is not the case, this function returns [SQLITE_MISUSE].
-**
-** If argument pzTab is not NULL, then *pzTab is set to point to a
-** nul-terminated utf-8 encoded string containing the name of the table
-** affected by the current change. The buffer remains valid until either
-** sqlite3changeset_next() is called on the iterator or until the
-** conflict-handler function returns. If pnCol is not NULL, then *pnCol is
-** set to the number of columns in the table affected by the change. If
-** pbIncorrect is not NULL, then *pbIndirect is set to true (1) if the change
-** is an indirect change, or false (0) otherwise. See the documentation for
-** [sqlite3session_indirect()] for a description of direct and indirect
-** changes. Finally, if pOp is not NULL, then *pOp is set to one of
-** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the
-** type of change that the iterator currently points to.
-**
-** If no error occurs, SQLITE_OK is returned. If an error does occur, an
-** SQLite error code is returned. The values of the output variables may not
-** be trusted in this case.
-*/
-int sqlite3changeset_op(
- sqlite3_changeset_iter *pIter, /* Iterator object */
- const char **pzTab, /* OUT: Pointer to table name */
- int *pnCol, /* OUT: Number of columns in table */
- int *pOp, /* OUT: SQLITE_INSERT, DELETE or UPDATE */
- int *pbIndirect /* OUT: True for an 'indirect' change */
-);
-
-/*
-** CAPI3REF: Obtain The Primary Key Definition Of A Table
-**
-** For each modified table, a changeset includes the following:
-**
-** <ul>
-** <li> The number of columns in the table, and
-** <li> Which of those columns make up the tables PRIMARY KEY.
-** </ul>
-**
-** This function is used to find which columns comprise the PRIMARY KEY of
-** the table modified by the change that iterator pIter currently points to.
-** If successful, *pabPK is set to point to an array of nCol entries, where
-** nCol is the number of columns in the table. Elements of *pabPK are set to
-** 0x01 if the corresponding column is part of the tables primary key, or
-** 0x00 if it is not.
-**
-** If argumet pnCol is not NULL, then *pnCol is set to the number of columns
-** in the table.
-**
-** If this function is called when the iterator does not point to a valid
-** entry, SQLITE_MISUSE is returned and the output variables zeroed. Otherwise,
-** SQLITE_OK is returned and the output variables populated as described
-** above.
-*/
-int sqlite3changeset_pk(
- sqlite3_changeset_iter *pIter, /* Iterator object */
- unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */
- int *pnCol /* OUT: Number of entries in output array */
-);
-
-/*
-** CAPI3REF: Obtain old.* Values From A Changeset Iterator
-**
-** The pIter argument passed to this function may either be an iterator
-** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
-** created by [sqlite3changeset_start()]. In the latter case, the most recent
-** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
-** Furthermore, it may only be called if the type of change that the iterator
-** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise,
-** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
-**
-** Argument iVal must be greater than or equal to 0, and less than the number
-** of columns in the table affected by the current change. Otherwise,
-** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
-**
-** If successful, this function sets *ppValue to point to a protected
-** sqlite3_value object containing the iVal'th value from the vector of
-** original row values stored as part of the UPDATE or DELETE change and
-** returns SQLITE_OK. The name of the function comes from the fact that this
-** is similar to the "old.*" columns available to update or delete triggers.
-**
-** If some other error occurs (e.g. an OOM condition), an SQLite error code
-** is returned and *ppValue is set to NULL.
-*/
-int sqlite3changeset_old(
- sqlite3_changeset_iter *pIter, /* Changeset iterator */
- int iVal, /* Column number */
- sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */
-);
-
-/*
-** CAPI3REF: Obtain new.* Values From A Changeset Iterator
-**
-** The pIter argument passed to this function may either be an iterator
-** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
-** created by [sqlite3changeset_start()]. In the latter case, the most recent
-** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
-** Furthermore, it may only be called if the type of change that the iterator
-** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise,
-** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
-**
-** Argument iVal must be greater than or equal to 0, and less than the number
-** of columns in the table affected by the current change. Otherwise,
-** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
-**
-** If successful, this function sets *ppValue to point to a protected
-** sqlite3_value object containing the iVal'th value from the vector of
-** new row values stored as part of the UPDATE or INSERT change and
-** returns SQLITE_OK. If the change is an UPDATE and does not include
-** a new value for the requested column, *ppValue is set to NULL and
-** SQLITE_OK returned. The name of the function comes from the fact that
-** this is similar to the "new.*" columns available to update or delete
-** triggers.
-**
-** If some other error occurs (e.g. an OOM condition), an SQLite error code
-** is returned and *ppValue is set to NULL.
-*/
-int sqlite3changeset_new(
- sqlite3_changeset_iter *pIter, /* Changeset iterator */
- int iVal, /* Column number */
- sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */
-);
-
-/*
-** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator
-**
-** This function should only be used with iterator objects passed to a
-** conflict-handler callback by [sqlite3changeset_apply()] with either
-** [SQLITE_CHANGESET_DATA] or [SQLITE_CHANGESET_CONFLICT]. If this function
-** is called on any other iterator, [SQLITE_MISUSE] is returned and *ppValue
-** is set to NULL.
-**
-** Argument iVal must be greater than or equal to 0, and less than the number
-** of columns in the table affected by the current change. Otherwise,
-** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
-**
-** If successful, this function sets *ppValue to point to a protected
-** sqlite3_value object containing the iVal'th value from the
-** "conflicting row" associated with the current conflict-handler callback
-** and returns SQLITE_OK.
-**
-** If some other error occurs (e.g. an OOM condition), an SQLite error code
-** is returned and *ppValue is set to NULL.
-*/
-int sqlite3changeset_conflict(
- sqlite3_changeset_iter *pIter, /* Changeset iterator */
- int iVal, /* Column number */
- sqlite3_value **ppValue /* OUT: Value from conflicting row */
-);
-
-/*
-** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations
-**
-** This function may only be called with an iterator passed to an
-** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case
-** it sets the output variable to the total number of known foreign key
-** violations in the destination database and returns SQLITE_OK.
-**
-** In all other cases this function returns SQLITE_MISUSE.
-*/
-int sqlite3changeset_fk_conflicts(
- sqlite3_changeset_iter *pIter, /* Changeset iterator */
- int *pnOut /* OUT: Number of FK violations */
-);
-
-
-/*
-** CAPI3REF: Finalize A Changeset Iterator
-**
-** This function is used to finalize an iterator allocated with
-** [sqlite3changeset_start()].
-**
-** This function should only be called on iterators created using the
-** [sqlite3changeset_start()] function. If an application calls this
-** function with an iterator passed to a conflict-handler by
-** [sqlite3changeset_apply()], [SQLITE_MISUSE] is immediately returned and the
-** call has no effect.
-**
-** If an error was encountered within a call to an sqlite3changeset_xxx()
-** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an
-** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding
-** to that error is returned by this function. Otherwise, SQLITE_OK is
-** returned. This is to allow the following pattern (pseudo-code):
-**
-** sqlite3changeset_start();
-** while( SQLITE_ROW==sqlite3changeset_next() ){
-** // Do something with change.
-** }
-** rc = sqlite3changeset_finalize();
-** if( rc!=SQLITE_OK ){
-** // An error has occurred
-** }
-*/
-int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
-
-/*
-** CAPI3REF: Invert A Changeset
-**
-** This function is used to "invert" a changeset object. Applying an inverted
-** changeset to a database reverses the effects of applying the uninverted
-** changeset. Specifically:
-**
-** <ul>
-** <li> Each DELETE change is changed to an INSERT, and
-** <li> Each INSERT change is changed to a DELETE, and
-** <li> For each UPDATE change, the old.* and new.* values are exchanged.
-** </ul>
-**
-** This function does not change the order in which changes appear within
-** the changeset. It merely reverses the sense of each individual change.
-**
-** If successful, a pointer to a buffer containing the inverted changeset
-** is stored in *ppOut, the size of the same buffer is stored in *pnOut, and
-** SQLITE_OK is returned. If an error occurs, both *pnOut and *ppOut are
-** zeroed and an SQLite error code returned.
-**
-** It is the responsibility of the caller to eventually call sqlite3_free()
-** on the *ppOut pointer to free the buffer allocation following a successful
-** call to this function.
-**
-** WARNING/TODO: This function currently assumes that the input is a valid
-** changeset. If it is not, the results are undefined.
-*/
-int sqlite3changeset_invert(
- int nIn, const void *pIn, /* Input changeset */
- int *pnOut, void **ppOut /* OUT: Inverse of input */
-);
-
-/*
-** CAPI3REF: Concatenate Two Changeset Objects
-**
-** This function is used to concatenate two changesets, A and B, into a
-** single changeset. The result is a changeset equivalent to applying
-** changeset A followed by changeset B.
-**
-** This function combines the two input changesets using an
-** sqlite3_changegroup object. Calling it produces similar results as the
-** following code fragment:
-**
-** sqlite3_changegroup *pGrp;
-** rc = sqlite3_changegroup_new(&pGrp);
-** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA);
-** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nB, pB);
-** if( rc==SQLITE_OK ){
-** rc = sqlite3changegroup_output(pGrp, pnOut, ppOut);
-** }else{
-** *ppOut = 0;
-** *pnOut = 0;
-** }
-**
-** Refer to the sqlite3_changegroup documentation below for details.
-*/
-int sqlite3changeset_concat(
- int nA, /* Number of bytes in buffer pA */
- void *pA, /* Pointer to buffer containing changeset A */
- int nB, /* Number of bytes in buffer pB */
- void *pB, /* Pointer to buffer containing changeset B */
- int *pnOut, /* OUT: Number of bytes in output changeset */
- void **ppOut /* OUT: Buffer containing output changeset */
-);
-
-
-/*
-** Changegroup handle.
-*/
-typedef struct sqlite3_changegroup sqlite3_changegroup;
-
-/*
-** CAPI3REF: Combine two or more changesets into a single changeset.
-**
-** An sqlite3_changegroup object is used to combine two or more changesets
-** (or patchsets) into a single changeset (or patchset). A single changegroup
-** object may combine changesets or patchsets, but not both. The output is
-** always in the same format as the input.
-**
-** If successful, this function returns SQLITE_OK and populates (*pp) with
-** a pointer to a new sqlite3_changegroup object before returning. The caller
-** should eventually free the returned object using a call to
-** sqlite3changegroup_delete(). If an error occurs, an SQLite error code
-** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL.
-**
-** The usual usage pattern for an sqlite3_changegroup object is as follows:
-**
-** <ul>
-** <li> It is created using a call to sqlite3changegroup_new().
-**
-** <li> Zero or more changesets (or patchsets) are added to the object
-** by calling sqlite3changegroup_add().
-**
-** <li> The result of combining all input changesets together is obtained
-** by the application via a call to sqlite3changegroup_output().
-**
-** <li> The object is deleted using a call to sqlite3changegroup_delete().
-** </ul>
-**
-** Any number of calls to add() and output() may be made between the calls to
-** new() and delete(), and in any order.
-**
-** As well as the regular sqlite3changegroup_add() and
-** sqlite3changegroup_output() functions, also available are the streaming
-** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm().
-*/
-int sqlite3changegroup_new(sqlite3_changegroup **pp);
-
-/*
-** Add all changes within the changeset (or patchset) in buffer pData (size
-** nData bytes) to the changegroup.
-**
-** If the buffer contains a patchset, then all prior calls to this function
-** on the same changegroup object must also have specified patchsets. Or, if
-** the buffer contains a changeset, so must have the earlier calls to this
-** function. Otherwise, SQLITE_ERROR is returned and no changes are added
-** to the changegroup.
-**
-** Rows within the changeset and changegroup are identified by the values in
-** their PRIMARY KEY columns. A change in the changeset is considered to
-** apply to the same row as a change already present in the changegroup if
-** the two rows have the same primary key.
-**
-** Changes to rows that that do not already appear in the changegroup are
-** simply copied into it. Or, if both the new changeset and the changegroup
-** contain changes that apply to a single row, the final contents of the
-** changegroup depends on the type of each change, as follows:
-**
-** <table border=1 style="margin-left:8ex;margin-right:8ex">
-** <tr><th style="white-space:pre">Existing Change </th>
-** <th style="white-space:pre">New Change </th>
-** <th>Output Change
-** <tr><td>INSERT <td>INSERT <td>
-** The new change is ignored. This case does not occur if the new
-** changeset was recorded immediately after the changesets already
-** added to the changegroup.
-** <tr><td>INSERT <td>UPDATE <td>
-** The INSERT change remains in the changegroup. The values in the
-** INSERT change are modified as if the row was inserted by the
-** existing change and then updated according to the new change.
-** <tr><td>INSERT <td>DELETE <td>
-** The existing INSERT is removed from the changegroup. The DELETE is
-** not added.
-** <tr><td>UPDATE <td>INSERT <td>
-** The new change is ignored. This case does not occur if the new
-** changeset was recorded immediately after the changesets already
-** added to the changegroup.
-** <tr><td>UPDATE <td>UPDATE <td>
-** The existing UPDATE remains within the changegroup. It is amended
-** so that the accompanying values are as if the row was updated once
-** by the existing change and then again by the new change.
-** <tr><td>UPDATE <td>DELETE <td>
-** The existing UPDATE is replaced by the new DELETE within the
-** changegroup.
-** <tr><td>DELETE <td>INSERT <td>
-** If one or more of the column values in the row inserted by the
-** new change differ from those in the row deleted by the existing
-** change, the existing DELETE is replaced by an UPDATE within the
-** changegroup. Otherwise, if the inserted row is exactly the same
-** as the deleted row, the existing DELETE is simply discarded.
-** <tr><td>DELETE <td>UPDATE <td>
-** The new change is ignored. This case does not occur if the new
-** changeset was recorded immediately after the changesets already
-** added to the changegroup.
-** <tr><td>DELETE <td>DELETE <td>
-** The new change is ignored. This case does not occur if the new
-** changeset was recorded immediately after the changesets already
-** added to the changegroup.
-** </table>
-**
-** If the new changeset contains changes to a table that is already present
-** in the changegroup, then the number of columns and the position of the
-** primary key columns for the table must be consistent. If this is not the
-** case, this function fails with SQLITE_SCHEMA. If the input changeset
-** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
-** returned. Or, if an out-of-memory condition occurs during processing, this
-** function returns SQLITE_NOMEM. In all cases, if an error occurs the
-** final contents of the changegroup is undefined.
-**
-** If no error occurs, SQLITE_OK is returned.
-*/
-int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
-
-/*
-** Obtain a buffer containing a changeset (or patchset) representing the
-** current contents of the changegroup. If the inputs to the changegroup
-** were themselves changesets, the output is a changeset. Or, if the
-** inputs were patchsets, the output is also a patchset.
-**
-** As with the output of the sqlite3session_changeset() and
-** sqlite3session_patchset() functions, all changes related to a single
-** table are grouped together in the output of this function. Tables appear
-** in the same order as for the very first changeset added to the changegroup.
-** If the second or subsequent changesets added to the changegroup contain
-** changes for tables that do not appear in the first changeset, they are
-** appended onto the end of the output changeset, again in the order in
-** which they are first encountered.
-**
-** If an error occurs, an SQLite error code is returned and the output
-** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK
-** is returned and the output variables are set to the size of and a
-** pointer to the output buffer, respectively. In this case it is the
-** responsibility of the caller to eventually free the buffer using a
-** call to sqlite3_free().
-*/
-int sqlite3changegroup_output(
- sqlite3_changegroup*,
- int *pnData, /* OUT: Size of output buffer in bytes */
- void **ppData /* OUT: Pointer to output buffer */
-);
-
-/*
-** Delete a changegroup object.
-*/
-void sqlite3changegroup_delete(sqlite3_changegroup*);
-
-/*
-** CAPI3REF: Apply A Changeset To A Database
-**
-** Apply a changeset to a database. This function attempts to update the
-** "main" database attached to handle db with the changes found in the
-** changeset passed via the second and third arguments.
-**
-** The fourth argument (xFilter) passed to this function is the "filter
-** callback". If it is not NULL, then for each table affected by at least one
-** change in the changeset, the filter callback is invoked with
-** the table name as the second argument, and a copy of the context pointer
-** passed as the sixth argument to this function as the first. If the "filter
-** callback" returns zero, then no attempt is made to apply any changes to
-** the table. Otherwise, if the return value is non-zero or the xFilter
-** argument to this function is NULL, all changes related to the table are
-** attempted.
-**
-** For each table that is not excluded by the filter callback, this function
-** tests that the target database contains a compatible table. A table is
-** considered compatible if all of the following are true:
-**
-** <ul>
-** <li> The table has the same name as the name recorded in the
-** changeset, and
-** <li> The table has the same number of columns as recorded in the
-** changeset, and
-** <li> The table has primary key columns in the same position as
-** recorded in the changeset.
-** </ul>
-**
-** If there is no compatible table, it is not an error, but none of the
-** changes associated with the table are applied. A warning message is issued
-** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most
-** one such warning is issued for each table in the changeset.
-**
-** For each change for which there is a compatible table, an attempt is made
-** to modify the table contents according to the UPDATE, INSERT or DELETE
-** change. If a change cannot be applied cleanly, the conflict handler
-** function passed as the fifth argument to sqlite3changeset_apply() may be
-** invoked. A description of exactly when the conflict handler is invoked for
-** each type of change is below.
-**
-** Unlike the xFilter argument, xConflict may not be passed NULL. The results
-** of passing anything other than a valid function pointer as the xConflict
-** argument are undefined.
-**
-** Each time the conflict handler function is invoked, it must return one
-** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or
-** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned
-** if the second argument passed to the conflict handler is either
-** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler
-** returns an illegal value, any changes already made are rolled back and
-** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different
-** actions are taken by sqlite3changeset_apply() depending on the value
-** returned by each invocation of the conflict-handler function. Refer to
-** the documentation for the three
-** [SQLITE_CHANGESET_OMIT|available return values] for details.
-**
-** <dl>
-** <dt>DELETE Changes<dd>
-** For each DELETE change, this function checks if the target database
-** contains a row with the same primary key value (or values) as the
-** original row values stored in the changeset. If it does, and the values
-** stored in all non-primary key columns also match the values stored in
-** the changeset the row is deleted from the target database.
-**
-** If a row with matching primary key values is found, but one or more of
-** the non-primary key fields contains a value different from the original
-** row value stored in the changeset, the conflict-handler function is
-** invoked with [SQLITE_CHANGESET_DATA] as the second argument.
-**
-** If no row with matching primary key values is found in the database,
-** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
-** passed as the second argument.
-**
-** If the DELETE operation is attempted, but SQLite returns SQLITE_CONSTRAINT
-** (which can only happen if a foreign key constraint is violated), the
-** conflict-handler function is invoked with [SQLITE_CHANGESET_CONSTRAINT]
-** passed as the second argument. This includes the case where the DELETE
-** operation is attempted because an earlier call to the conflict handler
-** function returned [SQLITE_CHANGESET_REPLACE].
-**
-** <dt>INSERT Changes<dd>
-** For each INSERT change, an attempt is made to insert the new row into
-** the database.
-**
-** If the attempt to insert the row fails because the database already
-** contains a row with the same primary key values, the conflict handler
-** function is invoked with the second argument set to
-** [SQLITE_CHANGESET_CONFLICT].
-**
-** If the attempt to insert the row fails because of some other constraint
-** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is
-** invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT].
-** This includes the case where the INSERT operation is re-attempted because
-** an earlier call to the conflict handler function returned
-** [SQLITE_CHANGESET_REPLACE].
-**
-** <dt>UPDATE Changes<dd>
-** For each UPDATE change, this function checks if the target database
-** contains a row with the same primary key value (or values) as the
-** original row values stored in the changeset. If it does, and the values
-** stored in all non-primary key columns also match the values stored in
-** the changeset the row is updated within the target database.
-**
-** If a row with matching primary key values is found, but one or more of
-** the non-primary key fields contains a value different from an original
-** row value stored in the changeset, the conflict-handler function is
-** invoked with [SQLITE_CHANGESET_DATA] as the second argument. Since
-** UPDATE changes only contain values for non-primary key fields that are
-** to be modified, only those fields need to match the original values to
-** avoid the SQLITE_CHANGESET_DATA conflict-handler callback.
-**
-** If no row with matching primary key values is found in the database,
-** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
-** passed as the second argument.
-**
-** If the UPDATE operation is attempted, but SQLite returns
-** SQLITE_CONSTRAINT, the conflict-handler function is invoked with
-** [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument.
-** This includes the case where the UPDATE operation is attempted after
-** an earlier call to the conflict handler function returned
-** [SQLITE_CHANGESET_REPLACE].
-** </dl>
-**
-** It is safe to execute SQL statements, including those that write to the
-** table that the callback related to, from within the xConflict callback.
-** This can be used to further customize the applications conflict
-** resolution strategy.
-**
-** All changes made by this function are enclosed in a savepoint transaction.
-** If any other error (aside from a constraint failure when attempting to
-** write to the target database) occurs, then the savepoint transaction is
-** rolled back, restoring the target database to its original state, and an
-** SQLite error code returned.
-*/
-int sqlite3changeset_apply(
- sqlite3 *db, /* Apply change to "main" db of this handle */
- int nChangeset, /* Size of changeset in bytes */
- void *pChangeset, /* Changeset blob */
- int(*xFilter)(
- void *pCtx, /* Copy of sixth arg to _apply() */
- const char *zTab /* Table name */
- ),
- int(*xConflict)(
- void *pCtx, /* Copy of sixth arg to _apply() */
- int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
- sqlite3_changeset_iter *p /* Handle describing change and conflict */
- ),
- void *pCtx /* First argument passed to xConflict */
-);
-
-/*
-** CAPI3REF: Constants Passed To The Conflict Handler
-**
-** Values that may be passed as the second argument to a conflict-handler.
-**
-** <dl>
-** <dt>SQLITE_CHANGESET_DATA<dd>
-** The conflict handler is invoked with CHANGESET_DATA as the second argument
-** when processing a DELETE or UPDATE change if a row with the required
-** PRIMARY KEY fields is present in the database, but one or more other
-** (non primary-key) fields modified by the update do not contain the
-** expected "before" values.
-**
-** The conflicting row, in this case, is the database row with the matching
-** primary key.
-**
-** <dt>SQLITE_CHANGESET_NOTFOUND<dd>
-** The conflict handler is invoked with CHANGESET_NOTFOUND as the second
-** argument when processing a DELETE or UPDATE change if a row with the
-** required PRIMARY KEY fields is not present in the database.
-**
-** There is no conflicting row in this case. The results of invoking the
-** sqlite3changeset_conflict() API are undefined.
-**
-** <dt>SQLITE_CHANGESET_CONFLICT<dd>
-** CHANGESET_CONFLICT is passed as the second argument to the conflict
-** handler while processing an INSERT change if the operation would result
-** in duplicate primary key values.
-**
-** The conflicting row in this case is the database row with the matching
-** primary key.
-**
-** <dt>SQLITE_CHANGESET_FOREIGN_KEY<dd>
-** If foreign key handling is enabled, and applying a changeset leaves the
-** database in a state containing foreign key violations, the conflict
-** handler is invoked with CHANGESET_FOREIGN_KEY as the second argument
-** exactly once before the changeset is committed. If the conflict handler
-** returns CHANGESET_OMIT, the changes, including those that caused the
-** foreign key constraint violation, are committed. Or, if it returns
-** CHANGESET_ABORT, the changeset is rolled back.
-**
-** No current or conflicting row information is provided. The only function
-** it is possible to call on the supplied sqlite3_changeset_iter handle
-** is sqlite3changeset_fk_conflicts().
-**
-** <dt>SQLITE_CHANGESET_CONSTRAINT<dd>
-** If any other constraint violation occurs while applying a change (i.e.
-** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is
-** invoked with CHANGESET_CONSTRAINT as the second argument.
-**
-** There is no conflicting row in this case. The results of invoking the
-** sqlite3changeset_conflict() API are undefined.
-**
-** </dl>
-*/
-#define SQLITE_CHANGESET_DATA 1
-#define SQLITE_CHANGESET_NOTFOUND 2
-#define SQLITE_CHANGESET_CONFLICT 3
-#define SQLITE_CHANGESET_CONSTRAINT 4
-#define SQLITE_CHANGESET_FOREIGN_KEY 5
-
-/*
-** CAPI3REF: Constants Returned By The Conflict Handler
-**
-** A conflict handler callback must return one of the following three values.
-**
-** <dl>
-** <dt>SQLITE_CHANGESET_OMIT<dd>
-** If a conflict handler returns this value no special action is taken. The
-** change that caused the conflict is not applied. The session module
-** continues to the next change in the changeset.
-**
-** <dt>SQLITE_CHANGESET_REPLACE<dd>
-** This value may only be returned if the second argument to the conflict
-** handler was SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If this
-** is not the case, any changes applied so far are rolled back and the
-** call to sqlite3changeset_apply() returns SQLITE_MISUSE.
-**
-** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_DATA conflict
-** handler, then the conflicting row is either updated or deleted, depending
-** on the type of change.
-**
-** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_CONFLICT conflict
-** handler, then the conflicting row is removed from the database and a
-** second attempt to apply the change is made. If this second attempt fails,
-** the original row is restored to the database before continuing.
-**
-** <dt>SQLITE_CHANGESET_ABORT<dd>
-** If this value is returned, any changes applied so far are rolled back
-** and the call to sqlite3changeset_apply() returns SQLITE_ABORT.
-** </dl>
-*/
-#define SQLITE_CHANGESET_OMIT 0
-#define SQLITE_CHANGESET_REPLACE 1
-#define SQLITE_CHANGESET_ABORT 2
-
-/*
-** CAPI3REF: Streaming Versions of API functions.
-**
-** The six streaming API xxx_strm() functions serve similar purposes to the
-** corresponding non-streaming API functions:
-**
-** <table border=1 style="margin-left:8ex;margin-right:8ex">
-** <tr><th>Streaming function<th>Non-streaming equivalent</th>
-** <tr><td>sqlite3changeset_apply_str<td>[sqlite3changeset_apply]
-** <tr><td>sqlite3changeset_concat_str<td>[sqlite3changeset_concat]
-** <tr><td>sqlite3changeset_invert_str<td>[sqlite3changeset_invert]
-** <tr><td>sqlite3changeset_start_str<td>[sqlite3changeset_start]
-** <tr><td>sqlite3session_changeset_str<td>[sqlite3session_changeset]
-** <tr><td>sqlite3session_patchset_str<td>[sqlite3session_patchset]
-** </table>
-**
-** Non-streaming functions that accept changesets (or patchsets) as input
-** require that the entire changeset be stored in a single buffer in memory.
-** Similarly, those that return a changeset or patchset do so by returning
-** a pointer to a single large buffer allocated using sqlite3_malloc().
-** Normally this is convenient. However, if an application running in a
-** low-memory environment is required to handle very large changesets, the
-** large contiguous memory allocations required can become onerous.
-**
-** In order to avoid this problem, instead of a single large buffer, input
-** is passed to a streaming API functions by way of a callback function that
-** the sessions module invokes to incrementally request input data as it is
-** required. In all cases, a pair of API function parameters such as
-**
-** <pre>
-** &nbsp; int nChangeset,
-** &nbsp; void *pChangeset,
-** </pre>
-**
-** Is replaced by:
-**
-** <pre>
-** &nbsp; int (*xInput)(void *pIn, void *pData, int *pnData),
-** &nbsp; void *pIn,
-** </pre>
-**
-** Each time the xInput callback is invoked by the sessions module, the first
-** argument passed is a copy of the supplied pIn context pointer. The second
-** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no
-** error occurs the xInput method should copy up to (*pnData) bytes of data
-** into the buffer and set (*pnData) to the actual number of bytes copied
-** before returning SQLITE_OK. If the input is completely exhausted, (*pnData)
-** should be set to zero to indicate this. Or, if an error occurs, an SQLite
-** error code should be returned. In all cases, if an xInput callback returns
-** an error, all processing is abandoned and the streaming API function
-** returns a copy of the error code to the caller.
-**
-** In the case of sqlite3changeset_start_strm(), the xInput callback may be
-** invoked by the sessions module at any point during the lifetime of the
-** iterator. If such an xInput callback returns an error, the iterator enters
-** an error state, whereby all subsequent calls to iterator functions
-** immediately fail with the same error code as returned by xInput.
-**
-** Similarly, streaming API functions that return changesets (or patchsets)
-** return them in chunks by way of a callback function instead of via a
-** pointer to a single large buffer. In this case, a pair of parameters such
-** as:
-**
-** <pre>
-** &nbsp; int *pnChangeset,
-** &nbsp; void **ppChangeset,
-** </pre>
-**
-** Is replaced by:
-**
-** <pre>
-** &nbsp; int (*xOutput)(void *pOut, const void *pData, int nData),
-** &nbsp; void *pOut
-** </pre>
-**
-** The xOutput callback is invoked zero or more times to return data to
-** the application. The first parameter passed to each call is a copy of the
-** pOut pointer supplied by the application. The second parameter, pData,
-** points to a buffer nData bytes in size containing the chunk of output
-** data being returned. If the xOutput callback successfully processes the
-** supplied data, it should return SQLITE_OK to indicate success. Otherwise,
-** it should return some other SQLite error code. In this case processing
-** is immediately abandoned and the streaming API function returns a copy
-** of the xOutput error code to the application.
-**
-** The sessions module never invokes an xOutput callback with the third
-** parameter set to a value less than or equal to zero. Other than this,
-** no guarantees are made as to the size of the chunks of data returned.
-*/
-int sqlite3changeset_apply_strm(
- sqlite3 *db, /* Apply change to "main" db of this handle */
- int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
- void *pIn, /* First arg for xInput */
- int(*xFilter)(
- void *pCtx, /* Copy of sixth arg to _apply() */
- const char *zTab /* Table name */
- ),
- int(*xConflict)(
- void *pCtx, /* Copy of sixth arg to _apply() */
- int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
- sqlite3_changeset_iter *p /* Handle describing change and conflict */
- ),
- void *pCtx /* First argument passed to xConflict */
-);
-int sqlite3changeset_concat_strm(
- int (*xInputA)(void *pIn, void *pData, int *pnData),
- void *pInA,
- int (*xInputB)(void *pIn, void *pData, int *pnData),
- void *pInB,
- int (*xOutput)(void *pOut, const void *pData, int nData),
- void *pOut
-);
-int sqlite3changeset_invert_strm(
- int (*xInput)(void *pIn, void *pData, int *pnData),
- void *pIn,
- int (*xOutput)(void *pOut, const void *pData, int nData),
- void *pOut
-);
-int sqlite3changeset_start_strm(
- sqlite3_changeset_iter **pp,
- int (*xInput)(void *pIn, void *pData, int *pnData),
- void *pIn
-);
-int sqlite3session_changeset_strm(
- sqlite3_session *pSession,
- int (*xOutput)(void *pOut, const void *pData, int nData),
- void *pOut
-);
-int sqlite3session_patchset_strm(
- sqlite3_session *pSession,
- int (*xOutput)(void *pOut, const void *pData, int nData),
- void *pOut
-);
-int sqlite3changegroup_add_strm(sqlite3_changegroup*,
- int (*xInput)(void *pIn, void *pData, int *pnData),
- void *pIn
-);
-int sqlite3changegroup_output_strm(sqlite3_changegroup*,
- int (*xOutput)(void *pOut, const void *pData, int nData),
- void *pOut
-);
-
-
-/*
-** Make sure we can call this stuff from C++.
-*/
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) */
-
-/******** End of sqlite3session.h *********/
-/******** Begin file fts5.h *********/
-/*
-** 2014 May 31
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** Interfaces to extend FTS5. Using the interfaces defined in this file,
-** FTS5 may be extended with:
-**
-** * custom tokenizers, and
-** * custom auxiliary functions.
-*/
-
-
-#ifndef _FTS5_H
-#define _FTS5_H
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*************************************************************************
-** CUSTOM AUXILIARY FUNCTIONS
-**
-** Virtual table implementations may overload SQL functions by implementing
-** the sqlite3_module.xFindFunction() method.
-*/
-
-typedef struct Fts5ExtensionApi Fts5ExtensionApi;
-typedef struct Fts5Context Fts5Context;
-typedef struct Fts5PhraseIter Fts5PhraseIter;
-
-typedef void (*fts5_extension_function)(
- const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
- Fts5Context *pFts, /* First arg to pass to pApi functions */
- sqlite3_context *pCtx, /* Context for returning result/error */
- int nVal, /* Number of values in apVal[] array */
- sqlite3_value **apVal /* Array of trailing arguments */
-);
-
-struct Fts5PhraseIter {
- const unsigned char *a;
- const unsigned char *b;
-};
-
-/*
-** EXTENSION API FUNCTIONS
-**
-** xUserData(pFts):
-** Return a copy of the context pointer the extension function was
-** registered with.
-**
-** xColumnTotalSize(pFts, iCol, pnToken):
-** If parameter iCol is less than zero, set output variable *pnToken
-** to the total number of tokens in the FTS5 table. Or, if iCol is
-** non-negative but less than the number of columns in the table, return
-** the total number of tokens in column iCol, considering all rows in
-** the FTS5 table.
-**
-** If parameter iCol is greater than or equal to the number of columns
-** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
-** an OOM condition or IO error), an appropriate SQLite error code is
-** returned.
-**
-** xColumnCount(pFts):
-** Return the number of columns in the table.
-**
-** xColumnSize(pFts, iCol, pnToken):
-** If parameter iCol is less than zero, set output variable *pnToken
-** to the total number of tokens in the current row. Or, if iCol is
-** non-negative but less than the number of columns in the table, set
-** *pnToken to the number of tokens in column iCol of the current row.
-**
-** If parameter iCol is greater than or equal to the number of columns
-** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
-** an OOM condition or IO error), an appropriate SQLite error code is
-** returned.
-**
-** This function may be quite inefficient if used with an FTS5 table
-** created with the "columnsize=0" option.
-**
-** xColumnText:
-** This function attempts to retrieve the text of column iCol of the
-** current document. If successful, (*pz) is set to point to a buffer
-** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
-** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
-** if an error occurs, an SQLite error code is returned and the final values
-** of (*pz) and (*pn) are undefined.
-**
-** xPhraseCount:
-** Returns the number of phrases in the current query expression.
-**
-** xPhraseSize:
-** Returns the number of tokens in phrase iPhrase of the query. Phrases
-** are numbered starting from zero.
-**
-** xInstCount:
-** Set *pnInst to the total number of occurrences of all phrases within
-** the query within the current row. Return SQLITE_OK if successful, or
-** an error code (i.e. SQLITE_NOMEM) if an error occurs.
-**
-** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" or "detail=column" option. If the FTS5 table is created
-** with either "detail=none" or "detail=column" and "content=" option
-** (i.e. if it is a contentless table), then this API always returns 0.
-**
-** xInst:
-** Query for the details of phrase match iIdx within the current row.
-** Phrase matches are numbered starting from zero, so the iIdx argument
-** should be greater than or equal to zero and smaller than the value
-** output by xInstCount().
-**
-** Usually, output parameter *piPhrase is set to the phrase number, *piCol
-** to the column in which it occurs and *piOff the token offset of the
-** first token of the phrase. The exception is if the table was created
-** with the offsets=0 option specified. In this case *piOff is always
-** set to -1.
-**
-** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
-** if an error occurs.
-**
-** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" or "detail=column" option.
-**
-** xRowid:
-** Returns the rowid of the current row.
-**
-** xTokenize:
-** Tokenize text using the tokenizer belonging to the FTS5 table.
-**
-** xQueryPhrase(pFts5, iPhrase, pUserData, xCallback):
-** This API function is used to query the FTS table for phrase iPhrase
-** of the current query. Specifically, a query equivalent to:
-**
-** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid
-**
-** with $p set to a phrase equivalent to the phrase iPhrase of the
-** current query is executed. Any column filter that applies to
-** phrase iPhrase of the current query is included in $p. For each
-** row visited, the callback function passed as the fourth argument
-** is invoked. The context and API objects passed to the callback
-** function may be used to access the properties of each matched row.
-** Invoking Api.xUserData() returns a copy of the pointer passed as
-** the third argument to pUserData.
-**
-** If the callback function returns any value other than SQLITE_OK, the
-** query is abandoned and the xQueryPhrase function returns immediately.
-** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
-** Otherwise, the error code is propagated upwards.
-**
-** If the query runs to completion without incident, SQLITE_OK is returned.
-** Or, if some error occurs before the query completes or is aborted by
-** the callback, an SQLite error code is returned.
-**
-**
-** xSetAuxdata(pFts5, pAux, xDelete)
-**
-** Save the pointer passed as the second argument as the extension functions
-** "auxiliary data". The pointer may then be retrieved by the current or any
-** future invocation of the same fts5 extension function made as part of
-** of the same MATCH query using the xGetAuxdata() API.
-**
-** Each extension function is allocated a single auxiliary data slot for
-** each FTS query (MATCH expression). If the extension function is invoked
-** more than once for a single FTS query, then all invocations share a
-** single auxiliary data context.
-**
-** If there is already an auxiliary data pointer when this function is
-** invoked, then it is replaced by the new pointer. If an xDelete callback
-** was specified along with the original pointer, it is invoked at this
-** point.
-**
-** The xDelete callback, if one is specified, is also invoked on the
-** auxiliary data pointer after the FTS5 query has finished.
-**
-** If an error (e.g. an OOM condition) occurs within this function, an
-** the auxiliary data is set to NULL and an error code returned. If the
-** xDelete parameter was not NULL, it is invoked on the auxiliary data
-** pointer before returning.
-**
-**
-** xGetAuxdata(pFts5, bClear)
-**
-** Returns the current auxiliary data pointer for the fts5 extension
-** function. See the xSetAuxdata() method for details.
-**
-** If the bClear argument is non-zero, then the auxiliary data is cleared
-** (set to NULL) before this function returns. In this case the xDelete,
-** if any, is not invoked.
-**
-**
-** xRowCount(pFts5, pnRow)
-**
-** This function is used to retrieve the total number of rows in the table.
-** In other words, the same value that would be returned by:
-**
-** SELECT count(*) FROM ftstable;
-**
-** xPhraseFirst()
-** This function is used, along with type Fts5PhraseIter and the xPhraseNext
-** method, to iterate through all instances of a single query phrase within
-** the current row. This is the same information as is accessible via the
-** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient
-** to use, this API may be faster under some circumstances. To iterate
-** through instances of phrase iPhrase, use the following code:
-**
-** Fts5PhraseIter iter;
-** int iCol, iOff;
-** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
-** iCol>=0;
-** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
-** ){
-** // An instance of phrase iPhrase at offset iOff of column iCol
-** }
-**
-** The Fts5PhraseIter structure is defined above. Applications should not
-** modify this structure directly - it should only be used as shown above
-** with the xPhraseFirst() and xPhraseNext() API methods (and by
-** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
-**
-** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" or "detail=column" option. If the FTS5 table is created
-** with either "detail=none" or "detail=column" and "content=" option
-** (i.e. if it is a contentless table), then this API always iterates
-** through an empty set (all calls to xPhraseFirst() set iCol to -1).
-**
-** xPhraseNext()
-** See xPhraseFirst above.
-**
-** xPhraseFirstColumn()
-** This function and xPhraseNextColumn() are similar to the xPhraseFirst()
-** and xPhraseNext() APIs described above. The difference is that instead
-** of iterating through all instances of a phrase in the current row, these
-** APIs are used to iterate through the set of columns in the current row
-** that contain one or more instances of a specified phrase. For example:
-**
-** Fts5PhraseIter iter;
-** int iCol;
-** for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol);
-** iCol>=0;
-** pApi->xPhraseNextColumn(pFts, &iter, &iCol)
-** ){
-** // Column iCol contains at least one instance of phrase iPhrase
-** }
-**
-** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" option. If the FTS5 table is created with either
-** "detail=none" "content=" option (i.e. if it is a contentless table),
-** then this API always iterates through an empty set (all calls to
-** xPhraseFirstColumn() set iCol to -1).
-**
-** The information accessed using this API and its companion
-** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
-** (or xInst/xInstCount). The chief advantage of this API is that it is
-** significantly more efficient than those alternatives when used with
-** "detail=column" tables.
-**
-** xPhraseNextColumn()
-** See xPhraseFirstColumn above.
-*/
-struct Fts5ExtensionApi {
- int iVersion; /* Currently always set to 3 */
-
- void *(*xUserData)(Fts5Context*);
-
- int (*xColumnCount)(Fts5Context*);
- int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
- int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken);
-
- int (*xTokenize)(Fts5Context*,
- const char *pText, int nText, /* Text to tokenize */
- void *pCtx, /* Context passed to xToken() */
- int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
- );
-
- int (*xPhraseCount)(Fts5Context*);
- int (*xPhraseSize)(Fts5Context*, int iPhrase);
-
- int (*xInstCount)(Fts5Context*, int *pnInst);
- int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff);
-
- sqlite3_int64 (*xRowid)(Fts5Context*);
- int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn);
- int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken);
-
- int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData,
- int(*)(const Fts5ExtensionApi*,Fts5Context*,void*)
- );
- int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
- void *(*xGetAuxdata)(Fts5Context*, int bClear);
-
- int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
- void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
-
- int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
- void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
-};
-
-/*
-** CUSTOM AUXILIARY FUNCTIONS
-*************************************************************************/
-
-/*************************************************************************
-** CUSTOM TOKENIZERS
-**
-** Applications may also register custom tokenizer types. A tokenizer
-** is registered by providing fts5 with a populated instance of the
-** following structure. All structure methods must be defined, setting
-** any member of the fts5_tokenizer struct to NULL leads to undefined
-** behaviour. The structure methods are expected to function as follows:
-**
-** xCreate:
-** This function is used to allocate and inititalize a tokenizer instance.
-** A tokenizer instance is required to actually tokenize text.
-**
-** The first argument passed to this function is a copy of the (void*)
-** pointer provided by the application when the fts5_tokenizer object
-** was registered with FTS5 (the third argument to xCreateTokenizer()).
-** The second and third arguments are an array of nul-terminated strings
-** containing the tokenizer arguments, if any, specified following the
-** tokenizer name as part of the CREATE VIRTUAL TABLE statement used
-** to create the FTS5 table.
-**
-** The final argument is an output variable. If successful, (*ppOut)
-** should be set to point to the new tokenizer handle and SQLITE_OK
-** returned. If an error occurs, some value other than SQLITE_OK should
-** be returned. In this case, fts5 assumes that the final value of *ppOut
-** is undefined.
-**
-** xDelete:
-** This function is invoked to delete a tokenizer handle previously
-** allocated using xCreate(). Fts5 guarantees that this function will
-** be invoked exactly once for each successful call to xCreate().
-**
-** xTokenize:
-** This function is expected to tokenize the nText byte string indicated
-** by argument pText. pText may or may not be nul-terminated. The first
-** argument passed to this function is a pointer to an Fts5Tokenizer object
-** returned by an earlier call to xCreate().
-**
-** The second argument indicates the reason that FTS5 is requesting
-** tokenization of the supplied text. This is always one of the following
-** four values:
-**
-** <ul><li> <b>FTS5_TOKENIZE_DOCUMENT</b> - A document is being inserted into
-** or removed from the FTS table. The tokenizer is being invoked to
-** determine the set of tokens to add to (or delete from) the
-** FTS index.
-**
-** <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed
-** against the FTS index. The tokenizer is being called to tokenize
-** a bareword or quoted string specified as part of the query.
-**
-** <li> <b>(FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX)</b> - Same as
-** FTS5_TOKENIZE_QUERY, except that the bareword or quoted string is
-** followed by a "*" character, indicating that the last token
-** returned by the tokenizer will be treated as a token prefix.
-**
-** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
-** satisfy an fts5_api.xTokenize() request made by an auxiliary
-** function. Or an fts5_api.xColumnSize() request made by the same
-** on a columnsize=0 database.
-** </ul>
-**
-** For each token in the input string, the supplied callback xToken() must
-** be invoked. The first argument to it should be a copy of the pointer
-** passed as the second argument to xTokenize(). The third and fourth
-** arguments are a pointer to a buffer containing the token text, and the
-** size of the token in bytes. The 4th and 5th arguments are the byte offsets
-** of the first byte of and first byte immediately following the text from
-** which the token is derived within the input.
-**
-** The second argument passed to the xToken() callback ("tflags") should
-** normally be set to 0. The exception is if the tokenizer supports
-** synonyms. In this case see the discussion below for details.
-**
-** FTS5 assumes the xToken() callback is invoked for each token in the
-** order that they occur within the input text.
-**
-** If an xToken() callback returns any value other than SQLITE_OK, then
-** the tokenization should be abandoned and the xTokenize() method should
-** immediately return a copy of the xToken() return value. Or, if the
-** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally,
-** if an error occurs with the xTokenize() implementation itself, it
-** may abandon the tokenization and return any error code other than
-** SQLITE_OK or SQLITE_DONE.
-**
-** SYNONYM SUPPORT
-**
-** Custom tokenizers may also support synonyms. Consider a case in which a
-** user wishes to query for a phrase such as "first place". Using the
-** built-in tokenizers, the FTS5 query 'first + place' will match instances
-** of "first place" within the document set, but not alternative forms
-** such as "1st place". In some applications, it would be better to match
-** all instances of "first place" or "1st place" regardless of which form
-** the user specified in the MATCH query text.
-**
-** There are several ways to approach this in FTS5:
-**
-** <ol><li> By mapping all synonyms to a single token. In this case, the
-** In the above example, this means that the tokenizer returns the
-** same token for inputs "first" and "1st". Say that token is in
-** fact "first", so that when the user inserts the document "I won
-** 1st place" entries are added to the index for tokens "i", "won",
-** "first" and "place". If the user then queries for '1st + place',
-** the tokenizer substitutes "first" for "1st" and the query works
-** as expected.
-**
-** <li> By adding multiple synonyms for a single term to the FTS index.
-** In this case, when tokenizing query text, the tokenizer may
-** provide multiple synonyms for a single term within the document.
-** FTS5 then queries the index for each synonym individually. For
-** example, faced with the query:
-**
-** <codeblock>
-** ... MATCH 'first place'</codeblock>
-**
-** the tokenizer offers both "1st" and "first" as synonyms for the
-** first token in the MATCH query and FTS5 effectively runs a query
-** similar to:
-**
-** <codeblock>
-** ... MATCH '(first OR 1st) place'</codeblock>
-**
-** except that, for the purposes of auxiliary functions, the query
-** still appears to contain just two phrases - "(first OR 1st)"
-** being treated as a single phrase.
-**
-** <li> By adding multiple synonyms for a single term to the FTS index.
-** Using this method, when tokenizing document text, the tokenizer
-** provides multiple synonyms for each token. So that when a
-** document such as "I won first place" is tokenized, entries are
-** added to the FTS index for "i", "won", "first", "1st" and
-** "place".
-**
-** This way, even if the tokenizer does not provide synonyms
-** when tokenizing query text (it should not - to do would be
-** inefficient), it doesn't matter if the user queries for
-** 'first + place' or '1st + place', as there are entires in the
-** FTS index corresponding to both forms of the first token.
-** </ol>
-**
-** Whether it is parsing document or query text, any call to xToken that
-** specifies a <i>tflags</i> argument with the FTS5_TOKEN_COLOCATED bit
-** is considered to supply a synonym for the previous token. For example,
-** when parsing the document "I won first place", a tokenizer that supports
-** synonyms would call xToken() 5 times, as follows:
-**
-** <codeblock>
-** xToken(pCtx, 0, "i", 1, 0, 1);
-** xToken(pCtx, 0, "won", 3, 2, 5);
-** xToken(pCtx, 0, "first", 5, 6, 11);
-** xToken(pCtx, FTS5_TOKEN_COLOCATED, "1st", 3, 6, 11);
-** xToken(pCtx, 0, "place", 5, 12, 17);
-**</codeblock>
-**
-** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time
-** xToken() is called. Multiple synonyms may be specified for a single token
-** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence.
-** There is no limit to the number of synonyms that may be provided for a
-** single token.
-**
-** In many cases, method (1) above is the best approach. It does not add
-** extra data to the FTS index or require FTS5 to query for multiple terms,
-** so it is efficient in terms of disk space and query speed. However, it
-** does not support prefix queries very well. If, as suggested above, the
-** token "first" is subsituted for "1st" by the tokenizer, then the query:
-**
-** <codeblock>
-** ... MATCH '1s*'</codeblock>
-**
-** will not match documents that contain the token "1st" (as the tokenizer
-** will probably not map "1s" to any prefix of "first").
-**
-** For full prefix support, method (3) may be preferred. In this case,
-** because the index contains entries for both "first" and "1st", prefix
-** queries such as 'fi*' or '1s*' will match correctly. However, because
-** extra entries are added to the FTS index, this method uses more space
-** within the database.
-**
-** Method (2) offers a midpoint between (1) and (3). Using this method,
-** a query such as '1s*' will match documents that contain the literal
-** token "1st", but not "first" (assuming the tokenizer is not able to
-** provide synonyms for prefixes). However, a non-prefix query like '1st'
-** will match against "1st" and "first". This method does not require
-** extra disk space, as no extra entries are added to the FTS index.
-** On the other hand, it may require more CPU cycles to run MATCH queries,
-** as separate queries of the FTS index are required for each synonym.
-**
-** When using methods (2) or (3), it is important that the tokenizer only
-** provide synonyms when tokenizing document text (method (2)) or query
-** text (method (3)), not both. Doing so will not cause any errors, but is
-** inefficient.
-*/
-typedef struct Fts5Tokenizer Fts5Tokenizer;
-typedef struct fts5_tokenizer fts5_tokenizer;
-struct fts5_tokenizer {
- int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
- void (*xDelete)(Fts5Tokenizer*);
- int (*xTokenize)(Fts5Tokenizer*,
- void *pCtx,
- int flags, /* Mask of FTS5_TOKENIZE_* flags */
- const char *pText, int nText,
- int (*xToken)(
- void *pCtx, /* Copy of 2nd argument to xTokenize() */
- int tflags, /* Mask of FTS5_TOKEN_* flags */
- const char *pToken, /* Pointer to buffer containing token */
- int nToken, /* Size of token in bytes */
- int iStart, /* Byte offset of token within input text */
- int iEnd /* Byte offset of end of token within input text */
- )
- );
-};
-
-/* Flags that may be passed as the third argument to xTokenize() */
-#define FTS5_TOKENIZE_QUERY 0x0001
-#define FTS5_TOKENIZE_PREFIX 0x0002
-#define FTS5_TOKENIZE_DOCUMENT 0x0004
-#define FTS5_TOKENIZE_AUX 0x0008
-
-/* Flags that may be passed by the tokenizer implementation back to FTS5
-** as the third argument to the supplied xToken callback. */
-#define FTS5_TOKEN_COLOCATED 0x0001 /* Same position as prev. token */
-
-/*
-** END OF CUSTOM TOKENIZERS
-*************************************************************************/
-
-/*************************************************************************
-** FTS5 EXTENSION REGISTRATION API
-*/
-typedef struct fts5_api fts5_api;
-struct fts5_api {
- int iVersion; /* Currently always set to 2 */
-
- /* Create a new tokenizer */
- int (*xCreateTokenizer)(
- fts5_api *pApi,
- const char *zName,
- void *pContext,
- fts5_tokenizer *pTokenizer,
- void (*xDestroy)(void*)
- );
-
- /* Find an existing tokenizer */
- int (*xFindTokenizer)(
- fts5_api *pApi,
- const char *zName,
- void **ppContext,
- fts5_tokenizer *pTokenizer
- );
-
- /* Create a new auxiliary function */
- int (*xCreateFunction)(
- fts5_api *pApi,
- const char *zName,
- void *pContext,
- fts5_extension_function xFunction,
- void (*xDestroy)(void*)
- );
-};
-
-/*
-** END OF REGISTRATION API
-*************************************************************************/
-
-#ifdef __cplusplus
-} /* end of the 'extern "C"' block */
-#endif
-
-#endif /* _FTS5_H */
-
-
-/******** End of fts5.h *********/
diff --git a/ext/sqlite3/libsqlite/sqlite3ext.h b/ext/sqlite3/libsqlite/sqlite3ext.h
index 20a2fcdf02..f9a066592d 100644
--- a/ext/sqlite3/libsqlite/sqlite3ext.h
+++ b/ext/sqlite3/libsqlite/sqlite3ext.h
@@ -267,20 +267,6 @@ struct sqlite3_api_routines {
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
void(*)(void*), unsigned char);
int (*strglob)(const char*,const char*);
- /* Version 3.8.11 and later */
- sqlite3_value *(*value_dup)(const sqlite3_value*);
- void (*value_free)(sqlite3_value*);
- int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
- int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
- /* Version 3.9.0 and later */
- unsigned int (*value_subtype)(sqlite3_value*);
- void (*result_subtype)(sqlite3_context*,unsigned int);
- /* Version 3.10.0 and later */
- int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
- int (*strlike)(const char*,const char*,unsigned int);
- int (*db_cacheflush)(sqlite3*);
- /* Version 3.12.0 and later */
- int (*system_errno)(sqlite3*);
};
/*
@@ -294,7 +280,7 @@ struct sqlite3_api_routines {
** the API. So the redefinition macros are only valid if the
** SQLITE_CORE macros is undefined.
*/
-#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
+#ifndef SQLITE_CORE
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
@@ -421,7 +407,6 @@ struct sqlite3_api_routines {
#define sqlite3_value_text16le sqlite3_api->value_text16le
#define sqlite3_value_type sqlite3_api->value_type
#define sqlite3_vmprintf sqlite3_api->vmprintf
-#define sqlite3_vsnprintf sqlite3_api->vsnprintf
#define sqlite3_overload_function sqlite3_api->overload_function
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
@@ -512,23 +497,9 @@ struct sqlite3_api_routines {
#define sqlite3_result_blob64 sqlite3_api->result_blob64
#define sqlite3_result_text64 sqlite3_api->result_text64
#define sqlite3_strglob sqlite3_api->strglob
-/* Version 3.8.11 and later */
-#define sqlite3_value_dup sqlite3_api->value_dup
-#define sqlite3_value_free sqlite3_api->value_free
-#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
-#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
-/* Version 3.9.0 and later */
-#define sqlite3_value_subtype sqlite3_api->value_subtype
-#define sqlite3_result_subtype sqlite3_api->result_subtype
-/* Version 3.10.0 and later */
-#define sqlite3_status64 sqlite3_api->status64
-#define sqlite3_strlike sqlite3_api->strlike
-#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
-/* Version 3.12.0 and later */
-#define sqlite3_system_errno sqlite3_api->system_errno
-#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
+#endif /* SQLITE_CORE */
-#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
+#ifndef SQLITE_CORE
/* This case when the file really is being compiled as a loadable
** extension */
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;